Servus allerseits
Meine Schaltung steht, die Software laeuft. Nur: nach 10 - 30 Sekunden
haengt sich die Software auf: die Tastatur reagiert nicht mehr, die
Ctrl-LED blinkt nicht mehr.
Wenn der Debugger angeschlossern ist (ST-Link oder J-Link), kann ich mit
Halt das Programm anhalten, und gleich mit Go weiterfahren. Dann
funktioniert es wieder so für 10 bis 30 Sekunden.
Mit ist aufgefallen, dass ich bei diesen Haengern dann jedesmal im
Interrupt Handler des Usart3 mich wiederfinde.
(Am Usart3 ist ein Atmega angeschlossen, der vom STM32 Anweisungen
erhaelt und je nach Anweisung mit 2 bis 4 Byte antwortet.)
Ich habe dann einen Breakpoint auf diese erste Zeile im Interrupt
gesetzt und festgestellt, dass diese Zeile immer angesprungen wird,
obwohl RXNE nicht gesetzt ist.
Es wird also irgendwo ein Interrupt ausgelöst. Nur: Im CR1 Register des
Usart3 ist nur RE, RE und RXNEIE gesetzt.
Irgendwie habe ich das Gefühl, als würde ein IDLE Interrupt ausgelöst
werden, aber IDLEIE ist definitiv nicht gesetzt.
PS1: Die RxD Leitung ist sauber, dort kommt nur, was auch wirklich
kommen soll und muss. Der Atmega ist also nicht der Schuldige.
PS2: Waehrend ich diese Zeilen schreibe, kam es nur 2x zu einem Haenger
und waehrend diesen 2 Haengern lief das gute Stück ca. 5 Minuten ohne
Probleme.
Bin dankbar für jeden Hinweis und sei es auch noch so spekulativ.
MfG aus Istanbul
Hallo Mehmet,
> Bin dankbar für jeden Hinweis und sei es auch noch so spekulativ.
Immer doch :) Wild gewordener Zeiger der zufälligerweise das
entsprechende Interruotbit setzt und gleich wieder löscht ...
Was steht im SR Register, wenn der "Phantom" Interrupt ausgelöst wird?
Gruß
Jörn
Mehmet Kendi schrieb:> Der SR Register enthaelt dann 0xD8
Moin Mehmet.
Dann scheint das ORE (overrun error detected) der Schuldige zu sein.
Wenn der Interrupt RXNEIE (RXNE interrupt enable) aktiv ist, dann steht
im Datenblatt, dass bei RXNE oder ORE ein Interrupt ausgelöst werden.
Irgendwie scheint ein Überlauf beim Empfänger aufzutreten. Sperrst du
die Interrupts irgendwo zu lange? Oder sind die Prioritäten so vergeben,
dass der UART Interrupt evtl. nicht schnell genug dran kommt?
Edit: Gerade sehe ich, dass dafür das EIE (Error interrupt enable) in
CR3 auch gesetzt sein muß. Ist das der Fall?
Aber das gesetzte ORE Bit würde mir trotzdem Sorgen machen.
Woher kommt der ORE (Overrun Error)?
Ist bei dir folgende Zeile noch vorhanden, wenn du das Programm
übersetzt hast. Nicht dass der Compiler diese rausschmeißt da die
Variable nur beschrieben und nicht weiter verwendet wird.
> uint8_t tmp = USART3->DR; // dummy read
Dadurch würde auch das RXNE Bit nicht zurückgesetzt werden und die ISR
würde dauerhaft aufgerufen werden.
G a s t schrieb:> Nicht dass der Compiler diese rausschmeißt
Hmmm.... vielleicht ist das so. Würde das Verhalten auch erklären.
Dann die Zeile wie folgt ändern:
volatile uint8_t tmp = USART3->DR; // dummy read
Mit volatile dürfte der Compiler die Zeile nicht rausschmeißen.
Aber EIE (Error interrupt enable) in CR3 müßte auch gesetzt sein,
wenn ich das Datenblatt richtig verstehe, sonst dürfte bei ORE kein
Interrupt auftreten.
Edit: Alles Quatsch oben :-) Das mit dem volatile wird nicht helfen. Die
Registerdefinitionen der UARTs sind ja schon volatile. Die Zeile dürfte
in keinem Fall rausgeschmissen werden.
900ss D. schrieb:> Aber EIE (Error interrupt enable) in CR3 müßte auch gesetzt sein,> wenn ich das Datenblatt richtig verstehe, sonst dürfte bei ORE kein> Interrupt auftreten.
Gebe ich dir Recht. Allerdings wenn ein Errorbit gesetzt ist, macht mich
das immer etwas stutzig.
G a s t schrieb:> Allerdings wenn ein Errorbit gesetzt ist, macht mich> das immer etwas stutzig.900ss D. schrieb:> Aber das gesetzte ORE Bit würde mir trotzdem Sorgen machen.
:-)
Kleine Zwischenbilanz:
Meine Prioritaeten sind wie folgt gesetzt:
1
constintINT_PRIORITY_USART3=1;
2
constintINT_PRIORITY_TIM2=2;
3
constintINT_PRIORITY_USART1=3;
4
constintINT_PRIORITY_SYSTICK=15;
Baudrate ist 1,25MBaud
Ich habe jetzt mal den Atmega schlafen gelegt (Reset auf Low).
Nach ca. 2 Minuten, wurde der Interrupt ausgelöst und SR enhielt 0x1D8.
Also LBD, TXE, TC, IDLE, ORE. (LBDIE ist nicht gesetzt)
Nach einem CONTINUE ging's dann wieder so 'ne Zeitlang bis ich dann
wieder im Interrupt landete.
Diesmal mit 0xD0 im SR Register.
Ich habe dann die Stopuhr ausgepackt:
00:02:16 SR: 0x1D0
00:02:35 SR: 0x1D8
00:00:00 SR: 0x1C0 (CONTINUE brachte mich gleich wieder zum Breakpoint)
00:02:27 SR: 0x1D8
00:00:00 SR: 0x1D0 (CONTINUE brachte mich gleich wieder zum Breakpoint)
00:05:45 SR: 0x1C2
Gute Morgen Mehmet,
muss man nicht wenn ein Interrupt ausgelöst wird, immer auch noch das
PendingBit wieder zurücksetzten? Da er ansonsten immer wieder in den
Interrupt springt?
Oder habe ich da iwas falsch verstanden? (Sry bin noch recht neu im
Umgang mit den STM32)
Der Befehl wäre dann folgender:
Da kommen trotz stillgelegtem Empfänger ORE und FE?
Lege mal den UART-RX direkt am STM32 auf Masse. Fängst du dir Müll am
Empfänger ein?
Schick mal alle Registerinhalte des UARTs. So weiß man ja nicht, welche
IRQs wirklich freigeschaltet werden.
noobuntu schrieb:> muss man nicht wenn ein Interrupt ausgelöst wird, immer auch noch das> PendingBit wieder zurücksetzten?
Muß man nicht bei allen Interrupts. Steht im Datenblatt bei der
Beschreibung des Statusregisters. Da wir aber nicht wissen, wie der UART
von Mehmet aufgesetzt ist, können wir das gerade nicht sagen.
Hi,
ich würde auch wetten (wie noobuntu schon sagte), das du das Flag
löschen musst.
Also am Ende der ISR mal
"USART_ClearFlag(USART3, USART_FLAG_RXNE);"
einfügen.
Gruß
Jean Payer schrieb:> Hi,> ich würde auch wetten (wie noobuntu schon sagte), das du das Flag> löschen musst.>> Also am Ende der ISR mal> "USART_ClearFlag(USART3, USART_FLAG_RXNE);"> einfügen.>> Gruß
Ok, die Wette nehme ich an. Ich sage, man muss es nicht löschen, das
passiert beim lesen des empfangenen Bytes automatisch. Ich setze mein
Fahrrad ;-)
900ss D. schrieb:> Jean Payer schrieb:>> Hi,>> ich würde auch wetten (wie noobuntu schon sagte), das du das Flag>> löschen musst.>>>> Also am Ende der ISR mal>> "USART_ClearFlag(USART3, USART_FLAG_RXNE);">> einfügen.>>>> Gruß>> Ok, die Wette nehme ich an. Ich sage, man muss es nicht löschen, das> passiert beim lesen des empfangenen Bytes automatisch. Ich setze mein> Fahrrad ;-)
Ich glaube da hat der 900ss D. recht. Seht sogar bei der Dokumentation
der STM32 FirmwareLib der ClearPendingBit Funktion für den UART.
Leider hat sich das Licht im Tunnel (wieder einmal) als ein
entgegenkommender Zug herausgestellt.
Ich habe mal zu Testzwecken die Intervalle, in denen der STM32 dem
Atmega auf die Schulter tippt, vergrössert. Nun wird anstelle von 100ms
alle 5 Sekunden eine Anfrage losgeschickt.
Und alle 5 Sekunden lande ich im Interrupt.
Also an der Software scheint es nicht zu liegen. Und trozdem, nach einer
gewissen Zeit bleibe ich in diesem Interrupt haengen.
In meiner Ratlosigkeit habe ich am Rx-Eingang des STM32 einen 3k9
pull-up Widerstand angeklemmt.
Und siehe da: der Haenger kam erst nach 21 Minuten. Absoluter Rekord!
Jetzt haengt ein 2k2 Widerstand an diesem Eingang. Bin bei 25 Minuten
....
toi toi toi
Hast Du mal das Programm auf ein Minimum reduziert, so dass nur noch die
USART-Funktion drin ist? Manchmal gibts bei den STM32 auch Probleme,
wenn bestimmte Peripheriekomponenten gleichzeitig genutzt werden und
über notwendige Initialisierungsreihenfolgen wurde hier auch schon
berichtet.
Zeig mal das ganze Programm und die Schaltung?
Mehmet Kendi schrieb:> Also an der Software scheint es nicht zu liegen. Und trozdem, nach einer> gewissen Zeit bleibe ich in diesem Interrupt haengen.
Wieso liegt es nicht an der SW wenn du dem ATMEGA nur alle 5s auf die
Schulter tipst und du nur alle 5s einen IRQ hast? Ein schleichendes
Memory Leak und nach 20min. PENG! Egal wie oft du IRQs hast. Aber die
Anzahl der IRQs scheinen ja mit der Laufzeit bis zum Fehler
zusammenzuhängen?
Evtl. hast du einen Fehler in der Abarbeitung der Empfangsdaten nach dem
IRQ?
Hängt sich das Programm auch auf, wenn du keine Daten zum STM schickst?
Du könnest auch mal den IRQ tot machen und in der Hauptschleife (oder an
geeigneter Stelle) pollen. Wie ist es dann?
Was immer noch merkwürdig ist: der ORE und FE Fehler. Das können
Baudratenfehler oder Störungen auf der Leitung sein.
Oder wie oben schon jemand vorgeschlagen hat, specke das Programm auf
Minimum ab und nutze die gleiche UART-Initialisierung.
Ich betreibe den UART mit 115kB und TX- und RX-IRQ, allerdings hängt
dort ein Terminal dran. Da kommen beim empfangen nicht so viele Daten
zusammen (jedenfalls nicht, wenn ich etwas Sinnvolles eintippe :-) Aber
es läuft ohne Fehler.
Matthias K. schrieb:> Zeig mal das ganze Programm und die Schaltung?
:D Ich glaube nicht, dass hier jemand Lust haette, ernsthaft sich durch
15 Scheets und zig hundert Zeilen Code durchzuarbeiten!
900ss D. schrieb:> Hängt sich das Programm auch auf, wenn du keine Daten zum STM schickst?
Ich habe schon dermassen vieles durchgehechelt, dass ich manchmal selbst
nicht weiss, was ich schon ausprobiert habe oder nicht.
Aber ich glaube (glaube: anderes Wort für 'nicht wissen') das hatte ich
schon man probiert. Und ich glaube mich zu erinnern, dass es dann nicht
zu einem Haenger gekommen ist.
Ich lass diesen Test aber nochmals durchlaufen; sicher ist sicher. Ich
habe jetzt die Stoppuhr ins Programm eingebaut: wenn's knallt, dann
bleibt die Uhr stehen.
Z.Zt. ist der Ablauf eigentlich recht simple:
Beim Init gibt der STM32 dem Atmega durch, welche 3 Spannungen er
erzeugen soll. Dann, in der TaskLoop wird alle 100ms der Atmega befragt,
ob irgendwelche Sensortasten gedrückt worden sind. Falls nein, gibts ein
Paket mit einer 0, sonst halt ein Paket mit dem Inhalt der gedrückden
Tasten.
900ss D. schrieb:> Ein schleichendes Memory Leak und nach 20min. PENG!
Wie weiter oben erwaehnt: wenn ich beim Debugger kurz auf Halt und dann
gleich wieder auf Continue drücke, geht es problemlos bis zum naechsten
Haenger weiter.
Also wenn's ein Memory Problem waere, wie Du vermutest, könnte ich
sicher nicht weiterfahren, als waere nichts geschehen.
Mehmet Kendi schrieb:> :D Ich glaube nicht, dass hier jemand Lust haette, ernsthaft sich durch> 15 Scheets und zig hundert Zeilen Code durchzuarbeiten!
Um so mehr ist es angebracht, erstmal alles um die USART raus zu
schmeisen und wenn dann der Fehler nicht mehr auftritt, es schrittweise
wieder einzubinden.
Okay, für heute mache ich den Laden dicht. Bei uns ist es jetzt 21 Uhr
...
Ich lass mal das Ding so mal laufen, mal schauen wie weit ich komme.
Morgen werde ich mal alles ausser Ctrl-LED und USART ausklammern.
Gute Nacht, und danke für die Hilfe.
Mehmet Kendi schrieb:> Okay, für heute mache ich den Laden dicht.
Gute Idee, 'n Rotwein und entspannen. Dann kommt die Idee von selbst.
:-)
> Gute Nacht, und danke für die Hilfe.
Auch gute Nacht. Aber 21:00 Uhr ist noch recht früh für die Matraze
oder?
900ss D. schrieb:> Ok, die Wette nehme ich an. Ich sage, man muss es nicht löschen, das> passiert beim lesen des empfangenen Bytes automatisch. Ich setze mein> Fahrrad ;-)
Hehehe, ich habe leider kein Fahrrad, ansonsten .... !
Nein mal im Ernst habe gerade noch mal Detenblatt studiert, du hast
schon Recht beim auslesen des Datenregisters sollte das Bit gelöscht
werden !
Zitat:
In single buffer mode, clearing the RXNE bit is performed by a software
read to the USART_DR register
Zeig doch mal deinen gesamten Kendi, bzw. hänge ihn als Datei mal an.
Dann kann man dir sicher helfen.
Aber bitte so das er compilierbar ist. Dann Debug ich mal schnell durch.
Gruß
21 Uhr ist natürlich nicht Schlafenszeit :)
Aber ich versuche jeden Abend so für 'ne Stunde aufs Laufband zu
klettern.
Nach der sportlichen Ertüchtigung gings weiter bis Mitternacht. Nichts
als Frust.
Als ich heute morgen den Motor wieder anwarf, war von gestern abend noch
ein Breakpoint in der ersten Zeile im Interrupt.
Der STM32 hatte in der Init-Phase dem Atmega ein paar Anweisungen
erteilt und dieser hatte geantwortet.
Also klar, dass der Breakpoint ansprang. Womit der Empfang abgewürgt
worden war.
Ein Continue brachte aber gar nichts. Der STM32 hatte sich aufgehaengt.
Und da fiel bei mir endlich der Groschen.
Die Bemerkungen von 900ss "Aber das gesetzte ORE Bit würde mir trotzdem
Sorgen machen." war der springende Punkt.
Ursache
Dem STM32 sind die 1.250.000 Baud sporadisch zu schnell.
Sollte zwar nicht sein, aber wie auch immer; werde es spaeter naeher
untersuchen.
Es kommt zu einem Overrun. ORE flag im SR Register wird gesetzt und ein
Interrupt wird generiert.
Und solange dieser Status nicht gelöscht wird, kommt es zu einem
Interrupt-Trommelfeuer.
Wenn dann der Debugger den STM32 anhaelt, muss er ja alle Register
auslesen. Somit auch das SR Register und das DR Register .... womit
dieser Interrupt gelöscht wurde.
Und weshalb ein Continue den STM32 dazu veranlasste weiterzufahren, so
als waere nichts geschehen.
Lösung
In der Interrupt Routine nach dem Test der RXNE und TXE Flags ein else
hinzugügen und das DR Register lesen.
Ein explizietes Lesen des SR Register ist nicht mehr notwendig, da ja
dieses mit der USART_GetITStatus() Funktion bereits geschehen ist.
Mehmet Kendi schrieb:> Und da fiel bei mir endlich der Groschen.
Fein, freut mich dass du es gefunden hast.
Bei 1,25MB trudeln alle 8us ein Byte ein. Wenn du da nicht fix abholst,
dann hast du schon den Überlauf.
900ss D. schrieb:> Bei 1,25MB trudeln alle 8us ein Byte ein
Aber diese 8us bedeuten für die MCU @72MHz 576 Cyclen. Haette eigentlich
schon erwartet, dass das keine Probleme gibt.
Habe mal nachgeführt, wie oft ein Haenger aufgefangen wurde:
Nach 45 Minuten (entspricht ca. 27.000 Anfragen) gab es 19 Haenger.
Mehmet Kendi schrieb:> Aber diese 8us bedeuten für die MCU @72MHz 576 Cyclen
Stimmt schon. Ist halt die Frage, wie die IRQ-Latenzzeit ist. Wenn du
die IRQ-Bearbeiung erst noch einer Aufwendigen Routine übergibts, also
bis der "echte" UART-Handler angesprungen wird, dann ist es wohl eng.
Ich hab das bei einem RTOS gesehen. Da gab es Routinen zum registrieren
von IRQ-Handler u.s.w.. Alle IRQs wurden einer zentralen Routine
zugeführt und von der erst über eine Tabelle in den echten Handler
gesprungen. Ich war erstaunt, wie "lahm" das war gegenüber einem
direktem Ansprung.
Du kannst das ja mal mit einem 2-Kanal Scope messen. Setze am Anfang des
UART-Handlers einen Portpin, am Ende wieder zurück. Dann mißt du mit dem
Scope die UART-RX-Leitung und siehst, wann ein Zeichen komplett durch
ist, danach muß dann ja der Portpin kurz aktiv werden. Da siehst du dann
wie lange das dauert. Wenn es mehr als 8us sind hast du verloren ;-)