Hallo alle zusammen,
ich bin gerade dabei eine kleine Firmware mit IAR zu entwickeln.
Des Öfteren kommt es vor, dass sich der MSP beim Starten des
Debugvorgangs in einer Endlosschleife aufhängt, die mir jedoch völlig
unbekannt ist.
Ein Screenshot vom Disassembly-Fenster von IAR habe ich als Anlage
beigefügt. Die Endlosschleife geht von bereits markierten Startadresse
0x4378 bis zum Befehl "jne" auf der Adresse 0x4380.
Könnt ihr mir sagen, wass hier passiert und für was das gut ist?
Danke für eure Hilfe!
Gruß
Jochen
Das ist ein Teil des C-Startupcodes vor dem Aufruf von main(). An dieser
Stelle wird der Datenbereich inititalisiert und zwar wohl ausgenullt
(memzero).
Vielleicht stimmt die Speichergröße des eingestellten Targets nicht und
die Funktion hat bei den Registern (R15,R12) einen 16-Bit
Integeroverflow.
002796 531C inc.w R12
002798 9F0C cmp.w R15,R12
Bei einem Target mit mehr als 64KB RAM ist dieser Code IMHO
problematisch.
Nachsehen würde ich in der IAR Doku zur sog. _low_level_init Funktion,
im Startupcode/Linkerkontrollskript (wenn es das beim IAR gibt) und in
den Projekteinstellungen.
Der Codeabschnitt befindet sich eventuell direkt hinter dem Aufruf von
main() und dem anschliessenden exit() (vgl.
http://bbs.lierda.com/archive/index.php/t-21935.html). Da würde ich
prüfen, ob das Programm vom call exit zurückkommt und mit
uninitialierten Argumenten in die problematische Funktion durchfällt.
Hallo Stefan,
deine Antwort und die geposteten Links hörten sich vielversprechend an.
Ich habe Stellenweise einige große Arrays (x mal 256 Byte), aber die
meisten haben feste Werte und da wirkt "__no_init" nicht. Bei denen, wo
es möglich ist habe ich den Präprozessorbefehl hinzugefügt. Das Ergebnis
ist dennoch das gleiche. Fakt ist aber, dass das Ausschalten den
Watchdogs funktioniert, denn die __low_level_init-Funktion, in der der
Watchdog deaktiviert, wird wirklich als Erstes ausgeführt. Die
Funktionsbeschreibung enthält auch den markanten Satz:
1
IAR-standard function will be executed prior to initializing memory space
Deine RAM Initialisierung dauert laenger als die Timeoutzeit des
Watchdogs.
Daher in deiner Intialisierungsroutine schlaegt der Watchdog zu und das
Spiel beginnt von neuen. Wie du schon richtig erkannt hast muss du den
im Startupcode abschalten und erst nach der Initialisierung wieder
einschalten.
Das beinhaltet allerdings eine kurze Zeit wo kein Watchdog das System
ueberwacht. Besser ist es in der Initialisierungsroutine fuer das RAM
den Watchdog regelmaessig zu bedienen.
Genau dagegen ist ja die _low_level_init Funktion. Interessant wäre mal
im Debugger zu schauen, ob der WDT wirklich aus ist und/oder ab das Flag
für den WDT Reset gesetzt ist, also ob der WDT da wirklich reinspuckt.
Kann ja auch was ganz anderes sein.
Dafuer gibt es einen einfachen Test.
Wenn man die Anzahl der Variablen mal kleiner macht ist diese
Initialisierungsroutine auch schneller fertig. Und dann sollte der WD
auch nicht ausloessen.
Ich hatte mal das gleiche Problem. Irgendwann startete das Programm
nicht mehr nachdem ich noch etwas mehr RAM brauchte. Der Fehler war
anschliessend das die Initroutine mehr Zeit brauchte als der WD einem
lies.
Ja, ist oben in den Links genannt, Stichwort __no_init Kennzeichnung der
Variablen.
Aber wenn der Watchdog das Problem ist (was noch zu testen oder anhand
des Startupcodes zu kontrollieren wäre):
Den müsste man doch auch früher im Startupcode ausschalten können bzw.
zunächst auslassen können und erst nach der Initialisierung z.B. am
Anfang von main() anstellen können.
Hast du mal einen Debuggerlauf ohne Watchdog gemacht oder kann man das
bei dem MSP430 nicht?
Jochen schrieb:> Was bringt mir das Variablen zu entfernen, wenn ich sie doch für meine> Anwendung benötige ... !?
Du sollst es ja auch nur mal testen ob es daran liegt.
Im C Startup wird doch die Routine __data16_memzero aufgerufen.
Die bekommt doch vorher ihre Laenge und Startadresse mitgeteilt.
Die must du halt nur aufsplitten in 2 oder 3 Teile und dazwischen einmal
den WD betaetigen.
Stefan B. schrieb:> Den müsste man doch auch früher im Startupcode ausschalten können bzw.> zunächst auslassen können und erst nach der Initialisierung z.B. am> Anfang von main() anstellen können.
Kann man machen nur hast du dann ein Stelle am Anfang die nicht
ueberwacht wird. Sollte jetzt eine Stoerung auftreten und der WD
ausloesen und direkt danach im Startupcode nochmal ausloesen dann hast
du ein Problem ...
Hallo!
Ehrlich gesagt (und peinlicher Weise) verstehe ich nun immer weniger
statt mehr.
Stefan B. schrieb:> Ja, ist oben in den Links genannt, Stichwort __no_init Kennzeichnung der>> Variablen.
Das ist mir bekannt, mach ich ja auch schon stellenweise. Meine Frage
war aber nach einem "Globalen Flag", dass ich nur einmal setzen muss und
alle Variablen werden nicht initialisert.
Stefan B. schrieb:> Den müsste man doch auch früher im Startupcode ausschalten können bzw.>> zunächst auslassen können und erst nach der Initialisierung z.B. am>> Anfang von main() anstellen können.
Früher als in der __low_level_init-Funktion (LLI)? Inzwischen
deaktiviere ich den Watchdog sowohl in der LLI-, als auch in meiner
main-Funktion.
Helmut Lenzen schrieb:> Im C Startup wird doch die Routine __data16_memzero aufgerufen.>> Die bekommt doch vorher ihre Laenge und Startadresse mitgeteilt.>> Die must du halt nur aufsplitten in 2 oder 3 Teile und dazwischen einmal> den WD betaetigen.
Wie soll ich das bitte machen? An den generierten Code komme ich doch
gar nicht ran ... Entwickle in C und nicht Assembler.
Viele Grüße
Jochen
Jochen schrieb:> Wie soll ich das bitte machen? An den generierten Code komme ich doch> gar nicht ran ... Entwickle in C und nicht Assembler.
Und ob du daran kommst.
Die Datei heist "cstartup.s43" und ist Bestandteil der IAR Library.
Suche mal in deinem IAR Ordner nach dieser Datei.
Liegt meistens in ... SRC/LIB/430.
Bei allen C Compiler die ich kenne ist der Startupcode immer dabei
gewesen.
Muss er ja auch sonst kann man mit dem Compiler nicht allzu viel
anfangen.
PS. Auch ein C Programmierer muss ab und zu mal etwas Assembler
programmieren. Und wenn es nur darum geht den Startupcode zu
modifizieren.
Anderes Problem:
Da ich ja mit IAR nicht vorangekommen bin, habe ich jetzt mal das Ti
Code Composer Studio ausprobiert. Ergebnis:
Wie auch bei IAR ist der WDT deaktiviert, ABER er löst trotzdem aus!
Wann bzw. welchen Code er dabei gerade ausführt kann ich jedoch nicht
einsehen!
Helmut Lenzen schrieb:> PS. Auch ein C Programmierer muss ab und zu mal etwas Assembler> programmieren. Und wenn es nur darum geht den Startupcode zu> modifizieren.
Gestehe: Hab schon seit Uni-Zeiten nichts mehr mit Assembler gemacht und
das ist nun über 10 Jahre her! Mir wird das modifizieren des
Startupcodes entsprechend schwer fallen.
Ok, das Problem in Eclipse habe ich gefunden.
Hab vergessen eine Callback-Funktion mit 0 zu initialisieren (muss ich
ja in CCS nun manuell machen). Da stand dann ein Zufallswert drin und
meine Funktion prüft auf != 0 ab. Dadurch ist dann ein Sprung ins
Nirvana erfolgt.
Im Momment läuft also mein Code unter CCS. ;)
Suche mal in dem CSTARTUP diese Stelle
PUBLIC ?cstart_begin
?cstart_begin:
Und trage das dort ein
#define WDTPW (0x5A00)
#define WDTHOLD (0x0080)
#define WDTCTL (0x0120)
#define WDTSSEL (0x0004)
Dann suche diese Stelle
?cstart_init_zero:
MOV #SFB DATA16_Z, CW0
MOV #1024, CW1
MOV #WDTPW + WDTHOLD + WDTSSEL, &WDTCTL
XCALL #__data16_memzero
MOV #SFB DATA16_Z+1024, CW0
MOV #1024, CW1
MOV #WDTPW + WDTHOLD + WDTSSEL, &WDTCTL
XCALL #__data16_memzero
MOV #SFB DATA16_Z+2048, CW0
MOV #1024, CW1
MOV #WDTPW + WDTHOLD + WDTSSEL, &WDTCTL
XCALL #__data16_memzero
MOV #SFB DATA16_Z+3072, CW0
MOV #1024, CW1
MOV #WDTPW + WDTHOLD + WDTSSEL, &WDTCTL
XCALL #__data16_memzero
Und aendere dort den Code
Ich initialsiere dann das RAM (4096 Byte) in 1024 Byte grossen
Haeppchen.
Dazwischen wird der schlafende Hund wachgeruettelt
PS. Ist noch nicht von mir getestet.
Versuch es infach mal.