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?
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.
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 :-(
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
__interruptvoidNMI_ISR_HOOK(void)
3
{
4
if(IFG1&WDTIFG)
5
{
6
//while(1); // Watchdog timer+ interrupt flag
7
}
8
elseif(IFG1&OFIFG)
9
{
10
while(1);// Oscillator fault interrupt
11
}
12
elseif(IFG1&NMIIFG)
13
{
14
while(1);// NMI interrupt flag
15
}
16
elseif(FCTL3&ACCVIFG)
17
{
18
while(1);<-hierbleibterhaengen
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
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.
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
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 :-(
Hmm. Verwendest Du einen Bootloader oder irgendsoetwas? Denn irgendwo muss ja der Code herkommen, der versucht, das Flash zu beschreiben (oder auf welche Art und Weise auch immer darauf zuzugreifen, daß es zur Zugriffsverletzung kommt).
Einfaches Lesen sorgt natürlich nicht für so etwas.
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 ...
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.
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.
Wenn Du nicht drauf zugreifst, dann ist das ja auch klar. Aber das war vorhin eben noch nicht klar ...
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.
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.
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.
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.
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?
Allerdings besitzt die MSP430F2xx,
MSP430G2xx Family dieses Feature und somit auch das SYSRSTIV Register
nicht.
Dann schau eben ins Register IFG1:
• PORIFG and RSTIFG flags have been added to IFG1 to indicate the cause of a reset.
• An instruction fetch from the address range 0x0000 - 0x01FF will reset the device
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.
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.
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.
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.