Forum: Mikrocontroller und Digitale Elektronik Stack beschummeln? - need help


von Danny P. (Gast)


Lesenswert?

Hi Zusammen!

Kurze Frage:
Ich möchte am Ende des Interrupthandlers Timer0 nicht nur mit "reti"
dahin springen wo der Interrupt ausgelöst wurde, sondern an ein
bestimmte Programmpunkt viel weiter davor.
Kann/muss ich einfach mit "pop Akku" den Stack um einen zurücksetzen
(wurde ja mit dem Interruptsprung auch erhöht) und dann einfach mit
"rjmp Start" an meinen Punkt springen?
Oder handel ich mir mit sowas Probleme ein? Gibs elegantere
Möglichkeiten?

thx & greetz
Danny

von Benedikt (Gast)


Lesenswert?

Nö, denn das entspricht einem ret, du brauchst aber reti.
Es geht aber anderst: Mir 2x pop den Stack verringern und mit 2x push
die neue Sprungadresse laden.

von thkais (Gast)


Lesenswert?

In Interruptroutinen am Stack herummanipulieren, das ist sehr
gefährlich. Viel Spaß bei der Fehlersuche.
Ich wüßte auch keinen Grund, so etwas zu machen - Interrupts und
Unterprogramme sind eigentlich dafür da, daß sie ausgeführt werden,
ohne den Ablauf des übrigen Codes zu stören.
Denk mal z.B. über ein Flag nach, das in Deiner Hauptschleife abgefragt
wird.

von Danny P. (Gast)


Lesenswert?

Naja, es geht darum das ich Daten synchron Empfange und den Takt
(fallende Flanke) nicht über ein ext.Interrupt abfrage, sondern einfach
mit "warte bis high" - "warte bis low". Ist sicher wenig
professionell aber ich hab entschieden das es vom Programm her in
diesem Fall einfacher ist.
Falls der Empfänger nun aber mal ausser Takt fällt soll per Timer das
"warten" unterbrochen werden. Würd ich den Stack nun nicht
manipulieren würde ich nach dem "reti" im Interrupthandler ja wieder
in der Warteschleife hängen...

thx & greetz
Danny

von Tobi (Gast)


Lesenswert?

gabs schon mal nen thrad zu, such mal nach

von Benedikt (Gast)


Lesenswert?

Ja, der war von von mir...
Der Fehler lag am Ende woanderst, bzw. am Assembler, der Byte und Word
Adressen gleichsetzt.
Mit einem 8051 habe ich das schon oft genug gemacht, das geht
wunderbar.

Außerdem ist das überhaupt nicht gefährlich wenn man das in Assembler
in einem Interupt macht. Es gibt ja nichts, das den Interrupt
verändert, und wenn doch, das würde auch im normalen Betrieb den Stack
verhauen.

von Peter D. (peda)


Lesenswert?

"Mit einem 8051 habe ich das schon oft genug gemacht, das geht
wunderbar."

Wohl kaum !

Ohne ein RETI kannst Du beim 8051 nie wieder einen Interrupt
ausführen.


"Außerdem ist das überhaupt nicht gefährlich".

Na aber und ob. Du holst doch nur die Returnadresse vom Stack, was da
sonst noch so auf dem Stack liegt (Unterfunktionsreturnadressen, Daten)
davon hast Du nicht die geringste Ahnung.

D.h. Dein Stack läuft Dir irgendwann völlig aus dem Ruder.

Die einzige Möglichkeit ist, man springt ins Main zurück und dort wird
der Stack komplett neu initialisiert. Und beim 8051 mußt Du auch noch
bis zu 4 Dummy-RETIs machen (eins je Interruptlevel).


Peter

von Winfried (Gast)


Lesenswert?

So ein Vorgehen macht durchaus Sinn, wenn man es bedacht anwendet. Und
davon wurde auch z.B. in Heimcomputerzeiten viel Gebrauch gemacht.

Ich hatte letztens so einen Fall, wo ich es auch brauchte. Leider lässt
sich beim ATtiny 12 kein Stack manipulieren. Das Hauptprogramm musste in
einer sehr kurzen Schleife einen Pin toggeln, mehr nicht. Da war aber
keine Zeit, noch Bits abzufragen. Per Timerinterrupt sollte dann diese
Schleife umgeschaltet werden zu einer anderen, die etwas länger oder
kürzer läuft. Um ein unterschiedliches Tastverhältnis zu erreichen.

Also: Sagt niemals nie, aber man sollte schon mit Bedacht sowas
einsetzen. Oft gibt es bessere Lösungen.

Winfried

von Benedikt (Gast)


Lesenswert?

Bevor hier wieder die selbe Diskussion losgeht wie letzes mal:
a) es funktioniert einwandfrei !
b) ich lösche die Rücksprungadresse (=die letzen beiden Bytes auf dem
Stack) mit 2x POP
c) ich schreibe die neue Rücksprungadresse mit 2x push in den Stack
d) dann kommt ein reti
e) Bei einem Interrupt werden nur Adressen übergeben und keine Daten,
außerdem müssen die Adressen die letzen Daten auf dem Stack sein, denn
nach dem Interrupt befindet sich das Programm ja schon im Interrupt. In
C geht das nicht so leicht, denn man weiß nie was der Compiler macht,
aber in Assembler geht das problemlos.

von Dave (Gast)


Lesenswert?

man könnte auch den stack mit 2x pop befreien und dann mit nem rjmp und
sei weitermachen, dann braucht man keinen push der zeitraubend ist.

so: stimmt das eigentlich dass der µC durch ein falsches programm
abrauchen kann? z.b. stack-overflow?

dave

von andré (Gast)


Lesenswert?

"so: stimmt das eigentlich dass der µC durch ein falsches programm
abrauchen kann? z.b. stack-overflow?"

Nein, es stimmt nicht. Allein durch falsche Software wirst du keinen µC
kleinkriegen.

mfg

von Peter D. (peda)


Lesenswert?

"a) es funktioniert einwandfrei !"

Aber nur, wenn Du absolut unstrukturierten Spaghettikode verzapfst, der
keinerlei Unterfunktionen aufruft und keinerlei Daten pusht.

Denn nur dann weißt Du, daß nur die Returnadresse auf dem Stack liegt
und kannst diese löschen.

Bei strukturierten Programmen, die Unterfunktionen verwenden liegen da
noch ne Menge anderer Returnadressen und Daten drauf, je nach
Unterfunktionstiefe und die bleiben dann als Müll liegen.


Beispiel:

Funktion A ruft Funktion B auf, die 2 Register puscht, dann kommt ein
Interrupt C.
Dieser entfernt die Returnadresse zu B und springt wieder nach A.
Ergo die Returnadresse zu A und die 2 gepuschten Register bleiben
liegen.
Beim nächsten Interrupt dann wieder das gleiche usw. bis der Stack
überläuft.


Peter

von Benedikt (Gast)


Lesenswert?

>Funktion A ruft Funktion B auf, die 2 Register puscht, dann kommt ein
>Interrupt C.
Der Interrupt legt seine Rücksprungadresse auf den Stack.
Und solange der Interrupt nicht durch einen anderen unterbrochen wird
(zumindest nicht in dem Teil, wo der Stack manipuliert wird) passiert
nichts !

>Dieser entfernt die Returnadresse zu B und springt wieder nach A.
>Ergo die Returnadresse zu A und die 2 gepuschten Register bleiben
>liegen.
Nein ! Sonst würde das normale reti ja auch die Adresse von B
löschen...
>Beim nächsten Interrupt dann wieder das gleiche usw. bis der Stack
überläuft.
Nö, oder wie kommtst du bei folgender Rechnnung zu einem anderen
Ergebnis als Stack(nachher)= Stack(vorher)?
Stack(nachher)= Stack(vorher)+2*(-1)+2*(+1)
-1=pop
+1=push


Peter

von Peter D. (peda)


Lesenswert?

@Benedikt,

kehrt der Interrupt normal zurück, so tut er dies zu Funktion B, die er
ja unterbrochen hat. Diese wiederum popt die gesicherten Register wieder
und kehrt dann zu A zurück.

Geht der Interrupt aber direkt zu A, bleiben notgedrungen 4 Byte (ein
Call + 2 Datenbyte) auf dem Stack liegen.

Man kann aber auch nicht 6 Byte entfernen, da man ja nicht weiß, wo man
unterbrochen hat, ob in B oder B bzw. in B vor oder nach dem Puschen.

Im Interrupt können also bezogen auf Funktion A: 2, 4, 5 oder 6 Byte im
Stack liegen.


Peter

von Peter D. (peda)


Lesenswert?

Ups ein Dreckfuhler, richtig:

... ob in A oder B bzw. in B vor oder nach dem Puschen.


Peter

von Benedikt (Gast)


Lesenswert?

OK, stimmt.
Wenn man aber keine Unterprogramme verwendet dann geht es, (ansonsten
macht es ja auch wenig Sinn, zurück ins Hauptprogramm zu springen...

von Tobi (Gast)


Lesenswert?

dann bastel mal einen halbwegs komplexen code in asm ohne
unterprogramme. es ist schoon schwer genug mit welchen da ordnung und
übersicht zu halten...

von Benedikt (Gast)


Lesenswert?

Das geht schon, kommt immer darauf an was das Programm machen soll.
Ich habe mehrere Programme, die komplett ohne per call aufegerufene
Unterprogramme auskommen. Alles läuft über Interrupts (mit
Stackmanipulation) und rjmp. Ist ein Videogenerator.

von OldBug (Gast)


Lesenswert?

Warum einfach, wenns auch kompliziert geht?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.