Servus,
Ich sitze gerade an einem größeren Projekt für den MSP430F169 und bin
auf ein Problem gestoßen:
Ich muss (Und ich hab mir das echt lange überlegt; Polling in main ist
nicht drin!) aus einer Port-Interrupt-Funktion an eine bestimmte Stelle
in meinem Main-Programm springen.
Ich habe das jetzt über einen Inline-Asembler-Code gelöst, welcher den
PC manipuliert, um so gezielt die entsprechende Zeile erreichen zu
können.
Das Verfahren klappt auch perfekt. Aber leider nur ein einziges mal!!!
Danach wird der Interrupt gar nicht mehr ausgelöst, auch wenn der IE
noch aktiv ist und ich alle Flags vorher gelöscht habe.
Da ich Assembler nie gelernt habe: Weiß jemand, woher das kommen könnte?
Hängt das mit meiner frechen Manipulation der Core-Register zusammen?
Für eine Antwort wäre ich echt dankbar!!!
Markus
Markus schrieb:> aus einer Port-Interrupt-Funktion an eine bestimmte Stelle> in meinem Main-Programm springen.
Böser Fauxpas. Auch dann, wenn man von Assembler Ahnung hat. So
programmiert man nicht.
Polling/Abfragen von Status-Bits ist leider nicht möglich :(
Deshalb bin ich ja auf diese verquere Lösung gekommen!
Der Interrupt soll zu einem "kontrollierten Reset" führen und eine
Stelle in main anfahren ohne einen wirklichen Hardware-Rest zu benutzen,
das Variablen erhalten bleiben müssen!
Das was du vorhast, setzt beinahe voraus, dass du Compiler und Library
selbst geschrieben hast. Weil du ganz genau wissen musst, was beide in
allen Lebenslagen tun.
Da dies offensichlich nicht der Fall ist, kann ich nur die dringende
Empfehlung abgeben, dieses Konzept komplett in die Tonne zu kippen.
Wenn bestimmte Variablen einen Reset überleben sollen, dann gibt es
evtl. Möglichkeiten, sie entsprechend zu deklarieren oder den sie
initialisierenden Startup-Code entsprechend zu modifizieren/ersetzen.
Es gibt zwar mit setjmp/longjmp antike Mechanismen für non-local gotos,
aber wenn man das in einem Interrupt-Handler macht, dann drohen trotzdem
einige Überrschungen.
Stellt sich eher die Frage, wieso Polling nicht möglich ist? Musst halt
entsprechend oft pollen, quasi nach jeder Funktion in der Main-Schleife
das Bit, was die ISR setzt, überprüfen.
Polling ist extrem schwierig bis unmöglich, da der Sprung zurück an eine
bestimmt Main-zeile aus mehreren Funktionen in mehreren C-Modulen
(Dateien) kommen können muss! Deshalb ja der gescheiterte Versuch mit
dem Inline-Assembler. Ich wollte mir tausende von if(polling) Abfragen
ersparen, zumal die Applikation sehr Timing-sensitiv ist!
Das ist alles sehr unbefriediegend!
Aber trotzdem schonmal allen danke für die Antworten!
Und falls es noch Ideen gibt: Her damit!!!
Kannst Du deine Reset-Routine 'diese Stelle in Main' nicht als Funktion
/ Unterprogramm ausführen welches von Main und auch deiner
Interruptroutine angesprungen wird ?
Gute Idee!
Aber das Problem ist nicht, dass ich eine spezifische Operation, welche
schon mal in main vorgekommen ist, nochmal ausführen will, sondern dass
das ganze Programm nochmal von vorne starten soll (Halt nur ohne das
Setup). Und dieser Sprung muss halt IMMER und von ÜBERALL möglich sein,
weil in meiner Applikation ein Reset IMMER und ÜBERALL kommen kann und
das Programm SOFORT reagieren können muss und nicht erst beim nächsten
Polling.
Dumme Sache, was?
Ich bin weiterhin für alles offen! Super Hilfsbereitschaft!!!!!!
Dann setz doch in Main alle Register (ausser PC) so wie sie beim
Hard-Reset /Power-on gesetzt werden (Sprungmarke main_2 für die
Interruptroutine). Davor main_1 welche beim Power_on angesprungen wird -
zur Initialisierung...
Klingt gut!
Hab ich aber nicht verstanden!
Wäre ein Anschauungsbeispeil möglich???
(Fehlerhaftes) Prinzip im Moment:
Variablen.....
main()
{
Initialisierung........
Assembler-Code (PC speichern)
Programm.......
}
Interrupt-Funktion
{
Assembler-Code (Ersetzte PC durch gespeicherten Wert)
}
Ergebniss: Murks!
Hi
Ergebniss: Murks!
Du hast eigentlich die ganze zeit um den heißen Brei herumgeredet z.B.
Warum muss man aus jeder Programmstelle an eine bestimmte andere
springen?
Ausser deiner Meinung, das es nicht anders geht, hast du noch keinen
triftigen Grund genannt.
>Ergebniss: Murks!
eher: Konzept Murks.
MfG Spess
Tschuldigung, ich wollte nicht gleich mit allen Details nerven!
Habs ja nur einfach halten wollen!
Mein Prozessor soll zum 1-Wire-Slave werden und eine Kommunikation mit
anderen 1-Wire Devices ermöglichen. Da diese Schnittstelle rein auf
Timing basiert und jede Flanke damit entscheidend ist, muss ich
Interrupt-Funktion für jeden Befehl nutzen können. Dies bedeutet auch,
dass mal auf einen Interrupt gewartet werden muss, zb, wenn mehr als ein
bit erwartet wird!
Nun wollte ich vermeiden, dass sich das Programm beim Verlust eines Bits
oder einer Flanke (Aus welchem grund auch immer) aufhängt. Also: Es muss
immer ein Reset möglich sein, ganz egal, wo das Programm gerade ist, ob
in main oder sonst wo!
Zufrieden?
Wenn ja, ich bin weiterhin am Suchen für eine Lösung!
MfG,
Markus
Naja, du müsstest den StackPointer auch wieder zurück stellen, denn beim
Srpung in die ISR wird der PC und das SR auf den Stack gerettet. Dann
wird sicherlich der C-Compiler auch noch einige Pushs eingebaut haben,
um seine Register zu retten. Das alles musst du wieder per pop
zurückholen. Außerdem musst du alles das abhandeln, was ein RETI
eigentlich macht. Flags löschen, GIE wieder einschalten usw. damit es
wirklich so ist, als wärest du aus der ISR wieder heraus gesprungen.
Dann könnte es klappen, obwohl es eine wirkliche Schweinerei ist die
ganze Sache. Du wolltest das Konzept nochmal überdenken, es geht
garantiert auch ohne diese Kankheit.
OK, mir ist klar geworden, dass es so nicht gehen kann!
Aber anscheinend gibt es auch keine bessere Lösung in diesem einfachen
Sinne.
Vielleicht mache ich doch einen Totalen Hardware-Reset und speichere mir
vorher die wichtigen Variablen im Flash!
Schade aber auch! Eine schnelle und korrekte Lösung für mein Problem
scheint es echt nicht zu geben!
Trotzdem allen Vielen Dank! Falls jemandem doch noch was einfällt, wäre
ich überaus dankbar, wenn er/sie es mir noch mitteilen könnte!
Gruß,
Markus
Hab's mir jetzt nicht im detail durchgelesen, aber wenn es darum geht
nach dem Reset einen Code-Teil zu überspringen, müsste das doch mit dem
Watchdog möglich sein. Wenn ich mich recht erinnere kann man doch
feststellen ob der Reset durch Power on oder Watchdog ausgelöst wurde.
Also muss man beim booten nur schauen ob's ein Watchdog war und wenn ja
den Code Teil überspringen den er nicht ausführen soll.
1-wire-Slave würd ich eher mit Timerinterrupts programmieren als über
irgendwelche Flankenerkennungen, da du ja 0 und 1 nur über
unterschiedlich lange Low-Phasen codierst, kann man ja im Timerinterrupt
den Pinstatus mitzählen, von mir aus 4 mal low = 0 und 10 mal low = 1.
dann die Zeitlich außeinanderliegenden Abtastwerte in ein Datenwort
zusammenschieben und auswerten.
Markus schrieb:> Nun wollte ich vermeiden, dass sich das Programm beim Verlust eines Bits> oder einer Flanke (Aus welchem grund auch immer) aufhängt.
Sowas geschieht ja nicht grundlos und falls man den Grund nicht als
irrelevant betrachtet, hat das den Vorteil das man ihn kennt und
vermeiden kann.
Gefühlsmäßig beruht die Fragestellung des TO auf der Unsicherheit
darüber welche Gründe es für das übersehen von Flanken gibt. Das sollte
man zuerst angehen und erst wenn man die Gründe kennt eine Abhilfe
überlegen.
Es ist IMHO besser die Ursachen anzugehen und nicht die Symptome.
A. K. schrieb:> Es gibt zwar mit setjmp/longjmp antike Mechanismen für non-local gotos,> aber wenn man das in einem Interrupt-Handler macht, dann drohen trotzdem> einige Überrschungen.
Schau in der Compiler-Doku oder im "setjmp.h" nach.
Z.B. beim AVR-GCC geht es.
Eine andere Möglichkeit ist, den Main-Code als Statemachine
(Switch/Case) aufzubauen, statt als ellenlangen Spaghetticode.
Dann brauchst Du immer nur zu Beginn des Switch das Flag abtesten.
Oder der Interrupt setzt Deine Statevariable ganz brutal auf 0 und schon
geht alles automatisch von vorne los.
Es wird maximal noch der gerade laufende State beendet.
Peter
Hier mal ein Beispiel für eine Statemachine für 1-Wire Master im
Hintergrund per Timerinterrupt auf nem 8051:
State 20, 19: Reset
State 18 .. 11: sende Byte
State 8 .. 1: lese Byte
State 0: fertig
onwi_write: Anzahl der zu sendenden Bytes
onwi_read: Anzahl der zu lesenden Bytes
Flo schrieb:> 1-wire-Slave würd ich eher mit Timerinterrupts programmieren als über> irgendwelche Flankenerkennungen, da du ja 0 und 1 nur über> unterschiedlich lange Low-Phasen codierst, kann man ja im Timerinterrupt> den Pinstatus mitzählen, von mir aus 4 mal low = 0 und 10 mal low = 1.
Schon klar, ich zähle ja auch Zeiten und keine Flanken (Nur nicht über
Timer, sondern über Delay-Cycles, die sind genauer). Nur für den Start,
also das loslassen der Timer, brauche ich die Flankendetektierung. (Und
das bei jedem Bit auf neue!)
Nobody schrieb:> Gefühlsmäßig beruht die Fragestellung des TO auf der Unsicherheit> darüber welche Gründe es für das übersehen von Flanken gibt. Das sollte> man zuerst angehen und erst wenn man die Gründe kennt eine Abhilfe> überlegen.
Es gibt dafür bei mir nur einen Grund: Hardware zu langsam.
Alles andere habe ich beseitigt!
Den Fehler kann ich im Moment nicht beheben, da Übertakten und Austausch
im Moment nicht in Frage kommen.
Aber grundsätzlich stimme ich dem Statement voll und ganz zu!!!!!
Peter Dannegger schrieb:> Hier mal ein Beispiel für eine Statemachine für 1-Wire Master im> Hintergrund per Timerinterrupt auf nem 8051:>> State 20, 19: Reset> State 18 .. 11: sende Byte> State 8 .. 1: lese Byte> State 0: fertig
Guuuuuut! Vielen Dank für den Hinweis!
Allerdings ist die sache nicht ganz so einfach:
Weiterhin gilt: Reset muss immer möglich sein und der Slave-Code
beschränkt sich nicht nur aufs andauernde lesen und schreiben, sodass
durchaus mal Flanken verloren gehen können (Siehe: Hardware zu langsam)
Das ist bei mir aber echt nur die Ausnahme. Die Sicherheit in Sachen
aufhängen muss halt nur immer gegeben sein. Und falls mal eine erste (!)
Flanke verloren geht, ist halt ohne möglichen Reset Ende!
Aber ich werde die Sache mit der Satemachine weiter verfolgen!
vielleicht lässt sich das verwerten! Danke!