Hallo,
ich möchte, dass ein Interrupt keine eigentliche ISR ausführt, sondern
an eine gewisse Stelle im Hauptprogram springt (so eine Art Teilreset).
Wenn ich jedoch direkt aus der ISR mit RJMP raus springen würde, dann
wäre ja noch die Rücksprungadresse im Stack und Globale Interrupts
deaktiviert.
Reicht folgender Code aus, um das Problem zu beheben?
1
.equ F_CPU = 4800000
2
3
.def temp = R16
4
5
.org 0x000
6
RJMP RESET
7
RJMP ISR_SMALL_RESET
8
9
RESET:
10
;Hauptinitialisierung
11
SMALL_RESET:
12
;Reset der Module
13
SEI ;Globale Inerrupts nach Reset und Small Reset erlauben
Natürlich reicht das aus. Wenn Du die Änderungen durch den
Interrupt-Einsprung rückgängig machst, woher soll der µC dann noch
wissen, daß da einer stattgefunden hat? Erst Stack reinigen, danach
Interrupts wieder aktivieren.
Ähnlich haben x86-DOS-Viren ermittelt, an welche Adresse im RAM sie
geladen wurden.
call 0
pop <adresse>
Stefan schrieb:> Wenn ich jedoch direkt aus der ISR mit RJMP raus springen würde, dann> wäre ja noch die Rücksprungadresse im Stack und Globale Interrupts> deaktiviert.
Außerdem liegt auf dem Stack noch wer weiß was alles vom Programm, das
durch den Interrupt ja irgendwo mittendrin unterbrochen wurde.
Aus einer ISR heraus direkt ins Hauptprogramm springen klingt sehr
abenteuerlich.
Ich bin mir eben nicht sicher was so ein Interrupt alles macht. Ich
weiß, dass er quasi CLI macht und natürlich in den Stack die
Rücksprungadresse schreibt.
Ob es da mehr gibt wollte ich eben erfragen.
Ein voller Reset soll nicht stattfinden, da ich werte aus dem RAM
erhalten will. Es sollen nur ein paar Module in einen definierten
Zustand übergehen und dann wieder normal die Arbeit aufnehmen.
Stefan schrieb:> Ich bin mir eben nicht sicher was so ein Interrupt alles macht. Ich> weiß, dass er quasi CLI macht und natürlich in den Stack die> Rücksprungadresse schreibt.> Ob es da mehr gibt wollte ich eben erfragen.
Der Interrupt unterbricht dein Programm irgendwo mitten während seiner
Ausführung. Kommt dein Programm wirklich in allen Fällen damit klar,
wenn an einer beliebigen Stelle mittendrin plötzlich wo anders hin
gesprungen wird?
> Ein voller Reset soll nicht stattfinden, da ich werte aus dem RAM> erhalten will. Es sollen nur ein paar Module in einen definierten> Zustand übergehen und dann wieder normal die Arbeit aufnehmen.
Setze in der ISR ein Flag und rufe vom Hauptprogramm aus die
Initialisierungs-Funktionen auf.
Um es noch etwas klarer zu machen: Mir würde kein einzige Szenario
einfallen, bei dem ein Jump aus einer ISR heraus ins Hauptprogramm
hinein eine gute Idee wäre.
Hallo,
die 2x pop kannst du dir sparen, lade lieber an deiner small_reset
stelle wieder RAMEND in den Stackpointer und gib im Anschluss die
Interrupts frei.
Wenn du nur die gesichtere Rückprungadresse der ISR vom Stack löschst
könnten dort immer noch gesicherte Register oder Rücksprungadresen aus
anderen Subroutinen bleiben. Das stört zwar erst mal nicht deine
gewünschte Funktion, aber wenn du die Reset-ISR paar mal auslöst dann
verbleibt mit der Zeit immer mehr auf dem Stack und irgendwann wenn du
nicht mehr dran denkst tritt ein ganz komischer Fehler auf weil der
Stack überläuft.
Sascha
Stefan schrieb:> ich möchte, dass ein Interrupt keine eigentliche ISR ausführt, sondern> an eine gewisse Stelle im Hauptprogram springt (so eine Art Teilreset).
Das ist Mist. Du weißt ja nicht, an welcher Stelle dein Hauptprogramm
unterbrochen wurde, dementsprechend kann da beliebig viel Müll auf dem
Stack liegen, nicht nur die Rücksprungadresse der aktuellen ISR.
Sprich: Stackunterlauf ist der vorprogrammierte End-GAU dieser überaus
schwachsinnigen Idee...
Wennschon, mußt du also mindestens den kompletten Stack abräumen und
nicht nur die Rückspungadresse der aktuellen ISR. Dann ist die Sache
wenigstens erstmal prinzipiell sauber.
Allerdings muß dann alles (und wirklich absolut alles), was in main()
passiert, darauf vorbereitet sein. D.h.: nix darf davon abhängig sein,
dass eine Aufrufstruktur von Unterprogrammen immer vollständig
abgearbeitet werden kann. Das ist durchaus machbar, aber oft garnicht so
einfach zu realisieren, wie man im ersten Moment denken mag und es führt
i.A. zu extrem ineffizienten Code.
Insgesamt: Ein technisch mögliches, aber absolut nicht empfehlenswertes
Design-Pattern. Nur die Verwender von längeren Software-Zeitscheifen
kommen normalerweise auf solche unsinnigen Ideen. Und diese sollten sich
statt mit schrägen Hacks lieber damit beschäftigen, wie sie diese
schwachsinnigen Warteschleifen loswerden können...
Klar, einfach den Stack neu initialisieren. **headslap**
Es geht im Endeffekt darum, dass ein Programm alle paar Sekunden genau
die gleiche Tätigkeit machen soll. Nur soll es vom vorherigen mal ein
paar Werte im RAM behalten und vergleichen.
Das die ISR mitten im Program aufgerufen wird, ist nahezu unmöglich, da
es nach paar 100ms abgearbeitet sein soll und alles in den Tiefschlaf
geht, die ISR aber nur alle 10sec kommt. Selbst wenn sie mal ausversehen
rein haut, stört es nicht, da wie gesagt alles neu initialisiert
wird/werden muss (bis auf die RAM Adresse) und somit nix passieren kann.
Stefan schrieb:> Es geht im Endeffekt darum, dass ein Programm alle paar Sekunden genau> die gleiche Tätigkeit machen soll. Nur soll es vom vorherigen mal ein> paar Werte im RAM behalten und vergleichen.> Das die ISR mitten im Program aufgerufen wird, ist nahezu unmöglich, da> es nach paar 100ms abgearbeitet sein soll und alles in den Tiefschlaf> geht, die ISR aber nur alle 10sec kommt. Selbst wenn sie mal ausversehen> rein haut, stört es nicht, da wie gesagt alles neu initialisiert> wird/werden muss (bis auf die RAM Adresse) und somit nix passieren kann.
Wenn das alles so ist, wie du schreibst, kannst du auch einfach einen
ganz normalen Reset auslösen. Der faßt den RAM-Inhalt nicht an...
Sprich: Du hast da wohl gerade den Watchdog neu erfunden. Den gibt's
aber schon lange...
Stefan schrieb:> Es geht im Endeffekt darum, dass ein Programm alle paar Sekunden genau> die gleiche Tätigkeit machen soll. Nur soll es vom vorherigen mal ein> paar Werte im RAM behalten und vergleichen.> Das die ISR mitten im Program aufgerufen wird, ist nahezu unmöglich, da> es nach paar 100ms abgearbeitet sein soll und alles in den Tiefschlaf> geht, die ISR aber nur alle 10sec kommt. Selbst wenn sie mal ausversehen> rein haut, stört es nicht, da wie gesagt alles neu initialisiert> wird/werden muss (bis auf die RAM Adresse) und somit nix passieren kann.
Und warum kann dein Programm das nicht einfach in einer Schleife tun,
ganz ohne fiese Sprünge "quer" aus der ISR raus?
Hallo,
die einzig sichere Methode eine ISR zu benden ist mit dem jeweiligen
Return from Interrupt-Befehl. Neben dem bereits gesagten, dass der
Zustand beim Auftreten des Interrupts dem Programmierer völlig unbekannt
ist, bestehen je nach Prozessor auch möglicherweise
Hardware-Abhängigkeiten: manche Prozessoren setzen z.B. mit dem
RETI-Befehl u.a. die IRQ-Prioritäts-Chain zurück, ohne RETI passiert das
nicht. Ob ein einfaches SEI den ordentlichen Rückkehrbefehl ersetzen
kann ist fraglich, schon deshalb, weil bei vielen Systemen nicht nur der
allgemeine Interrupt wieder eingeschaltet werden muss, sondern auch die
auslösende Peripherie muss erfahren, dass die Bearbeitung IHRES IRQs
fertig ist. Man kann sich um vieles herumtricksen, aber so einfach mit
SEI wie behauptet ist es nicht.
Man kann den Stack aufräumen, wenn man weiss wie, aber nur wenn das
Hauptprogramm wie vorgesehen weiter ausgeführt wird. Springt man
irgendwo anders hin, besteht keine Möglichkeit den Stack korrekt
zurückzusetzen - ausser man startet komplett von vorn mit allen
Initialisierungen. Dann kann man sich aber den ganzen Aufwand sparen und
gleich einen Reset oder JMP 0 ausführen.
Georg
Stefan schrieb:> Es geht im Endeffekt darum, dass ein Programm alle paar Sekunden genau> die gleiche Tätigkeit machen soll.
Dann setzt der Timerinterrupt einfach ein Bit und das Main testet in
einer Schleife das Bit.
Falls es wirklich nur diesen einen Interrupt gibt, wäre auch ein Sleep
an der Stelle möglich, d.h. das Main geht in Idle.
Daß vom Sprung aus Interrupts abgeraten wird, liegt nicht daran, daß es
grundsätzlich nicht geht, sondern daß man sich damit eine Zeitbombe ins
Programm einbaut, die bei größer werdendem Programm irgendwann
explodiert.
Und dann heißt es, alles wegschmeißen und nochmal von vorne
programmieren.
man kann sowas in ASM schon machen, nur kaschiert man damit meist andere
Fehler.
Wer löst denn den zugehörigen IRQ aus?
Es muß ja schon Fehler im Programm geben, sonst können Module ja nicht
in einen undefinierten Zustand gelangen.
Natürlich kann z.B. ein externes Modul abstürzen, nur dann initialisiere
ich genau dieses neu und weiß zu dieser Zeit auch genau, welche Daten im
Ram ich da behalten will und auch kann.
Gruß aus Berlin
Michael
Stefan schrieb:> ich möchte, dass ein Interrupt keine eigentliche ISR ausführt, sondern> an eine gewisse Stelle im Hauptprogram springt (so eine Art Teilreset).
Es ist mir zwar nicht ganz klar was du damit überhaupt bezwecken
willst, aber anstatt von einer ISR zur irgendeiner Routine zu
springen, könntest du alles in der zuerst aufgerufenen ISR machen.
Stefan schrieb:> ISR_SMALL_RESET:> POP ;Stack Pointer "säubern"> POP> RJMP SMALL_RESET
wenn schon, dann so: