Hallo !
Ich stehe mit meinem STM32F4DISCOVERY vor einem mir vorläufig noch
unerklärlichen Problem und hoffe, durch den einen oder anderen Tip auf
die richtige Fährte geführt zu werden.
Ausgehend von einer Spielwiesenapplikation unter CooCox und CMSIS, die 4
LEDS, gesteuert durch den SysTick im Sekundentakt im Kreis blinken
lässt, habe ich nun den USART3 hinzugefügt. Ich habe zur Zeit bloß die
Initialisierung durchgeführt und sende bzw. empfange noch nichts.
Wie man sieht, habe ich TXE Interrups enabled.
Demnach hätte SysTick höhere Priorität als USART3.
Das Verhalten ist nun, dass das Programm unmittelbar nach der Freigabe
des UART TXE Interrupts in die UART Service Routine springt. Das würde
mich nicht stören, da ja das TXE Flag erst einmal ansteht. Allerdings
wird die SysTick Service Routine überhaupt nicht mehr angesprungen. Ich
würde mir beim Ablauf des SysTick Timers erwarten, dass diese irgendwann
drankommt, da sie ja höhere Priorität hat als der USART, und gemäß
Programming Manual ein Pre-Empting von USART3 zugunsten SysTick
stattfinden sollte, da letzterer ja eine höhere Priorität zugewiesen
bekommt. Das scheint aber nicht zu passieren. Warum nicht?
Die USART Service Routine macht übrigens (noch) fast nichts, und ist
vorläufig nur für Testzwecke:
1
voidUSART3_IRQHandler(void)
2
{
3
doblink=1;
4
}
Vielen Dank; ich bin schon gespannt welchem Denkfehler ich hier
aufgesessen bin ;-)
Liebe Grüße,
Michael
Du musst natürlich im UART-Interrupt auch ein Zeichen versenden. Und
wenn keine Zeichen mehr da sind, schaltest Du den UART-Interrupt (in der
Interrupt-Behandlung!) wieder ab. So wird das System vom UART-Interrupt
dicht gemacht.
Eddy Current schrieb:> Du musst natürlich im UART-Interrupt auch ein Zeichen versenden. Und> wenn keine Zeichen mehr da sind, schaltest Du den UART-Interrupt (in der> Interrupt-Behandlung!) wieder ab. So wird das System vom UART-Interrupt> dicht gemacht.
Mir ist schon klar, dass dies so gemacht wird.
Mache ich den UART Interrupt nicht dicht, so erwarte ich mir aber
trotzdem, dass andere Interrupt-Routinen mit höherer Priorität
drankommen. DAS ist auch meine Frage, nicht wie man den UART bedient.
Hi,
habe gerade nicht alles auswendig im Kopf aber evtl. liegt dein Problem
am priority grouping. Evtl. Hast Du die Gruppierung AO gemacht, das die
Prios jetzt doch nicht mehr unterschiedlich sind.
In welcher Reihenfolge Rufst du die Konfigurationen auf? Sind die
Interrupts schon konfiguriert wenn Du den UART einschaltest?
Hast du den Systick einzeln getestet?
Ansonsten würde ich auch sagen, das des Systick bei höherer
Priodurchkommen müsste. Aber wie eddy auch schon geschrieben hat ball
erst Du im Moment dein System mit UART Interrupts voll.
Wenn das System so dicht ist, stellt sich evtl. die Frage, ob jemals der
Aufruf von SysTick_Config erreicht wird. Dann käme es auf die
Aufrufreihenfolge während der Initialisierung an. Ich würde bezüglich
des TX-Interrupts mal ein wenig "vom Gas" gehen.
Eddy Current schrieb:> Wenn das System so dicht ist, stellt sich evtl. die Frage, ob jemals der> Aufruf von SysTick_Config erreicht wird. Dann käme es auf die> Aufrufreihenfolge während der Initialisierung an. Ich würde bezüglich> des TX-Interrupts mal ein wenig "vom Gas" gehen.
Kann es passieren, dass der USAT IR so oft drankommt, dass er trotz
niederer Priorität blockiert?
Keine Ahnung. Ich beziehe mich momentan eher auf die Initialisierung.
Wenn die abgeschlossen ist, wird der Vordergrundprozess möglicherweise
nicht weiter ausgeführt und deswegen des SysTick nie eingeschaltet. Ich
sehe auch nirgends die Initialisierung des SysTick.
Eddy Current schrieb:> Keine Ahnung. Ich beziehe mich momentan eher auf die Initialisierung.> Wenn die abgeschlossen ist, wird der Vordergrundprozess möglicherweise> nicht weiter ausgeführt und deswegen des SysTick nie eingeschaltet. Ich> sehe auch nirgends die Initialisierung des SysTick.
SysTick_Config(RCC_Clocks.HCLK_Frequency / 100);
wird vorher aufgerufen:
Woran erkennst Du eigentlich, dass der SysTick nicht mehr aufgerufen
wird? Weil es nicht mehr blinkt? Blinken erledigt der
Vordergrundprozess, daher könnte der genauso gut zum stehen gekommen
sein.
Noch etwas grundsätzliches:
Unabhängig vom konkreten Problem (welches ich keinesfalls umgehen will),
erlaube ich mir zu fragen, wozu Du den präemptiven Interrupt überhaupt
benötigst?
Eddy Current schrieb:> Woran erkennst Du eigentlich, dass der SysTick nicht mehr aufgerufen> wird? Weil es nicht mehr blinkt? Blinken erledigt der> Vordergrundprozess, daher könnte der genauso gut zum stehen gekommen> sein.
Ursprüglich war die while(1) in main() leer und das blinken war in der
SysTick Routine. Auch da hat es nicht funktioniert. Wenn ich im Debugger
einen Haltepunkt setze, sehe ich, dass in die Routine nie gesprungen
wird. Haltepunkt in USART Handler wird sofort angesprungen.
Eddy Current schrieb:> Unabhängig vom konkreten Problem (welches ich keinesfalls umgehen will),> erlaube ich mir zu fragen, wozu Du den präemptiven Interrupt überhaupt> benötigst?
Es geht eher um ein Kennenlernen der Möglichkeiten. Ich habe kein
konkretes Problem, sonder "spiele" mich mit dem Ding herum. Mir ist es
wichtig, zu verstehen, was ich mache, daher brauche ich hier auch keinen
Workaround ;-)
Übrigens wird der Vordergrund nach dem USART3_Configuration() nicht mehr
bearbeitet. Es bleibt alles total im UART Handler hängen. Das könnte ich
ja noch "akzeptieren", aber dass der höherpriore Handler von SysTick
nicht angefahren wird...?
Michael W. schrieb:> ...daher brauche ich hier auch keinen Workaround ;-)
Gerade in Deinem Fall wäre der Workaround so einfach: Gib das Zeug in
den nächsten Mülleimer.
Ich würde den Testaufbau trotzdem verfeinern: Zeichen im UART-Interrupt
versenden, damit wir aus dem unbekannten Systemzustand herauskommen.
Zusätzlich eine Warteroutine von ein paar 100µs einbauen, um eine Chance
zu erhalten, dass der UART-Interrupt "getroffen" wird.
Eddy Current schrieb:> Michael W. schrieb:>>> ...daher brauche ich hier auch keinen Workaround ;-)>> Gerade in Deinem Fall wäre der Workaround so einfach: Gib das Zeug in> den nächsten Mülleimer.>>> Ich würde den Testaufbau trotzdem verfeinern: Zeichen im UART-Interrupt> versenden, damit wir aus dem unbekannten Systemzustand herauskommen.> Zusätzlich eine Warteroutine von ein paar 100µs einbauen, um eine Chance> zu erhalten, dass der UART-Interrupt "getroffen" wird.
Ich habe den UART schon zum Laufen gebracht und kann Zeichen senden.
Es geht mir hier um eine Verständnisfrage, nicht wie ich ein konkretes
Problem löse.
Die Frage ist: WIESO hat der SysTick Interrupt keine Chance, obwohl er
höhere Prio hat? Das, und sonst nichts will ich hier verstehen. Es muss
ja einen Grund geben. Die Frage wird auch nicht beantwortet, indem ich
den Code in den Mülleimer werfe...
NVIC_Init stammt aus der Zeit vor CMSIS und ist nur noch der lieben
Kompatibilität halber noch in der StdPerLib drin. Für die Core
Peripherals sollte CMSIS verwendet werden, sowas wie NVIC_SetPriority,
nicht die StdPerLib. "Not recommended for new designs", wie die
Datasheets immer sagen.
Ausserdem ist der SysTick kein normaler Interrupt, der Kram für die
System Exceptions sitzt im SCB und nicht im NVIC. Die CMSIS Funktionen
können damit umgehen, die StdPerLib nicht.
Michael W. schrieb:> Die Frage wird auch nicht beantwortet, indem ich> den Code in den Mülleimer werfe...
Mein Gott, das war ein Spass.
Du hast mich nicht verstanden: Du willst verstehen, das ist gut.
Andererseits ist Dein Setup so, dass man nicht unterscheiden kann, ob
Dein Problem durch 100% Systemlast oder durch eine falsche
Initialisierung entsteht.
Also rate ich Dir, beseitige das, worauf keine Antwort da ist (100%
Systemlast) und dann sehen wir weiter.
Es hilft jetzt nichts, wenn Du nur durch Nachdenken die Ursache des
Problems finden willst.
Ändere Deinen Testaufbau, und wir gewinnen Zusatzinformationen.
A. K. schrieb:> NVIC_Init stammt aus der Zeit vor CMSIS und ist nur noch der lieben> Kompatibilität halber noch in der StdPerLib drin. Für die Core> Peripherals sollte CMSIS verwendet werden, sowas wie NVIC_SetPriority,> nicht die StdPerLib. "Not recommended for new designs", wie die> Datasheets immer sagen.>> Ausserdem ist der SysTick kein normaler Interrupt, der Kram für die> System Exceptions sitzt im SCB und nicht im NVIC. Die CMSIS Funktionen> können damit umgehen, die StdPerLib nicht.
Ich habe gerade gesehen, dass für die Konfiguration der Prios nur 80
Bytes zur Verfügung stehen (siehe Bild).
Die Funktion NVIC_Configuration(void) schreibt aber an die 255. Stelle:
NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;
und NVIC_InitStruct->NVIC_IRQChannel ist bei mir 255, da
SysTick_IRQn = -1, /*!< 15 Cortex-M4 System Tick
Interrupt
Das wäre dann ja kompletter Blödsinn...oder? Die Funktion fängt das
nicht ab...
Habe gerade gesehen, dass man die Prio des SysTick extra im System
Handler Priority Register (SHPR3) einstellt. Ich probier mal, ob es dann
geht...
Danke für die Tips!
Michael W. schrieb:> Habe gerade gesehen, dass man die Prio des SysTick extra im System> Handler Priority Register (SHPR3) einstellt. Ich probier mal, ob es dann> geht...
Für den CM3 gibts die Fuktionen in core_cm3.h, die sowohl für Interrupts
als auch für die System Exceptions taugen. Wird beim CM4 nicht anders
sein. Aussrdem sind die nicht so umständlich wie STs Manie mit den
Structs.
War das eine schwere Geburt! ;-)
Die Lösung:
1) wird in der Funktion SysTick_Config(), die vorher drankommt, die
Priorität für SysTick auf 15 gesetzt, also auf den niederpriorsten
Wert. Soll so sein, aber ob das gut ist...?
2) funktionierte NVIC_Init(&NVIC_InitStructure) nicht für Interrupts <
0; d.h. nicht für den SysTick.
Verwendet man nun stattdessen NVIC_SetPriority(...) , wie von prx
vorgeschlagen, ist alles OK: Nun kommen sowohl die USART wie auch die
SysTick Routine dran.
Dass der Vordergrund nicht mehr drankommt verstehe ich...
Alles ist jetzt erklärbar und für mich OK.
"Problem" gelöst.