Tipps zur Loesung der „retarget“ Aufgabe vom 13.11.2019

URL der Aufgabe: https://r-n-d.informatik.hs-augsburg.de:8080/es2/es2-nucl476/retarget

Folgendes gilt fuer das Beispiel „a1“ (bare-metal).

Die minimalen Stack und Heap-Groessen habe ich je auf 4K vergroessert: Dazu in STM32L476RG_FLASH.ld die Zeilen aendern:

_Min_Heap_Size = 0x1000;;      /* required amount of heap  */
_Min_Stack_Size = 0x1000;; /* required amount of stack */

Im Makefile waren meine Linker-Flags:

PRO_LDFLAGS = -TSTM32L476RG_FLASH.ld -Wl,-Map,main.map -nostartfiles -mcpu=cortex-m4 -mthumb -mfloat -abi=hard -mfpu=fpv4-sp-d16 --specs=nano.specs --specs=nosys.specs -u _printf_float -u _scanf_float -lm -ffast-math

In Src/usart.c muss man noch folgende Funktion einbauen:

__attribute__((weak)) char __io_getchar()
{
   char c;
   c = usart_receive_char();
   return c;
}

Die Empfangsfunktion usart_receive_char() sieht so aus:

char usart_receive_char()
{
   USART2_CR1 |= (1 << 2);
   while(!(USART2_ISR & (1 << 5)))
        ;
   return (char) USART2_RDR;
}

Die _read() Funktion sieht so aus:

/* works with gets and scanf() -- int, string, float
 * works with getchar()
 * tested with picocom terminal emulator on Linux
 */
int _read(int file, char *ptr, int len)
{
   int idx;
   char c;
   for (idx = 0; idx < len; idx++) {
       c = __io_getchar();
       if (c == 0x0d) {  /* 0x0d is the ENTER key */
           *ptr++ = 0x0a;  /* 0x0a is the newline character (line ending) */
           return idx+1;
       }
       else {
           *ptr++ = c;
       }
   }
}

Die _read() Funktion wird von allen Standardbibliotheksfunktionen aufgerufen, die ein oder mehrere Zeichen einlesen wollen. Da die Anzahl variabel ist, muss die Anzahl der tatsaechlich gelesenen Zeichen als Rueckgabewert zurueckliefert werden. Die Eingabe wird auf der Tastatur immer durch ENTER (ASCII 0x0d) abgeschlossen. Intern wertet aber __read() das Newline-Zeichen (0x0a) aus. Mit der obigen Funktion haben scanf(), gets() und getchar() funktioniert.


Die Ausgabe von Zeichen auf dem Terminal ist einfacher. Ohne grosse Schwierigkeiten haben printf() und snprintf() (zunächst in String, dann String über USART ausgeben) funktioniert.


Hier ist noch eine Anweisung zum Einschalten des numerischen Koprozessors (FPU). Ich bin mir nicht sicher, ob man das braucht. Wollte es nur mal ausprobieren.

#define SCB_CPACR  REGISTER_32(0xE000ED88)
SCB_CPACR |= ((3UL << 10*2) |    /* set CP10 Full Access */
             (3UL << 11*2) );    /* set CP11 Full Access */