Grüß euch
Ich hab grad ein kurioses Problem mit einem STM32L431. Und zwar würde
ich gerne die Priorität eines laufenden Interrupts ändern. Das sieht in
Pseudo-Code folgendermaßen aus:
1
voidisr(){
2
// do stuff
3
NVIC_setPriority(IRQn,10u);
4
// do some more stuff
5
NVIC_setPriority(IRQn,0u);
6
}
Leider führt das ganze im laufenden Betrieb zu einen Hardfault. Zeit und
Ort wann der Hardfault auftritt scheinen recht zufällig übers gesamte
Programm verteilt zu sein.
Ein Blick auf die Fault Status Register verraten, dass im UFSR Register
das INVPC Bit gesetzt ist:
Leider erschließt sich mir nicht ganz wo genau jetzt das Problem liegt
und ich hab auch keine Idee wie ich das näher eingrenzen soll.
Ebenfalls interessant ist, dass folgende Variante, die den Interrupt
vorm Änderung der Priorität sperrt, funktioniert:
Vincent H. schrieb:> Irgendwer eine Idee?
Klingt vielleicht doof, aber ich würde sowas gar nicht machen.
Welchem Zweck soll es denn dienen, zur Laufzeit die Prioritäten zu
ändern?
Stefan ⛄ F. schrieb:> Vielleicht darf man die Prio nicht innerhalb einer ISR ändern.
Ohne es genauer zu wissen stelle ich mir vor dass der NVIC
eine Art eigenen Stack verwaltet, und dieser Stack kommt
während einer Änderung der Prioritäten im Interrupt-Kontext
durcheinander. So, dass es krachen muss ....
Johnny B. schrieb:> Klingt vielleicht doof, aber ich würde sowas gar nicht machen.
Ich auch nicht.
Wo es doch durchaus machbar ist dies im Nicht-Interrupt-Kontext
zu setzen.
Den Text kenn ich, RTOS nutze ich keines. Ein Workaround via PendSV wäre
wohl denkbar um den selben Effekt zu erzielen, aber ich würd auch gerne
verstehn wieso der Hardfault triggered...
Stephan schrieb:> Vincent H. schrieb>> um den selben Effekt zu erzielen,>> Welchen Effekt denn genau?
Dass die Interrupt Priorität für "// do some more stuff" gesenkt wird
und Interrupts höherer Priorität diesen Teil unterbrechen können.
Vincent H. schrieb:> Stephan schrieb:>> Vincent H. schrieb>>> um den selben Effekt zu erzielen,>>>> Welchen Effekt denn genau?>> Dass die Interrupt Priorität für "// do some more stuff" gesenkt wird> und Interrupts höherer Priorität diesen Teil unterbrechen können.
Ach Du meinst Nested-Interrupts. Das ist natürlich nochmals eine völlig
andere Geschichte und würde ich noch weniger anwenden als während der
Laufzeit nur die Prioritäten zu ändern.
https://developer.arm.com/docs/dui0553/latest/cortex-m4-peripherals/nested-vectored-interrupt-controller
Du schreibst, dass Du noch kein RTOS einsetzt; lasse Dir doch von den ST
Tools mal FreeRTOS einbinden. Damit lässt sich super arbeiten und die
meisten Anwendungsfälle elegant abdecken.
Johnny B. schrieb:> Vincent H. schrieb:>> Stephan schrieb:>>> Vincent H. schrieb>>>> um den selben Effekt zu erzielen,>>>>>> Welchen Effekt denn genau?>>>> Dass die Interrupt Priorität für "// do some more stuff" gesenkt wird>> und Interrupts höherer Priorität diesen Teil unterbrechen können.>> Ach Du meinst Nested-Interrupts. Das ist natürlich nochmals eine völlig> andere Geschichte und würde ich noch weniger anwenden als während der> Laufzeit
"The Guru" schreibt aber hier explizit (im M3/M4 habe ich auf die
Schnelle auch nix gegenteiliges gefunden)
https://community.arm.com/developer/ip-products/processors/f/cortex-m-forum/2683/changing-interrupt-priority-to-prevent-nesting
das es tatsächlich mit ARMv7 möglich ist, das dynamisch IN der ISR zu
machen... (ob das jetzt Sinn macht ist eine andere Frage)...
Der HardFault kommt also möglicherweise woanders her:
Mein Tippp (s.o): Doch ein Stack problem? oder der NVIC kommt eben doch
durcheinander, wenn man in einer ISR > 0 dann wie Vincent die höchste
Prio mit "NVIC_setPriority(IRQn, 0u)" setzt...
Stephan
Das interessante ist, dass ich so eine Änderung der Prioritäten bereits
erfolgreich in die andere Richtung genutzt habe. Ich hab in einem Teil
meines Codes eine Interrupt gesteuerte State-Machine die zwischen 2x
Interrupts die Priorität ganz hochdreht weil ein einzelner State-Wechsel
extrem zeitkritisch ist, der Rest aber eher "best effort".
Dort geschieht das ändern der Priorität aber halt nur 1x, quasi
1
voidstate0(){
2
NVIC_setPriority(IRQn,0u);
3
}
4
5
voidstate1(){
6
NVIC_setPriority(IRQn,normal_prio);
7
}
Das funktioniert tadellos.
Ruediger A. schrieb:> Mglw. musst Du eine Barriere setzen.
Keine Änderung.
Also ich meine ich hätte mal irgendwo gelesen man soll die Priorität
setzen bevor man ihn enablet. Kanns aber nicht beschwören, hab aber
auch noch nicht ausprobiert was passiert wenn man davon abweicht oder
gar solche akrobatische Stunts wie Du da zu machen beabsichtigst
durchführt.
Nur ein einziges mal in einer ganz dunklen Stunde als es draußen
geblitzt und gedonnert hat hab ich mich mal selbst ertappt wie ich in
den nächtlichen bläulichen Schein des Bildschirms getaucht und der
Vernunft fast schon ganz entrückt aus einem Akt der puren Verzweiflung
heraus in einem Interrupt auf den Systick warten wollte, dann dachte ich
"Scheiße, das kann doch jetzt wohl nicht mein Ernst sein in Erwägung zu
ziehen diesen IRQ zeitweise niedriger zu priorisieren nur um hier jetzt
auf die Zeit warten zu können!?" - Ich habs schnell wieder verworfen und
einen Tag später nach einigen tieferen Umbauten war das Problem auf die
saubere Art gelöst.
Ok, noch ein paar Ideen:
1. Läuft ein Anderer ISR auf einer Priorität zwischen den beiden Prios,
zwischen denen Du deinen faultenden ISR togglest? Wenn ja, kann man das
testweise ändern (nur um herauszufinden, ob der Fault damit beeinflusst
wird)?
2. Wenn Du die Prio nur herunter- aber nicht mehr heraufsetzt, tritt der
fault dann auch noch auf?
3. (Variante)
void isr() {
// do stuff
NVIC_disableIRQ(IRQn);
NVIC_setPriority(IRQn, 10u);
NVIC_enableIRQ(IRQn);
// do some more stuff
NVIC_disableIRQ(IRQn);
NVIC_setPriority(IRQn, 0u);
NVIC_enableIRQ(IRQn);
}
Reicht es, das Disablen und enablen nur in einer der beiden Pfade zu
machen, damit das Problem weggeht? Wenn ja in welchem?
Meine momentane Vermutung ist, dass das back-to-back chaining von ISRs
durcheinandergerät. Wenn dem so ist, wird es nichts geben, was Du
dagegen tun kannst, ausser eben das disablen (reicht Dir das nicht?).
Ruediger A. schrieb:> Ok, noch ein paar Ideen:>> [...]>> Meine momentane Vermutung ist, dass das back-to-back chaining von ISRs> durcheinandergerät. Wenn dem so ist, wird es nichts geben, was Du> dagegen tun kannst, ausser eben das disablen (reicht Dir das nicht?).
Meine Vermutung geht in ungefähr die selbe Richtung.
Ich habe vielleicht was nicht verstanden oder überlesen, aber kann es
sein, dass Du:
1. Die Priorität genau desjenigen Interrupts änderst, in dessen ISR Du
Dich gerade befindest?
2. Du die Priorität eines momentan noch höherprioren oder niederprioren
Interrupts änderst, der gerade ansteht.
3. Gibt es überhaupt Pending Interrupts, während Du das tust?
Ruediger A. schrieb:> Ok, noch ein paar Ideen:>> 1. Läuft ein Anderer ISR auf einer Priorität zwischen den beiden Prios,> zwischen denen Du deinen faultenden ISR togglest? Wenn ja, kann man das> testweise ändern (nur um herauszufinden, ob der Fault damit beeinflusst> wird)?
Ja, auf so gut wie jeder Ebene zwischen 0 und 10 läuft ein anderer
Interrupt. Theoretisch könnte ich alle Prios mal raufschieben ja.
> 2. Wenn Du die Prio nur herunter- aber nicht mehr heraufsetzt, tritt der> fault dann auch noch auf?
Nein.
> 3. (Variante)>> void isr() {> // do stuff> NVIC_disableIRQ(IRQn);> NVIC_setPriority(IRQn, 10u);> NVIC_enableIRQ(IRQn);> // do some more stuff> NVIC_disableIRQ(IRQn);> NVIC_setPriority(IRQn, 0u);> NVIC_enableIRQ(IRQn);> }>> Reicht es, das Disablen und enablen nur in einer der beiden Pfade zu> machen, damit das Problem weggeht? Wenn ja in welchem?>> Meine momentane Vermutung ist, dass das back-to-back chaining von ISRs> durcheinandergerät. Wenn dem so ist, wird es nichts geben, was Du> dagegen tun kannst, ausser eben das disablen (reicht Dir das nicht?).
Es scheint dass das disablen/enablen an jener Stelle reicht wo wieder
auf die höhere Prio geschalten wird.
Theor schrieb:> Ruediger A. schrieb:>> Ok, noch ein paar Ideen:>>>> [...]>>>> Meine momentane Vermutung ist, dass das back-to-back chaining von ISRs>> durcheinandergerät. Wenn dem so ist, wird es nichts geben, was Du>> dagegen tun kannst, ausser eben das disablen (reicht Dir das nicht?).>> Meine Vermutung geht in ungefähr die selbe Richtung.>> Ich habe vielleicht was nicht verstanden oder überlesen, aber kann es> sein, dass Du:>> 1. Die Priorität genau desjenigen Interrupts änderst, in dessen ISR Du> Dich gerade befindest?
Ja.
> 2. Du die Priorität eines momentan noch höherprioren oder niederprioren> Interrupts änderst, der gerade ansteht.
Nein. Es wird nur die Prio des gerade aktiven IRQs geändert.
> 3. Gibt es überhaupt Pending Interrupts, während Du das tust?
Höchstwahrscheinlich ja.
Vincent H. schrieb:> Ruediger A. schrieb:>>> 2. Wenn Du die Prio nur herunter- aber nicht mehr heraufsetzt, tritt der>> fault dann auch noch auf?>> Nein.>
das klingt fast so, als ob der ISR wieder ansteht, während er
abgearbeitet wird und sich deswegen "selbst unterbricht." Ich denke
nicht, dass der NVIC das abhandeln kann (Du hast ja z.B. im SCB ein
Register für die Prio des momentan anstehenden Interrupts, was für keine
Verschachtelung von ISRs ausserhalb der statischen Hierarchie spricht).
Was ist wenn Du den ISR nicht auf NVIC Ebene, sondern auf
Peripherieebene abstellst während er seine Priorität hochsetzt? Kannst
Du das Löschen des Interruptrequests in der Peripherie auf nach dem
Hochstellen verschieben?