11  Versuche

11.1 Starter

Im wesentlichen geht es hier nur darum, das “starter” Projekt als ersten Versuch zum Laufen zu bringen, so dass man sicher sein kann, dass die Installation der Tools auf dem PC funktioniert hat. Am Ende der README.md stehen noch ein paar kleinere Aufgaben.

Siehe https://gitlab.com/hhoegl-tha/es/f446/starter

11.2 GDB-Uebung

Siehe https://gitlab.com/hhoegl-tha/es/f446/gdb-uebung

Die Aufgaben sind in der Datei Aufgaben.md im Repo enthalten.

11.3 GNU-Start

https://gitlab.com/hhoegl-tha/es/f446/gnu_start

Die Aufgaben sind in der Datei Aufgaben.md im Repo enthalten.

11.4 CMSIS und Exceptions

11.4.1 starter-cmsis

Klonen Sie das Repository

https://gitlab.com/hhoegl-tha/es/f446/starter-cmsis

Der CMSIS Standard gibt eine Struktur vor für den Startup-Vorgang. Sehen Sie sich in src/ die beiden Dateien startup_stm32f446xx.s und system_stm32f4xx.can und untersuchen Sie wie der genaue Ablauf ist.

11.4.2 syshandler-cmsis

Klonen Sie das Repository

https://gitlab.com/hhoegl-tha/es/f446/syshandler-cmsis

Aktivieren Sie nacheinander immer genau eine der folgenden Exception-Quellen, kompilieren Sie das Programm, und verwenden Sie GDB um den genauen Ablauf zu studieren.

  • SysTick (entweder Variante 1 oder Variante 2)

  • Bus fault

  • Usage fault

  • Integer division by zero

  • FPU interrupt division by zero (finden Sie auch die Stelle im Quelltext, an der die FPU aktiviert wird). Die Register der FPU werden in [PM], Kap. 4.6 beschrieben.

  • SVC handler

    Das Hauptprogramm triggert eine SVC Exception. Sehen Sie sich im SVC_Handler() mit dem GDB den Stackframe an und ermitteln Sie, an welcher Stelle der SVC aufgerufen wurde. Daraus können Sie wiederum die SVC Service Nummer ermitteln.

Nehmen Sie in Ihren Bericht auf, was Sie gemacht haben, und beschreiben Sie auch kurz die einzelnen Exceptions.

In .estool/gdbinit ist eine Funktion flags definiert, mit der man das xPSR Register, in dem sich die Flags befinden, im Klartext ausgeben kann:

  (arm-gdb) flags
  N=0 Z=1 C=1 V=0 Q=0 GE=0 ICI/IT=0x0 Exc#=0

Wenn Sie im GDB das Kommando layout regs eingeben, dann sehen Sie auch die aktuellen Werte der Register, so wie das hier zu sehen ist:

https://tha.de/homes/hhoegl/home_data/es2/gdb-tui-window/gdb_tui_window.png

11.4.3 gpio-intr-cmsis

Klonen Sie das Repository

https://gitlab.com/hhoegl-tha/es/f446/gpio-intr-cmsis

  1. Auf welchem Wert steht der Stack-Pointer sp beim Programmstart bei main()?

  2. Gehen Sie im GDB mit s (step) durch die Funktion __get_CONTROL(). Was wird ausgeführt?

    Schauen Sie sich auch die anderen Funktionen __get_PRIMASK(), __get_FAULTMASK(), __set_BASEPRI() und __get_BASEPRI() an.

  3. Das Statusregister können Sie mit folgendem Kommando ausgeben:

    (arm-gdb) p/x $xPSR
    $4 = 0x21000000       # beispielhafte Ausgabe

    Was bedeuten die einzelnen Bits? Sehen Sie dazu in [PM] nach. Eine Hilfe bietet auch die GDB Funktion flags, die Sie in .estool/gdbinit finden. Damit kann man die Werte der einzelnen Flags ausgeben:

    (arm-gdb) flags
    N=0 Z=1 C=1 V=0 Q=0 GE=0 ICI/IT=0x0 Exc#=0
  4. Was macht das folgende C Präprozessor-Makro in inc/main.h?

    /* register r, mask f, value v (taken from _VAL2FLD() and _FLD2VAL() macros) */
    #define SETBF(r, f, v)  r = ((r & ~(f ## _Msk)) | ((v << f ## _Pos) & f ## _Msk))
  5. Welche Vektornummer wird zu Beginn des Interrupt-Handlers EXTI15_10_IRQHandler(void) im xPSR angezeigt? Wie werden die Vektoren gezählt?

  6. Schauen Sie sich den Exception Stack Frame zu Beginn des Interrupt-Handlers EXTI15_10_IRQHandler(void) an. Achten Sie darauf, dass die Programmausführung exakt vor der ersten Instruktion im Handler stoppt. Es kann sein, dass Sie den Breakpoint durch eine Adresse setzen müssen, dazu verwenden Sie die Syntax:

      (arm-gdb) br *<address>

    Die Adresse finden Sie durch Disassemblieren des Handlers oder durch das Kommando p &EXTI15_10_IRQHandler. Das & ist der “address-of” Operator, genau so wie in C.

    In GDB verwenden Sie das Kommando disas <label> zum Disassemblieren.

    Sie finden Informationen zum Stack Frame in [PM], Abschnitt Exception entry and return (Kap. 2.3, “Exception Model”).

  7. Finden Sie mit dem Debugger heraus, was im Thread Mode (also in der main() Funktion) und im Handler Mode (also im Interrupt-Handler) jeweils eingestellt ist:

    • Privilegierter (privileged access) oder nicht privilegierter (user access) Zugriff?

    • Wird der PSP oder der MSP stack pointer verwendet?

    Sie brauchen dazu nur das CONTROL Register auslesen und interpretieren.

11.4.4 Literaturangaben

[SKRIPT] Kapitel 4.10

[PM] STM32F3, STM32F4 and STM32L4 Series Cortex®-M4 programming manual (PM0214). Siehe Kapitel 9.

  • S. 43: Stack Frame Layout
  • S. 37: Exception Model
  • S. 44: Fault Handling

[BERTOLOTTI] Ivan Cibrario Bertolotti, Cortex-M Exception Handling (Blog post), 2015/2016

https://tha.de/homes/hhoegl/home_data/es2/exceptions/bertolotti

[EXC_PROC] Übersicht zum Exception Processing auf dem STM32

https://tha.de/homes/hhoegl/home_data/es2/exceptions/stm32_exc_proc/stm32_exc_proc.svg

[YIU] Yiu, The Definitive Guide to ARM® Cortex®-M3 and Cortex®-M4 Processors, 3rd ed.

  • Kap. 2, Introduction to Embedded Software Development

  • Kap. 12, Fault Exceptions and Fault Handling

11.5 BPG

Diese Aufgabe baut auf einem Tutorial das es auf github gibt, sie finden es unter:

https://github.com/cpq/bare-metal-programming-guide

Die Programmierung von Mikrocontrollern in der Sprache C ist dabei in einzelne Schritte aufgeteilt, die sich nacheinander im Funktionsumfang steigern (siehe Verzeichnis steps). Die einzelnen Schritte sind

  • step-0-minimal/
  • step-1-blinky/
  • step-2-systick/
  • step-3-uart/
  • step-4-printf/
  • step-5-cmsis/
  • step-6-clock/
  • step-7-webserver/

Alle Schritte sind vom Schwierigkeitsgrad her relativ einfach. Das Tutorial ist für das Nucleo-F429ZI Board gemacht.

Die Schritte 0 bis 6 sind leicht anpassbar für das Nucleo-F446. Das wird eine ihrer Aufgaben sein.

Der Schritt step-7-webserver ist nur mit einem Board möglich, das einen Internetanschluss (eth, WiFi) hat. Das Programm verwendet die “mongoose” Network Library (https://github.com/cesanta/mongoose, https://mongoose.ws)
Wir werden das Programm auf einem NucleoF429ZI in Betrieb nehmen.

11.5.1 Debuggen

Im Tutorial wird der “Ozone” Debugger von Segger verwendet. Damit man ihn verwenden kann muss man leider den Debug Controller auf dem Nucleo Board mit einer neuen Firmware flashen, damit aus dem “STLINK” ein “J-Link” wird. Das finde ich nicht gut, deswegen bleiben wir bei dem bewährten Gespann aus OpenOCD und GDB. Damit die Anwendung leichter wird, habe ich das kleine Programm ogdb geschrieben.

https://gitlab.com/hhoegl-tha/es/ogdb

Man kann die Binärdatei von gitlab herunterladen und in einen Ordner legen, in dem ausführbare Dateien gefunden werden (Hinweis: Die PATH Umgebungsvariable muss diesen Ordner enthalten). In dem jeweiligen “Step” Ordner gibt man einfach das Kommando ogdb ein, damit wird der OpenOCD automatisch im Hintergrund gestartet und der GDB im TUI-Modus geöffnet. Dann sollte wie gewohnt das Debuggen in GDB möglich sein.

11.5.2 Ihre Aufgaben

  1. Lesen Sie die ersten drei Schritte (0, 1, 2) im Tutorial und ändern Sie die Programme so, dass sie auf dem Nucleo-F446 laufen.

    Meist müssen Sie dabei nur die zwei Zeilen im Linker-Skript ändern auf

    flash(rx) : ORIGIN = 0x08000000, LENGTH = 512k
    sram(rwx) : ORIGIN = 0x20000000, LENGTH = 128k  

    Ausserdem ist die LED zu ändern auf Port A, Pin 5.

    Bei Aufgaben die den UART verwenden ist der UART2 einzustellen.

    Beschreiben Sie in Ihrem Bericht kurz, wie der Programmablauf ist. Sie müssen sich dazu den Quelltext genauer ansehen.

  2. Wie funktionieren die Macros BIT, PIN, PINNO, PINBANK?

  3. Was erledigt der Reset Vektor _reset(void)?

    Was machen vor allem die zwei for Schleifen?

  4. Wie wird der Reset Vektor in der Vektor-Tabelle abgelegt?

  5. Welchen Wert hat der Stackpointer wenn das Programm bei Reset losläuft?

  6. Wie funktioniert die Takteinstellung? (RCC)

  7. Wie funktioniert der SysTick Interrupt in Verbindung mit timer_expired() bei step-2-systick? In welchem zeitlichen Abstand wird der SysTick ausgelöst?

  8. Was passiert mit dem SysTick, wenn man das Programm im GDB mit Ctrl-C stoppt?

  9. Wie schafft man es in GDB, dass die folgenden Programmzeilen in main() ausgeführt werden und das Programm bei /* stop */ wieder stoppt?

    for (;;) {
       if (timer_expired(&timer, period, s_ticks)) {
          ...  /* stop */

Bearbeiten Sie die Schritte 3-6.

step-3-uart

  1. Was macht die Funktion gpio_set_af()?

  2. Wie funktionieren uart_init() und uart_write_buf()?

step-4-printf

  1. Das Programm ist nun in mehrere Dateien aufgeteilt (hal.h, main.c, startup.c, syscalls.c). Was ist in den einzelnen Dateien drin?

  2. Damit printf() verwendet werden kann müssen Systemaufrufe implementiert werden. Welche sind das?

step-5-cmsis

  1. Dieser Schritt verwendet die CMSIS Bibliothek von ARM. Der CMSIS Code wird dazu erst geholt. Beschreiben Sie wie das im Makefile funktioniert (Achtung: Die neuen CMSIS Verzeichnisse nicht in ihr Abgabe-Repo übernehmen, das wäre Platzverschwendung).

  2. Welche Teile im Programm werden nun auf CMSIS ausgelagert?

step-6-clock

  1. Der Startup-Vorgang ist nun komplizierter! Versuchen Sie herauszubekommen, wie er genau abläuft. Es ist eine Assembler Datei daran beteiligt, die in der CMSIS liegt.

11.6 Cube

XXX Diese Aufgabe muss erst überarbeitet werden!

Dieser Versuch besteht aus zwei Teilen, GPIO_IO_TOGGLE und GPIO_EXTI. Beide Teile verwenden die STM32 CubeL4 Bibliothek.

11.6.1 GPIO_IO_TOGGLE

Klonen Sie das Repository https://gitlab.com/hhoegl-tha/es/l476/cube-demos. Danach finden Sie den Ordner in cube-demos/gpio_io_toggle.

Das originale README ist in readme.txt.

Der Quelltext für dieses Beispielprogramm stammt aus der CubeL4 Bibliothek. Es wurde lediglich ein Makefile hinzugefügt.

Es gibt folgende Abhängigkeiten:

  1. Die CubeL4 Bibliothek für den STM32L476 wird benötigt. Sie ist in folgendem Repository:

    XXX to do

  2. Das Board Support Package (BSP) für das STM32L476-Nucleo wird benötigt.

    Das BSP besteht aus einer Quelltextdatei stm32l4xx_nucleo.c und einer Header-Datei (siehe Makefile). Die Kompilierung wird automatisch durch das Makefile gesteuert.

Mit dem Befehl make wird das Programm kompiliert.

Mit make flash kann man das Programm in den Mikrocontroller übertragen.

Mit make gdb startet man den Debugger. Der OpenOCD Server muss dazu laufen (siehe estool --start-oocd, estool --ask-oocd, estool --stop-oocd).

11.6.2 Aufgaben

  1. Kompilieren Sie das Programm und lassen Sie es auf dem Nucleo Board laufen.

  2. Welche Bedeutung haben die einzelnen Quelltext-Dateien? Die Aufteilung ist teilweise durch die CMSIS Bibliothek und teilweise durch die Cube Bibliothek vorgegeben.

       ├── Inc
       │   ├── main.h
       │   ├── stm32l4xx_hal_conf.h
       │   └── stm32l4xx_it.h
       ├── Src
           ├── main.c
           ├── startup_stm32l476xx.s
           ├── stm32l4xx_it.c
           └── system_stm32l4xx.c

    Schauen Sie dazu mit dem Editor in die einzelnen Dateien und studieren Sie den Quelltext.

    Notieren Sie alle Programmteile, die nacheinander nach dem RESET Signal ablaufen. Denken Sie insbesondere an

    • Startup-Code
    • Initialisierung von data und bss Speicherabschnitt
    • Vektortabelle
    • Interrupt-Vektoren
    • Takteinstellung
  3. Gehen Sie in die einzelnen Verzeichnisse der Cube-Bibliothek und finden Sie heraus, aus welchen Bestandteilen sie besteht.

  4. Gehen Sie im Editor an die Zeile main.c:35 und navigieren Sie nach HAL_Init(). Was macht diese Funktion?

    Zur Erinnerung: Mit Ctrl-] kommen Sie in Vim an die Stelle an der die Funktion definiert ist. Mit Ctrl-T springen Sie wieder zurück.

  5. Gehen Sie im Editor an die Zeile main.c:38 und navigieren Sie zu SystemClock_Config();. Diese Funktion konfiguriert das Taktsystem des STM32. Besorgen Sie sich das Blockschaltbild der RCC-Einheit und finden Sie die genauen Takteinstellungen heraus. Das Kapitel 6 im Reference Manual behandelt die RCC-Einheit.

    Das Blockschaltbild finden Sie wenn Sie auf den Link mit den Literaturangaben gehen (unten) und nach “clocktree” suchen.

  6. Finden Sie heraus, ob der SysTick Timer bei dieser Anwendung konfiguriert ist und läuft.

  7. Wie funktioniert der Aufruf von HAL_Delay(200); auf Zeile main.c:49?

  8. In welchem Teil der Cube Bibliothek werden die LEDs und Taster auf dem Nucleo Board zusammengefasst?

    Wie heissen die Funktionsaufrufe, mit denen die LEDs initialisiert und angesprochen werden?

  9. Wozu gibt es die Funktion assert_failed(...) in Zeile main.c:131? Tipp: In der Cube Bibliothek gibt es oft assert() Aufrufe. Wozu dienen diese?

Literatur

Die benötigte Literatur finden Sie in Kapitel 9.

Die CubeL4 Bibliothek ist auf github unter

https://github.com/STMicroelectronics/STM32CubeL4

11.6.3 GPIO_EXTI

Der Beispielcode ist unter cube-demos/GPIO_EXTI/.

Durch Drücken des USER-Button (blaue Taste, B1) auf dem Nucleo-L476 wird ein Interrupt (EXTI) auf der fallenden Flanke ausgelöst. Der Interrupt-Handler toggelt die grüne USER-LED (LD2). Manchmal scheint das Umschalten der LED nicht richtig zu funktionieren. Das liegt daran, dass die Taste “prellt”, d.h. bei einmaligem Drücken werden mehrere Impulse erzeugt und der Interrupt-Handler wird dadurch mehrfach aufgerufen.

Das originale README ist in readme.txt.

11.6.4 Aufgaben

  1. Kompilieren Sie das Programm und lassen Sie es auf dem Nucleo Board laufen.

  2. Wie wird der Interrupt auf der User-Taste in main.c programmiert? Gehen Sie alle Peripherieblöcke durch, die bei einem Interrupt beteiligt sind, also NVIC, EXTI, GPIO und SYSCFG.

  3. Wo ist der Interrupt-Handler EXTI15_10_IRQHandler(...) definiert?

    Vollziehen Sie alle Schritte nach, die dieser Handler macht!

Die benötigte Literatur finden Sie in Kapitel 9.

11.7 RTOS

Literaturangaben

  • Siehe den Abschnitt “RTOS” in Kapitel 9.

  • CMSIS-RTOS API V1 Dokumentation https://www.keil.com/pack/doc/CMSIS/RTOS/html/index.html

    Machen Sie sich mit der CMSIS-RTOS Doku vertraut, öffnen Sie im Menü auf der linken Seite nacheinander die Einträge für “Reference” und “CMSIS-RTOS API”. Dann sehen Sie die wesentichen API Funktionen sortiert in folgende Bereiche:

    • Kernel
    • Thread
    • Generic Wait
    • Timer
    • Inter-Thread Comm
      • Signals
      • Msg Queue
      • Memory Pool
      • Mail Queue
      • Mutex
      • Semaph
    • Generic Data Types
    • Status and Error Codes
  • RTOS Abschnitt im Skript, Kapitel 6.

11.7.1 Papieraufgaben

  1. Allgemeine Fragen (Motivation, warum RTOS nötig sind)

    1. Der Artikel von Bill Earl, “Multi-tasking the Arduino”, beschreibt sehr anschaulich, wie man mehrere Sachen auf dem Mikrocontroller quasi-gleichzeitig erledigen kann, ohne einen echten Multi-Tasker zu haben. Beschreiben Sie die einzelnen Evolutionsstufen der Anwendung mit ihren Vor- und Nachteilen, die er in seinem Artikel beschreibt.

      Lit.: https://learn.adafruit.com/multi-tasking-the-arduino-part-1

    2. Wie entsteht bei Tasks eine race condition und wie vermeidet man sie?

      Lit.: Elecia White, Making Embedded Systems, O’Reilly 2011. Kapitel 5: Managing the Flow of Activity

      Hier sind hauptsächlich die Abschnitte “Scheduling and Operating System Basics” und “State Machines” von Interesse.

      Hinweis: Leider werden ganz wenige Fachbücher in diesem Bereich von Frauen geschrieben, dieses hier ist eine Ausnahme und es ist auch wirklich sehr gut gemacht. Schauen Sie unbedingt mal rein!

    Wer Interesse an einer weiteren anschaulichen Einführung in Echtzeit-Betriebssysteme hat, kann sich folgenden Auszug aus einem Buch anschauen (aus Jim Ledin, Architecting High-Performance Embedded Systems, Packt Publishing, Feb 2021): Link

  2. Fragen zu FreeRTOS

    1. Was sind typische Aufgaben eines Betriebssystems, z.B. GNU/Linux und welche davon werden von FreeRTOS unterstützt, gerne auch in Form einer Tabelle, in der Linux und FreeRTOS gegenüber gestellt wird.

      Denken Sie dabei an Ressourcenverbrauch, Prozesse, Threads, Tasks, Scheduler, Speicherschutz, Dateien, I/O, Echtzeit.

    2. Wie gross schätzen Sie den Ressourcenverbrauch von FreeRTOS an sich ein? Bietet der STM32L476 ausreichend CPU-Leistung, RAM und Flash dafür?

    3. Wann eignet sich FreeRTOS in einem Projekt (oder Teilprojekt) und wann nicht? Bzw. was sind Kriterien die gegen bzw. für FreeRTOS in einem Projekt sprechen.

      Das lässt sich gut beantworten, wenn man in das folgende FreeRTOS Tutorial schaut: Link

      Lesen Sie die Abschnitte 1 bis 6.

      • Beschreiben Sie knapp die geplante Anwendung in eigenen Worten.

      • Welche Vor- und Nachteile hat die Programmierung ohne RTOS? (“Why use an RTOS Kernel?”)

      • Welche Vor- und Nachteile hat die Programmierung mit einem preemptiven RTOS?

  3. Fragen zu “Mastering FreeRTOS” Link

    1. Was versteht man unter Multitasking und welche Arten unterstützt FreeRTOS?

    2. Welches Konstrukt der Sprache C kann zu einer Task gemacht werden?

    3. Wie macht man in FreeRTOS eine Task? (1.2, Task Functions)

    4. Welche Zustände kann eine Task haben? (1.6, Full task state machine)

    5. Wie kann man eine Task verzögern? (S. 21)

    6. Welche Prioritäten kann eine Task haben?

    7. Was ist eine “Idle Task”?

    8. Kann man die Priorität einer Task zur Laufzeit ändern, und wenn ja, wie? (1.8 Changing the priority of a task)

    9. Welchen Scheduling-Algorithmus verwendet FreeRTOS? (Kap. 1.10)

    10. Was ist eine “Queue”? (Kap. 2)

    11. Wann blockiert eine Queue?

    12. Kann eine Queue mehrere Sender und/oder mehrere Empfänger haben?

    13. Was bedeutet “deferred interrupt processing”? (Kap. 3.2)

    14. Wofür werden Semaphore typischerweise verwendet?

    15. Was ist eine “Binary Semaphore”?

    16. Was ist eine “Counting Semaphore”? (Kap. 3.3)

    17. Was ist ein “Mutex”? (Kap. 4.3, S. 105)

    18. Was ist “Priority Inversion”? (S. 111)

    19. Was versteht man unter dem Begriff Gatekeeper Task und welches Problem wird damit entschärft?

      Siehe Abschnitt 7.4 in Mastering the FreeRTOS Kernel zum Thema Gatekeeper Tasks.

    20. Gibt es in FreeRTOS eine so komfortable Heap-Speicherverwaltung wie in der libc? Nennen Sie die in FreeRTOS implementierten Verfahren Siehe Kap. 2.2, Example Memory Allocation Schemes.

      Welche der Alternativen heap_X (x = 1, 2, 3, 4, 5) wird bei den FreeRTOS Beispielen verwendet?

      Alternativer Lesestoff: UM1722 Link

11.7.2 Praktische Aufgaben

Die Beispielprogramme sind in Gitlab unter https://gitlab.com/hhoegl-tha/es/l476/cube-demos

Hinweise:

  • Verwenden Sie die Tags (make tags) zum Navigieren im Quelltext! Damit können Sie z.B. an die Stelle springen, an der die CMSIS-RTOS Funktionen oder die Board Support Package Funktionen definiert sind.

  • Bei den FreeRTOS Aufgaben ist es nützlich, wenn man den Ablauf der Tasks bzw. Threads beobachten kann. Bei langsam laufenden Tasks ist dies mit LEDs möglich. Man kann z.B. noch folgende LEDs auf einem Steckbrett anschliessen:

    • LED1: PA12
    • LED2: PA11
    • LED3: PB12
    • LED4: PB11
    • LED5: PA5 (das ist die grüne LED auf dem Board)

    Die Definition dieser LEDs finden sie in der installierten Cube Bibliothek unter stm32cubel4/freertos/BSP/freertos_leds.h.

    Verwenden Sie immer einen Vorwiderstand für jede LED. Ein Wert zwischen 220 und 470 Ohm sollte passen.

    Komfortabler geht die Visualisierung der Tasks mit einem einfachen Logikanalysator, z.B. dem Saleae https://www.saleae.com. Wir haben solche Geräte im Labor zum Ausleihen. Es gibt auch preiswerte Klone zum Kaufen, siehe z.B. https://sigrok.org/wiki/MCU123_Saleae_Logic_clone.

  • Bei den meisten FreeRTOS Beispielen ist auch eine readme.txt Datei vorhanden, in der die originale Funktionsweise beschrieben ist. Die Beispiele sind alle der Cube-Bibliothek für STM32L4 entnommen, manche sind leicht modifiziert worden, z.B. bei der Takteinstellung.

11.7.2.1 FreeRTOS_Thread_Creation

Finden Sie heraus, wie die einzelnen Tasks zeitlich nacheinander ablaufen und zeichnen Sie ein Task-Diagramm (x-Achse: Zeit, Y-Achse: die einzelnen Tasks).

11.7.2.2 FreeRTOS_SemaphoreFromISR

Dokumentieren Sie die Funktionsweise dieses Beispiels.

11.7.2.3 Gatekeeper Task

Dieses Beispiel ist als Programmgerüst in einem separaten Repository:

https://gitlab.informatik.hs-augsburg.de/es2/es2-nucl476/gatekeeper

In diesem Repository ist auch eine README.md, die sie lesen sollten.

Studieren Sie zunächst die Programme in den Ordnern:

  • FreeRTOS_Mail
  • FreeRTOS_Signal

Erstellen Sie nun ein Projekt mit fünf Threads (siehe Ordner gatekeeper nach git clone ...). Einer stellt den anderen die serielle Schnittstelle (USART2) zur Verfügung. Diese Funktion soll nicht blockieren, sondern den Inhalt, der über die serielle Schnittstelle ausgegeben werden soll, entgegennehmen und entsprechend umkopieren.

Nach einem Tastendruck (User Button) sollen die anderen vier Threads eine Ausgabe (über den vierten Thread) veranlassen.

Hinweise:

  • Welchen Synchronisationsmechanismus Sie verwenden ist Ihnen überlassen.
    Zur Auswahl stehen Semaphore, Signal und Mail.

  • Sie können das entsprechende Beispiel (Semaphore, Signal, Mail) kopieren, umbenennen und anpassen.

  • Das Gatekeeper Konzept wird im Buch “Mastering FreeRTOS” im Kapitel 7 beschrieben (“Resource Management”).

    https://hhoegl.informatik.hs-augsburg.de/es2/prog/rtos/Mastering-FreeRTOS-2016.pdf

    Abschnitt 7.4, S. 260 (Gatekeeper Tasks)

11.8 Low Power

Aufgaben

  1. Schauen Sie sich den Quelltext für das Beispiel PWR_ModesSelection an und stellen Sie in einer Tabelle zusammen, was in den einzelnen Stromsparbetriebsarten jeweils zum Stromsparen angewendet wird.

    Sie finden den Beispielcode im Repo

    https://gitlab.com/hhoegl-tha/es/l476/cube-demos

  2. Messen Sie die Stromaufnahme der PWR_ModesSelection Anwendung. Falls Sie ein Multimeter zu Hause haben, dann finden Sie heraus, welche Auflösung dessen kleinster Strommessbereich (Gleichstrom) hat. Sollten Sie auch noch ein Nucleo Board zu Hause haben, dann können Sie selber die Stromaufnahme des Boards über die beiden IDD Anschlüsse ermitteln.

    Falls Sie den Strom nicht selber messen können, finden Sie meine Messwerte unter Link

  3. Bestimmen Sie die Stromstärken für die LED-Ein und LED-Aus Zustände aus dem Oszilloskop-Bild im Skript, Abschnitt 6.10 (“Praktische Strommessung”).

  4. Welche Stromsparbetriebsarten kommen beim STM32L476 in Frage, wenn man einen Rauchmelder bauen möchte, der aus einer CR2032 Zelle (3,0V, 210mAh) gespeist werden soll und 10 bis 20 Jahre damit laufen soll?

  5. Wie funktioniert das Programm FreeRTOS_LowPower? Untersuchen Sie dazu den Quelltext.

Literatur

  • Skript, Abschnitt über Low-Power Programmierung Link

  • Designing Energy-Efficient Systems with Cortex-M Microcontrollers Link (Seiten 1-9)

  • STM32L4 ultra-low-power features overview (AN4621), 2017.

  • STM32L4 Reference Manual (RM0351), chap. 5.3 “Low-power modes”.

  • Elecia White, Making Embedded Systems, chap. 10 “Reducing Power Consumption”

  • Joseph Yiu, chap. 9 “Low Power and System Control Features”

11.9 Retarget

Repo: https://gitlab.com/hhoegl-tha/es/l476/retarget

Doku zur Newlib: https://sourceware.org/newlib

11.9.1 Aufgabe 1

Gehen Sie in das Programm a1/ (ein “baremetal” Programm) und testen Sie folgendes:

  1. Kompilieren Sie das Programm, so wie es ist. Wie gross ist es?

  2. In den Abschnitten (2) bis (12) wird immer eine Funktion aus der libc verwendet. Bauen Sie testweise einen dieser Abschntte in das Program ein (siehe die Kommentare im Programm) und kompilieren Sie das Programm. Gibt es Fehlermeldungen, wenn ja, welche?

  3. Aktivieren Sie im Makefile die andere Zeile mit der Variable PRO_SRCS (mit syscalls) und kompilieren Sie das Programm erneut. Warum klappt nun das Kompilieren?

    Achten Sie immer auf die Grösse des erzeugten Programms. Notieren Sie sich die Ausgabe von “size”, die in etwa so aussieht (natürlich haben Sie andere Werte):

     size main.elf
     text     data     bss     dec     hex filename
     24492     480    8280   33252    81e4 main.elf
  4. Programmieren Sie in retarget.c noch die Funktion __io_getchar(), die usart_receive_char() aufrufen soll. Auch letztere müssen Sie noch schreiben.

    Alle Eingabefunktionen (getchar(), gets() und scanf()) benötigen diese Funktion, sonst funktionieren sie nicht!

  5. Gehen Sie durch alle 12 Testfälle (1) bis (12) in Src/main.c und nehmen Sie den jeweiligen Code in Ihr Programm auf und testen ihn.

    Der Testfall (11) ist ein Test der im STM32L476 eingebauten Gleitkomma-Recheneinheit (FPU). Im Assembler-Listing findet man die erzeugten Assembler-Befehle für die FPU.

    Im Makefile sind die Linker-Flags durch PRO_LDFLAGS gegeben. Die am Anfang aktivierte Zeile linkt das Programm mit der newlib. Die zweite (noch auskommentierte) Zeile aktiviert die newlib-nano. Testen Sie die Kompilierung mit newlib und mit newlib-nano.

    Notieren Sie die jeweils erzeugte Code-Grösse (siehe “size” Kommando).

11.9.2 Aufgabe 2

In a2/ ist nun ein Beispiel, das die Cube-Bibliothek verwendet. Auch bei diesem Programm sollte printf() über Retargeting zum Laufen gebracht werden. Sprechen Sie den UART über das Cube API an.

11.9.3 Aufgabe 3

In shell/ findet man ein Programm (mit Cube), das eine kleine Shell über den UART auf dem Mikrocontroller bereitstellt. Der Shell-Code kommt von dem freien Projekt “libemb”:

https://github.com/wendlers/libemb

In shell/README.md steht, wie man das Programm verwendet. Man kann es sowohl über ein Terminal-Programm wie z.B. minicom steuern, oder über ein Python Programm, das die serielle Schnittstelle per Programm steuert (serial_control.py). Ausserdem gibt es in Qt5/terminal/ noch ein in C++ geschriebenes grafisches Terminalprogramm das mit dem “Qt GUI Framework” geschrieben wurde. Die Quellen sind dabei, deshalb eignet sich das Programm gut zum Kennenlernen einer Qt Applikation. Das ausführbare Programm ist in Qt5/terminal/terminalpgm. Vollziehen Sie alle drei Möglichkeiten nach.

Anregung für weitere Aufgaben (optional)

Sie nehmen irgend eine Peripherieeinheit aus cube-demos und integrieren es in die Shell. Zum Beispiel lesen Sie einen A/D Wandler mit dem Kommando adc ein. Oder Sie stellen ein Servo, das an einem PWM-Ausgang hängt, mit pwm 30 auf den Winkel 30 Grad. Die Ansteuerung vom PC erfolgt mit dem Python Programm serial_control.py, das Sie auf die neuen Funktionen erweitern.


Anregung für eine Aufgabe mit Qt5-Programmierung (optional)

In Qt5/serialui sind Ansätze eines grafischen Programms, das dafür gedacht ist, mehrere Peripheriemodule des STM32 zu kontrollieren. Wie man das Programm kompiliert steht in serialui/README. Modifizieren Sie das Programm so, dass es zumindest die LED ein-/und auschalten kann. Sie können gerne auch eine oder mehrere der anderen angedeuteten Möglichkeiten weiter ausführen.

Um Programme mit Qt zu kompilieren, muss Qt erst mal installiert werden. Eine vollständige Installation benötigt jedoch sehr viel Platz (ca. 9 GByte). Sollte ihr freier Platz ausreichen, dann können Sie folgende Alternativen nutzen:

Eine weitere Alternative, die aber auch mehrere Gigabyte Platz braucht, ist die Anaconda Python Distribution, die Sie unter https://www.anaconda.com/distribution/ bekommen. Darin ist auch Qt5 enthalten.