Hallo zusammen,
ich versuche gerade, auf meinem STM32F446 den PendSV-Handler vom
Systick-Handler unterbrechbar zu machen. So sieht mein Quelltext bislang
aus:
In den PendSV-Handler kommen später einmal etwas längere Berechnungen.
Zum Testen habe ich sie durch eine Warteschleife ersetzt.
Am Oszilloskop kann ich erkennen, daß der PendSV-Handler aufgerufen
wird, aber leider auch, daß in dieser Zeit der SysTick-Handler gar
nichts macht.
Ich hätte erwartet, daß der Systick-Timer, der die höhere
PreemptionPriority besitzt, den PendSV-Handler jederzeit unterbrechen
kann.
Wo liegt mein Denkfehler?
W.T.
Merkwürdig... wenn ich mir NVIC->ISER und NVIC->ICER ansehe, wird durch
die Initialisierung überhaupt nichts geschrieben. Ist die Init-Funktion
mit negativen Exception Numbers überfordert?
Walter T. schrieb:> Ich hätte erwartet, daß der Systick-Timer, der die höhere> PreemptionPriority besitzt, den PendSV-Handler jederzeit unterbrechen> kann.
Was den NVIC selbst angeht bedeutet ein niedrigerer Priority-Wert eine
höhere Dringlichkeit, d.h. es ist genau anders herum als man zunächst
annimmt. D.h. die höchste, vom Benutzer zu vergebende, Dringlichkeit hat
den Priority-Wert 0. Es gibt meiner Meinung nach absolut keinen Grund
für die NVIC-Konfiguration irgendeine Hersteller-Library zu verwenden,
weil der sich zwischen den Herstellern nicht unterscheidet und alles was
man braucht in den CMSIS-Core Headern steckt. Keine Ahnung was genau STs
NVIC_Init-Funktion macht. Jedenfalls macht es die Sache unnötig
kompliziert. Prinzipiell benötigt man eigentlich nur die Funktionen
NVIC_EnableIRQ und NVIC_SetPriority. Das Priority-Grouping lässt man am
besten einfach weg, d.h. auf dem Default-Wert ab Reset. Einen ganz
informativen Blog-Artikel zum Thema findest du hier:
https://embeddedgurus.com/state-space/2014/02/cutting-through-the-confusion-with-arm-cortex-m-interrupt-priorities/
Hallo Christopher,
danke für den Link. Es ist mir schon klar, daß die Prioritäts-Zahl um so
höher sein muß, je unterbrechbarer die ISR werden soll.
Ich habe mal den Tipp umgesetzt, mich allein auf die ARM-CMSIS ohne
STM-Herstellercode zu verlassen.
Main sieht jetzt so aus:
Das Gute: PendSV wird immer noch korrekt ausgelöst. Das Schlechte: Es
fängt zwar erst hinter dem Ende von SystickHandler an, läßt sich aber
von ihm nicht unterbrechen.
Das paßt auch zum Auslesewert "priority". Der ist immer 0.
Wenn ich das Reference Manual richtig verstehe, muß ich, damit ISRs
andere unterbrechen können, mit unterschiedlichen PriorityGroups
arbeiten.
NVIC_SetPriority scheint aber in SHP gar nicht zu schreiben.
Hallo Walter,
sieh Dir mal die Initialisierung der OS Interrupts in FreeRTOS an. Der
Pending SV muss unter Allen Umständen die niedrigste aller
Interruptprioritäten haben, damit er nur dann ausgeführt wird, wenn eine
Task aktiv ist (sonst gibt es keinen sauber definierten Kontext, aus dem
heraus geswitcht werden kann - der Pending SV ist das Herz des Context
Switch Mechanismus).
Du kannst Dir von hier:
http://www.springer.com/de/book/9783658148492
unter "Zusatzmaterial" die Beispielapplikationen umsonst und ohne
Seiteneffekte herunterladen. In Kapitel 3 gibt es dort das
Beispielprogramm HelloWorld_FreeRTOS, ein Blinky unter FreeRTOS für den
STM32Fxxx.
Eine genauere Beschreibung darüber, wie sich die beiden Interrupts
miteinander verhalten, um Context Switches zu realisieren, gibt's in
Kapitel 3.4.2. des Buches.
Die Priority Groups sind eine Eigenheit von ST. Der ARM Kernel erlaubt
es, zwischen 8 und 256 Interruptprioritäten zu implementieren, damit
sind je nach POD zwischen 0 und 5 bits im Prioritätsfeld frei. ST nutzt
dieses zur Implementation von Subprioritäten. Nein, es muss nicht
aktiviert werden, um die Interrupts wie gewohnt zu nutzen. Sieh einfach
im STM port von FreeRTOS nach, wie der Controller initialisiert wird.
Tipp: Der Kontrollfluss ist nicht immer einfach im Quelltext
nachvollziehbar. Sieh Dir in der IDE deiner Wahl nach abgeschlossener
Initialisierung die Registerwerte von SCB und NVIC im SFR Fenster an,
damit Du weisst, was genau in den Registern drinsteht.
Ruediger A. schrieb:> Der> Pending SV muss unter Allen Umständen die niedrigste aller> Interruptprioritäten haben,
Das gilt nur dann, wenn ich ein OS benutze, das den Pending_SV nutzt.
Ich habe kein OS. Für mich ist der Pending_SV einfach nur ein beliebiger
IRQ, der frei ist, weil er sonst nur von einem OS genutzt würde. Die
Timer-IRQs gehen mir nämlich so langsam aus.
Mein Ziel ist: Pending_SV_Handler soll von SysTick-Handler gestartet und
beliebig oft von diesem unterbrochen werden.
Soo....ich habe es gefunden. Die Konfiguration in Beitrag
Beitrag "Re: STM32 Interrupt-Prioritäten - mal wieder"
war schon so weit in Ordnung, bis auf die PriorityGroupConfig. Hier
gehört
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
hinein. Der M3 Guide von Joseph Yiu hat es besser erklärt als das ARM
Reference Manual.
Was ich noch nicht verstanden habe ist, warum
NVIC_GetPriority(PendSV_IRQn);
Null zurückliefert.
Wie gesagt ist das Priority-Grouping meiner Meinung nach unnötig. Lies
dir noch mal den Abschnitt zu den Subpriorities in dem Blog-Artikel
durch.
So sollte es eigentlich auch funktionieren:
Christopher J. schrieb:> So sollte es eigentlich auch funktionieren:> NVIC_SetPriorityGrouping(0);>> NVIC_SetPriority(PendSV_IRQn, 1);> NVIC_SetPriority(SysTick_IRQn, 0);
Das verstehe ich nicht. Die 1 müßte doch irgendwo in den fünf hinteren,
beim STM32 nicht implementierten Bits des Priority Registers
verschwinden. Und selbst wenn alle 8 Bit da wären, wäre sie an Bit 0, wo
selbst bei NVIC_SetPriorityGrouping(0) noch nicht-preemptive Priorität
stünde.
Edit: Die MCU versteht es auch nicht.
Nene, NVIC_SetPriority schiebt die 1 automatisch an die niedrigste
Stelle, die noch implementiert ist, d.h. bei drei Prio-Bits an die 5.
Stelle. Ich kann nur nochmal auf den Blog-Artikel verweisen, weil auch
dieser Zusammenhang dort anschaulich erklärt wird.
Walter T. schrieb:> Edit: Die MCU versteht es auch nicht.
Da verstehe ich wiederum nicht warum. Hast du den restlichen NVIC-Kram
von ST aus deinem Source-Code entfernt?
Im folgenden mal ein Ping-Pong-Beispiel mit PendSV und SysTick.
Den Systick triggere ich wie PendSV per Software. Natürlich würde das
normalerweise der Systick-Timer übernehmen. Jedenfalls triggert der
Systick-Handler, je nachdem ob eine Bedingung erfüllt ist, den
PendSV-Handler. In diesem Beispiel triggert der PendSV-Handler wiederum
den Systick-Handler um einen Systick-Interrupt zu simulieren. Wenn der
Systick keine höhere Dringlichkeit (d.h. niedrigeren Prioritätswert)
hat, dann wird das while(cnt) im PendSV-Handler zur Dauerschleife. Das
ganze habe ich getestet auf einem F411RE, wobei das so grundsätzlich -
von der unterschiedlichen Headerbezeichnung abgesehen - auf jedem
Cortex-M laufen sollte.
OK, Dein Beispiel kann ich auf einem STM32F446 nachvollziehen.
Bei meinem Beispiel ebenfalls: Wenn ich auf die Makros verzichte und die
Zahlen hart eintippe, funktioniert es: Der PensSV_Handler wird vom
SysTick_Handler unterbrochen.
Jetzt habe ich auch meinen Fehler gefunden: Das Makro
"NVIC_PriorityGroup_0" ist noch ein letzter Rest aus der misc.h und ist
von der Bedeutung genau invers zu dem, was man aus der ARM-Doku erwarten
würde.
Der Compiler hat deswegen keine Warnung wegen der fehlenden Definition
des Makros ausgegeben, weil die misc.h indirekt über die
stm32f4xx_conf.h eingebunden war.
Wegen einer Abbildung im obengenannten Buch bin ich davon ausgegangen,
daß "Priority Group = 0" bedeutet, daß es ein Sub-Priority Bit gibt.
Dann hätte eine Priorität 1 eine Priorität 0 nie unterbrechen können,
weil sie die gleiche Preemption Priority gehabt hätten.
Es klart sich auf!
Danke für Deine Hilfe!