Hallo Leute!
Wir sind MSP430-Anfänger und haben nun vor, Daten ins Flash zu schreiben
um sie auch nach einem PowerOff noch lesen zu können.
Wir haben nun eine raffinierte Routine entwickelt. Wir nutzen die
Main-Routine nur, um alle Variablen zu initialisieren und schicken den
Prozessor dann mit einem NOP in den Tiefschlaf.
Der eigentliche Funktionsteil unserer Schaltung wird durch eine
Interrupt-Routine ausgelöst. Und zwar auf Basis eines Timers, dem Timer
TA0. Dieser ist so programmiert, dass er alle 0.0125 Hz einen Interrupt
auslöst und dann eine von uns programmierte Interrupt-Routine abfährt.
Somit ist gewiss, dass der Prozessor zwischen den Interrupts immer schön
stromsparend einschläft und nur durch den Interrupt aufwacht.
Beim Beackern des User-Guides steht aber wohl fest, dass es für einen
Schreib- bzw. Löschvorgang eines Flash-Segmentes vonnöten ist, jegliche
Interruptausführungen am Prozessor zu stoppen, dann den Flash-Vorgang
auszuführen und dann gerne die Interrupts wieder einzuschalten.
Das Problem ist nun, dass wir, um in den Flash-Speicher schreiben und
lesen zu können (s.o.), die Interrupts generell eben nicht aus einem
Interrupt heraus deaktivieren können. Wie machen wir es nun aber, wenn
wie in unserem Falle die Main-Routine mit einem no_operation einschläft
und alle Funktionalitäten des Programms aus dem Timer-Interrupt kommen?
Können wir dann gar nicht auf den Flash schreiben/löschen/zugreifen?
Es wäre echt bitter, alles wieder in eine Main-Schleife umzumodeln.
Zudem läuft der Prozessor dann immer und schläft nie ein ...
Was tun?
Lieben Dank,
Matthias
Hm, also irgendwie ist das alles bissl unklar. Der MSP430 wird doch
nicht durch ein NOP in den Sleep geschickt sondern z.B. durch die Markos
_BIS_SR(LPM1_bits + GIE) usw.
Um den Flash zu beschreiben, kannst du sowieso nicht im LPM sein, denn
du brauchst für den Flash Controller einen Takt, der üblicherweise vom
SMCLK kommt (muss ja mindestens 450kHz oder sowas sein).
Alles in einer Timer-ISR abzuarbeiten ist eh schlechter
Programmier-Stil. Normalerweise setzt man in der ISR ein Flag, welches
die Main-Schleife veranlasst, eine gewisse Funktion anzuspringen und
abzuarbeiten. Am Ende der ISR muss dann das Wakup-Makro sein, damit der
Prozessor nach dem Interruptm noch wach ist. Anschließen wird das
Unterprogramm abgearbeitet, das Flag wieder gelöscht und wenn keine
Aufgaben mehr anstehen, der Prozessor wieder in den LPM geschickt. Das
ist ganz einfach und effektiv.
Natürlich kannst du auch in der ISR den Flash beschreiben, wenn du in
der ISR bist, ist ja auch alles aktiv, und die Interrupts erst mal aus.
Da kannst du doch deine Daten schreiben.
Hallo Christian!
Lieben Dank für Deine Antwort.
Unsere Main-Routine hat als letztes Kommando, nachdem wir den _EINT();
ausgeführt haben, __no_operation();. Dann hält der Prozessor doch an und
schläft ohne Aktion ein, oder? Der Watchdog ist aus. Als Clock nehmen
wir den internen DCO mit dem Grundtakt (glaube 800 kHz waren das). Der
MSP430 hat also in unserer Anwendung keinerlei externe Quarze oder
sowas.
Das einzige, was ihn aufweckt ist dann der Timer A0, den wir so
konfiguriert haben, dass er unsere eine Interrupt-Routine abfährt. Und
da ist der eigentliche Teil der auszuführenden Aktionen (ist blos das
Setzen einiger IOs). Der Timer bildet sich den Aufweckzeitpunkt aus dem
MCLK mit Teiler 10 und löst dann einen Interrupt aus. So kommt die Zeit
von 0.0125 sec pro Interrupt zustande. Wir haben bis jetzt auch nur
diesen einen Interrupt. Sonst keinen weiteren. Eventuell kommt noch
einmal einer für den ADC dazu, aber die Frage ist, ob ich das per
Interrupt machen wollte. Wohl eher nicht.
Wir nutzen den Controller blos als Ausführelement. Er soll also auf
verschiedene IOs als Eingänge geschaltet mit bestimmten Funktionen
reagieren und andere IOs als Ausgänge schalten. Mehr nicht. Dafür ist er
eh etwas oversized, aber die Tools und das Können sind beim MSP430
einfach genial.
Du meinst also, wir sollen einfach den Flash-Vorgang aus der
Interrupt-Routine heraus ausführen?
Lieben Dank noch einmal für Deine Antwort. Wir lernen ja noch ;-)))
Gruß,
Matthias
Also der NOP Befehl stoppt den Prozessor keineswegs. Da wird nur einfach
1 Prozessorzyklus lang nix gemacht, und dann gehts mit dem nächsten
Befehl weiter. NOP ist ein völlig normaler Befehl, nur dass es eben
keine Interaktion stattfindet. Wenn du in einen LPM willst, musst du die
entsprechenden Bits im Statusregister setzen. Das geht am einfachsten
über die Makros, siehe oben. Schau dir mal die Code-Beispiele bei TI an.
Hallo Christian!
Unsere Main-Routine hat keine Endlosschleife. Der letzte Befehl ist ein
NOP, aber danach kommt nichts mehr. Den NOP selbst könnten wir dann nach
unserem Main-Konstrukt wohl weglassen, oder? Was passiert am Ende der
Main-Routine mit dem Prozessor? Tut er dann einfach nichts mehr? Was
passiert bezüglich der Stromsparmodis?
Aber zurück zum Problem:
Im User's Guide steht, dass mit den Interrupts das Problem ist, dass der
Flash-Controller den Opcode 03FFFh (JMP PC) dem Prozessor aufprägt,
solange eine Flash-Operation läuft. Würde also in dieser Zeit ein
Interrupt ausgelöst, ginge als Sprung-Adresse 03FFFh auf den
Interrupt-Stack, was den Prozessor nach Beenden des Flash-Vorganges JMP
PC ausführen ließe aber sicher nicht die ISR, die wir ja brauchen.
Ist es also statthaft, dem Timer den Interrupt einfach aus der ISR
selbst heraus solange zu deaktivieren, wie geflasht wird und dann
einfach danach den Interrupt auf den Timer wieder einzuschalten?
Dann würde ja, falls der Flash-Vorgang länger als ein Timer-Intervall
dauerte, zwar der Timer entsprechend unseren Einstellungen nach wie vor
überlaufen, hierdurch aber kein Interrupt ausgelöst ...
Nach dem Flashen wäre dann wieder alles normal ...
Liebe Grüße,
Matthias
Also wenn du keine Endlosschleife in der Main hast, ist das sehr
gefährlich, denn der Prozessor läuft dann irgendwo hin. Eventuell hat
der Kompiler eine wie auch immer geartete Exit-Geschichte eingebaut,
aber darauf kann man sich nicht verlassen. Wo lernt man denn sowas zu
programmieren? Bau mal eine Endlosschleife ein, die den Prozessor in den
LPM schickt.
Zum Interrupt: Sobald eine ISR betreten wird, werden alle Interrupts
deaktiviert. Es sei denn, du gibts bei der ISR-Deklaration
ausdrücklich an, dass die Interrupts wieder aktiviert werden sollen
(nested interrupt). Das sollte man aber tunlichst nur dann machen, wenn
man ganz *ganau* weiß, was man programmiert. Also ihr solltet das auf
keinen Fall machen.
Du kannst also den Flash in der Timer-ISR beschreiben, da das GIE-Bit
sowieso aus ist, und keinerlei andere Interrupts dazwischen kommen
können.
Im Anhang ein PDF von TI, wie man das ordentlich macht.
Ach übrigens: Willst du alle 0,0125 Sekunden den Flash neu beschreiben?
Das wird der nicht lange mit machen....
Hallo Christian!
Nein, ich will nicht alle 0.0125 sec den Flash neu beschreiben.
Das mit den Interrupts habe ich auch verstanden. Hmm, ich weiß gerade
nicht ob der Timer A, der bei uns alle 0.0125 sec einen Interrupt
auslöst, damit aufhört, solange wir uns in der ISR dazu befinden. Weil
dann würde ja, würde die Abarbeitung der ISR länger als 0.0125 sec
dauern der Stack vom Interrupt ins Nirvana laufen weil pro ISR ein neuer
Interrupt dazukäme. Ich denke nicht, dass die Abarbeitung unser kleinen
ISR länger dauert, also keinesfalls, denn es läuft aktuell. Aber beim
Flashen bin ich mir nicht sicher. Zur Not schalte ich den Interrupt per
setzen des entsprechenden Status-Bits für den Timer einfach manuell ab,
sobald ich flashe und danach wieder an. Wir werden sehen!
Zum Main:
Nunja, habe einfach ein paar Code-Exemplare eines Bekannten beackert.
Insofern ist meine Erfahrung gering. Der Compiler muss dann eine
Exit-Geschichte hineinbauen, denn ein Prototyp läuft seit 2 Wochen
dauernd ohne Absturz durch!
Ich werde aber einmal eine While-1-Schleife hinten anbauen und mir die
LPMs mal ansehen.
Lieben Dank erst einmal!
Viele Grüße,
Matthias
Matthias Pollack schrieb:
> Das mit den Interrupts habe ich auch verstanden. Hmm, ich weiß gerade> nicht ob der Timer A, der bei uns alle 0.0125 sec einen Interrupt> auslöst, damit aufhört, solange wir uns in der ISR dazu befinden. Weil> dann würde ja, würde die Abarbeitung der ISR länger als 0.0125 sec> dauern der Stack vom Interrupt ins Nirvana laufen weil pro ISR ein neuer> Interrupt dazukäme.
Wie gesagt, solange du den Interrupt nicht explizit in der ISR wieder
einschaltest ist der aus, und jeder weitere Interrupt wird ignoriert,
solange die ISR dauert. Also läuft da überhaupt nix über. Außerdem hat
der MSP430 keinen direkten Stack, sondern der geht vom oberen Ende des
RAM los, bis halt die Variablen kommen. Da ist genug Platz, wenn man
nicht alles voll mit Variablen gehauen hat.