MSP430 startet sporadisch neu

#7718513
Lesenswert?

Hallo zusammen,

ich arbeite aktuell mit einem MSP430G2553. Ich hatte das 'System' eigentlich sehr stabil am Laufen, musste aber nun noch etwas hinzufügen. Jetzt habe ich das Problem, dass der Controller scheinbar gelegentlich einen Reset macht. Nachdem ich bereits den Verdacht hatte, habe ich einen Breakpoint am Anfang des Codes erstellt und konnte damit tatsächlich den Reset nachweisen. Der Reset-Pin ist mit 47k an VCC und 1nF an GND angebunden.

Meine Vermutung ist, dass ich den Flash-Speicher überschreite. CCS zeigt mir an, dass 79% genutzt werden. Aber das ist ja nur ein statischer Wert. Im Worst Case kann es ja auch mehr werden. Hat jemand eine Idee, wie ich herausfinden kann, ob das das Problem ist? Gibt es da eventuell einen Interrupt oder bietet CCS da irgend eine Funktion, um das zu prüfen?

Vielen Dank, Grüße Andreas

#7718941
Lesenswert?

Andreas S. schrieb:

Nachdem ich bereits den Verdacht hatte, habe ich einen Breakpoint am Anfang des Codes erstellt und konnte damit tatsächlich den Reset nachweisen.

Nö, Du hast damit nur festgestellt, daß der Programmcounter in den Resetvektor läuft. Ob ein Reset erfolgte kannst Du nur mit den Flags für den Resetgrund feststellen.

Z.B. beim AVR-GCC läuft jeder Interrupt in den Resetvektor, für den kein Handler aufgesetzt wurde.

#7720314
Lesenswert?

Hannes J. schrieb:

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/746272/faq-handling-msp430-system-reset-events

When a reset occurs, the cause of the event it logged by the MSP430 CPU’s System peripheral (SYS).

Hallo Hannes, vielen Dank für deinen Tipp. Wäre zu schön gewesen, wenn ich damit weiter gekommen wäre. Allerdings besitzt die MSP430F2xx, MSP430G2xx Family dieses Feature und somit auch das SYSRSTIV Register nicht.

Ersatzweise bin ich dann über die (Non)-Maskable Interrupts (NMI) gegangen und habe herausgefunden, dass der Reset scheinbar durch eine Flash Access Violation (ACCVIFG) ausgelöst wird. Jetzt muss ich nur noch herausfinden, wie ich das behebe. Vielen Dank für eure Hilfe!

Grüße Andy

P.S.: Vergrößerung des Stacks hat das Problem nicht gelöst :-(

#7720387
Lesenswert?

Nochmal kurz zum genaueren Verständnis. Ich lasse das Programm die ganze Zeit im Debugger laufen. Allerdings hatte ich das Problem, dass sich der Controller gelegentlich aufgehangen hat. Habe dann durch das Debugging herausgefunden, dass der Controller zwischendurch ungeplant zum Anfang der main() springt. Wenn er das tut, während er gerade mit anderen Komponenten kommuniziert, hängt er sich auf. Das er sich aufhängt, konnte ich fixen. Aber die Sprünge zum Anfang der main() sind weiter vorhanden. Ich habe die Sprünge als Reset interpretiert. Nun habe ich folgende ISR hinzugefügt

1
#pragma vector=NMI_VECTOR
2
__interrupt void NMI_ISR_HOOK(void)
3
{
4
    if (IFG1 & WDTIFG)
5
    {
6
        //while(1);   // Watchdog timer+ interrupt flag
7
    }
8
    else if (IFG1 & OFIFG)
9
    {
10
        while(1);   // Oscillator fault interrupt
11
    }
12
    else if (IFG1 & NMIIFG)
13
    {
14
        while(1);   // NMI interrupt flag
15
    }
16
    else if (FCTL3 & ACCVIFG)
17
    {
18
        while(1);   <- hier bleibt er haengen
19
    }
20
}

Im Debugger kann ich nun sehen, dass er in die while-Schleife (Zeile 18) springt. Daraus schließe ich: Es tritt ein Flash-Zugriffs Fehler auf, der laut Datenblatt automatisch zu einem Reset führt.

Auszug aus Datenblatt: A (non)-maskable NMI interrupt can be generated by three sources: • An edge on the RST/NMI pin when configured in NMI mode • An oscillator fault occurs • An access violation to the flash memory

Sehe ich das soweit richtig?

#7720416
Lesenswert?

Andreas S. schrieb:

habe herausgefunden, dass der Reset scheinbar durch eine Flash Access Violation (ACCVIFG) ausgelöst wird. Jetzt muss ich nur noch herausfinden, wie ich das behebe.

ACCVIFG wird gesetzt, wenn du zum falschen Zeitpunkt (während der Flash geschrieben oder gelöscht wird, siehe Tabelle 7-3) auf den Flash zugreifst.

Ich vermute mal, dass sich dein Code sich nicht an die Vorgaben in Kapitel 7.3.2/7.3.3 hält.

#7720423
Lesenswert?

Clemens L. schrieb:

Andreas S. schrieb:

habe herausgefunden, dass der Reset scheinbar durch eine Flash Access Violation (ACCVIFG) ausgelöst wird. Jetzt muss ich nur noch herausfinden, wie ich das behebe.

ACCVIFG wird gesetzt, wenn du zum falschen Zeitpunkt (während der Flash geschrieben oder gelöscht wird, siehe Tabelle 7-3) auf den Flash zugreifst.

Ich vermute mal, dass sich dein Code sich nicht an die Vorgaben in Kapitel 7.3.2/7.3.3 hält.

Hallo Clemens, ja, das wird es sein, denke ich. Allerdings weiß ich noch nicht, wie ich das Problem beheben soll. Ich kann doch nicht jedes Mal vor dem Zugriff das Busy-Bit prüfen :-O

#7720440
Lesenswert?

Harald K. schrieb:

Andreas S. schrieb:

Ich kann doch nicht jedes Mal vor dem Zugriff das Busy-Bit prüfen

Dein Programm schreibt im Flash herum? Wirklich?

Anscheinend, aber ich mach das nicht bewusst. Ich arbeite eigentlich nur mit den Variablen, SPI, I2C, Timer und ADC. Das dürfte sich ja eigentlich alles im RAM abspielen oder? Aber irgendwie scheint es ja zur Flash Access Violation zu kommen :-(

#7720531
Lesenswert?

Jens G. schrieb:

Andreas S. schrieb:

Ich kann doch nicht jedes Mal vor dem Zugriff das Busy-Bit prüfen :-O

Merkwürdige Ansicht. Du kannst natürlich alternativ pauschal x ms abwarten vor dem nächsten Zugriff. Aber egal wie Du das machst - abwarten mußt Du die Busy-Phase ...

Wenn ich bewusst auf den Flash zugreifen würde, würde ich das Busy-Bit natürlich abfragen. Aber ich greife ja eigentlich immer nur auf Variablen zu und da kann ich ja nicht jedes Mal vorher das Busy-Bit abfragen. Muss ja auch eigentlich nicht, da ich da ja nur auf den RAM zugreife.

Sry, arbeite schon einige Weile mit dem Controller, habe aber noch nie explizit auf den Flash zugegriffen. Ich hatte bisher auch noch nie solch ein Problem. Daher bin ich etwas unwissend in dem Bereich.

Ich flashe den Controller übrigens mit dem MSP-FET, also kein Bootloader.

#7720569
Lesenswert?

Andreas S. schrieb:

Meine Vermutung ist, dass ich den Flash-Speicher überschreite.

Das wird es wohl eher nicht sein. Das Teil hat lt. DaBla einen Watchdog, den Du hoffentlich abgeschalten hast oder immer rechtzeitig zurücksetzt. Für den Fall, das Du den immer zurücksetzt, könnte es sein, Wenn Du noch was dazu gebastelt hast, daß Du das nicht mehr rechtzeitig schaffst. Dann läuft der nämlich über und startet den Controller einfach neu.

Das nur mal so als Gedankenanstoß.

#7720600
Lesenswert?

Der Flash Int löst glaube ich ebenfalls aus wenn manche key Register falsch/nicht beschrieben werden (Register die man mit einer bestimmten Sequenz beschreiben muss um irgendwelche anderen Register zu ändern). Oder zb wenn du auf nicht existenten Speicher zugreifst. Also zb von einem NULL Pointer lesen. Zu überprüfen wäre ob es nicht initialisierte Pointer gibt oder ob irgendwo Stellen existieren welche durch zweifachen Zugriff (Interrupts) korrumpiert werden. Generell würde ich als erstes empfehlen den Users Guide nach diesem Interrupt zu durchsuchen und die Möglichen Ursachen alle auflisten.

#7720635
Lesenswert?

Harald K. schrieb:

Wenn Du im Debugger siehst, daß der NMI wegen des "Flash-Fehlers" ausgelöst wurde, kannst Du Dir natürlich auch den Stack ansehen, und so herausfinden, welche Funktion gerade aktiv war, als der Interrupt ausgelöst wurde.

Das sollte eigentlich schon einen gewissen Hinweis geben.

Das ist eine gute Idee. Ich habe den Debugger so noch nie genutzt. Werde ich morgen aber mal versuchen. Wenn ich die verursachende Funktion so ermitteln kann, wäre ich einen großen Schritt weiter.

Grüße Andreas

#7720876
Lesenswert?

Folgende neue Erkenntnisse:

Andreas S. schrieb:

Daraus schließe ich: Es tritt ein Flash-Zugriffs Fehler auf, der laut Datenblatt automatisch zu einem Reset führt.

Diese Aussage muss ich zurücknehmen, fürchte ich. Zumindestens weiß ich nicht, wo ich das im Datenblatt gelesen haben soll. Lediglich die "A Flash memory security key violation" führt zu einem PUC/Reset. Dennoch kommt es bei mir zu NMIs mit Flash Access Violation (ACCVIFG), gefolgt von einem Reset. Jetzt überlege ich doch wieder, ob ich einen Stack-Überlauf habe, der aus irgend einem Grund auch das ACCVIFG setzt.

Im angehängten Bild sieht man einen Screenshot vom Debugger. Damit ich nichts falsch verstehe, oben links (rot markiert) sehe ich den Stack? Da kann ich leider keine Schlüsse draus ziehen. Im Stack Usage unten links sehe ich, dass der Stack meiner main() anscheinend 184 Byte groß werden kann?! Die Adressen im Stack sind 2 Byte lang/groß. Also werden im Worst case 92 Funktionen verschachtelt aufgerufen :-O. Ich habe im Linker nur 144 Byte angegeben. Das hat bereits zur Folge, dass mein RAM zu 88% ausgelastet ist. Bei 184 Byte Stack size hätte ich 96% RAM auslastung, was wahrscheinlich zu anderen Fehlern führen würde.

Gibt es eine Möglichkeit, wie ich einen Stack-Überlauf eindeutig identifizieren kann? Im Internet habe ich dieses Video gefunden: https://youtu.be/edHHRf0v7Gk?feature=shared Allerdings gibt es bei mir nur die Optionen Breakpoint, Hardware Breakpoint und Watchpoint. Hat jemand eine Idee, warum ich die anderen Optionen nicht habe?

Grüße Andreas

Angehängte Dateien:
#7723849
Lesenswert?

Auch wenn ich mich noch nicht an die Assemblerbefehle getraut habe, konnte ich durch diesen Fehler doch wieder einiges Neues lernen :-)

Ich habe dank dieses Threads nun endlich mit Gewissheit den Stack Überlauf nachweisen können: https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/396854/detect-stack-overflow

Jetzt, wo der Fehler eindeutig nachgewiesen ist, kann ich mich an die Fehlerbehebung setzen und mich mit Code-Optimierung beschäftigen.

Vielen Dank für eure Unterstützung.

Grüße Andreas

#7724311
Lesenswert?

Andreas S. schrieb:

mich mit Code-Optimierung beschäftigen.

Man darf auf einem kleinen µC nicht so verschwenderisch den RAM nach dem Gießkannenprinzip verteilen, wie auf einem PC. Man sollte also schon ermitteln, welche maximale Größe ein Array wirklich benötigt. Und jedesmal hübsch testen, ob die Größe noch ausreicht, d.h. nicht blind auf einen Pointer schreiben. Und man darf auf einem 16-Bitter auch 8-Bit Variablen verwenden, um RAM zu sparen.

Kritisch kann es werden, wenn man malloc verwendet, da dafür ein fester RAM-Bereich reserviert werden muß. Es kann dann passieren, daß zwar ausreichend gesamter RAM verfügbar ist, aber im falschen Segment verteilt.

Ich hab mir für den AVR ein kleines Stacktestprogramm geschrieben, das den Bereich zwischen statischen Daten und Stackpointer prüft, ob da noch das Testpattern (0x77) drinsteht, bzw. ihn damit füllt. Es gibt den verfügbaren und den genutzten Stack zwischen 2 Aufrufen aus. Kleiner 16 Bytes Reserve würde ich als kritisch ansehen, größer 256 Bytes sollten ausreichen.

#7725111
Lesenswert?

Hallo Peter, vielen Dank für deine Tipps!

Peter D. schrieb:

Man sollte also schon ermitteln, welche maximale Größe ein Array wirklich benötigt.

Das mache ich selbstverständlich immer!

Peter D. schrieb:

Und man darf auf einem 16-Bitter auch 8-Bit Variablen verwenden, um RAM zu sparen.

Mache ich ausschließlich, abgesehen von Variablen, die größer sein müssen.

Peter D. schrieb:

Kritisch kann es werden, wenn man malloc verwendet, da dafür ein fester RAM-Bereich reserviert werden muß. Es kann dann passieren, daß zwar ausreichend gesamter RAM verfügbar ist, aber im falschen Segment verteilt.

Mit malloc arbeite ich auf Mikrocontrollern eigentlich gar nicht mehr. Eigentlich weiß ich auch immer genau, wie groß meine Variablen sein müssen.

Peter D. schrieb:

Ich hab mir für den AVR ein kleines Stacktestprogramm geschrieben, das den Bereich zwischen statischen Daten und Stackpointer prüft, ob da noch das Testpattern (0x77) drinsteht, bzw. ihn damit füllt.

So habe ich es jetzt auch gemacht.

Peter D. schrieb:

Kleiner 16 Bytes Reserve würde ich als kritisch ansehen, größer 256 Bytes sollten ausreichen.

Auch wenn du wahrscheinlich mehr Ahnung hast als ich, würde ich dem so nicht zustimmen. Mein MSP430 hat nur 512 Byte RAM. Da habe ich gar nicht die Möglichkeit nur annähernd 256 Byte Reserve einzuplanen.

Ich habe nun nach der Code-Optimierung 24 Byte reserve und es läuft jetzt zuverlässig (Die Standardeinstellung im Linker ist beim MSP430 in CCS übrigens auch nur insgesamt 80 Byte und ich habe nun auf 128 erweitert). Ich komme somit auf eine allgemeine RAM-Reserve von 150 Byte.

Grüße Andreas

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren