PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Nach ISR in beliebige Funktion springen? Wie? Inline-Asm?



Manu_91
14.02.2009, 21:20
Hallo liebe RN-Community :)

Ich habe eine Frage bezüglich ISRs.
Ist es möglich nach dem ausführen einer ISR an eine andere Stelle im Code (an den anfang einer Methode) zu springen, sodass nicht da weitergemacht wird, wo die ISR aufgerufen wurde.

Es würde mir schon reichen, wenn an den Anfang der Methode gesprungen würde, in der die ISR aufgerufen wurde.

Muss ich dazu den Epilog der ISR verändern? bzw Wie? Mit Inline-Assembler?

Könnte mir jemand evtl. ein bisschen Beispielcode posten und ggf. kurz erläutern? Das wäre echt super! :) ;)


Ich poste hier (http://rafb.net/p/UOpInI79.html) noch meinen code:
Es geht darum, dass nach "ISR(INT0_vect)" bzw "ISR(INT1_vect)" wieder zum Anfang der Funktion "mainLoop()" gesprungen wird.

Vielen Dank schonmal im Vorraus - ich hoffe dass mir wer helfen kann...

einen schönen Abend noch euch allen ;)

Besserwessi
14.02.2009, 23:20
Man kann an viel stellen springen. Vielleicht sogar ohne ASM mit Goto. Allerdings wird fast jeder sprung den Stack durcheinanderbringen. Das einzige was noch einigermaßen geht ist zum Reset zu springen und komlett neu zu Starten, allerdings mit den alten Werten in den globalen Variablen, sofern die nicht initialisiert werden.

Man wird da schon in der main loop ein flag abfragen müssen, das dann in der ISR gesetzt wird.

sternst
15.02.2009, 05:35
Das einzige was noch einigermaßen geht ist zum Reset zu springen und komlett neu zu Starten, allerdings mit den alten Werten in den globalen Variablen, sofern die nicht initialisiert werden.
Bei einem Sprung zum Resetvector wird der gleiche C-Startup-Code ausgeführt, wie bei einem "echten" Reset. Bezüglich der C-Umgebung macht das absolut keinen Unterschied, also hat man nicht die alten Werte in den globalen Variablen (außer natürlich man hat sie explizit in die noinit-Section gelegt). Es macht allerdings einen Unterschied bei den Hardware-Registern.

p_mork
15.02.2009, 08:18
Hallo Manu,

hast du es schon mal mit longjmp / setjmp versucht? Sollte rein theoretisch funktionieren. Ansonsten bleibt wohl nur der Weg über die Abfrage eines Flags in der mainLoop wie Besserwessi schon geschrieben hat oder Du musst die Software anders designen, sodass das Problem garnicht mehr auftritt. Was wird in der mainLoop eigentlich gemacht, dass sie nach dem Interrupt unbedingt von vorne anfangen soll?

MfG Mark

Bumbum
15.02.2009, 08:48
Moin Leute,

Besserwesi hat es doch schon gesagt: Man kann zwar springen, aber der Stack wird in kürzester Zeit überlaufen, weil er im ISR nur gefüllt wird, aber nie mehr geleert.

Da muss man genau aufpassen, was man tut, ansonsten hat man ruck zuck ein Programm das immer nur sehr kurze Zeit läuft und dann abstürzt.

Ich würde mir auf jedne Fall eine andere Lösung überlegen. Dafür sind ISR nicht gedacht und ausgelegt. Das Flag ist z.B. eine gute Lösung.

Viele Grüße
Andreas

Manu_91
15.02.2009, 11:09
die mainLoop ist igg. nur die "Endlosschleife" in der main - ich hab das lediglich in eine extra Funktion gepackt, um einen Anhaltspunkt beim "Springen" zu haben.
Dass der Stack überläuft und sich das ganze aufhängt, wenn man einfach mainLoop() am ende der ISR aufruft, hab ich mir gedacht und auch schon feststellen müssen :/

ja ich werde wohl um Flags im mainloop nicht drumrumkommen und "anders designen" kann ich das programm leider auch nicht an dieser Stelle... ich hab mir gestern Nacht im Bett jedoch schon ein Paar Gedanken gemacht, wie ich dies am schönsten umsetzen könnte...

Es soll dann nach JEDEM ausgeführten Befehl ein Check ausgeführt werden und ich glaube mit einer switch Verzweigung in einer Schleife sollte sich sowas am schönsten umsetzen lassen



mainLoop()
{
xyz...
for(int i = 1; i <= 3; i++)
{
checkFlags();
switch(i)
{
case 1: Befehl1;
break;
case 2: Befehl2;
break;
case 3: Befehl3;
break;
}
}
}


Was haltet ihr davon?

Danke übrigens an alle, die bisher auf meine Frage geantwortet haben :)

Rofo88
15.02.2009, 11:16
Warum nicht in der ISR den Stack-Pointer manipulieren so das der Rücksprung an ne andere Stelle erfolgt. Nun muß man nur noch rausbekommen was C alles in den Stack schmeißt in der ISR.

Manu_91
15.02.2009, 11:19
ja gut, ungefähr so hatte ich mir das igg. vorgestellt...
nur weiß ich leider auch nicht, wie ich das anstellen sollte :D

sternst
15.02.2009, 11:30
Warum nicht in der ISR den Stack-Pointer manipulieren so das der Rücksprung an ne andere Stelle erfolgt. Nun muß man nur noch rausbekommen was C alles in den Stack schmeißt in der ISR.
Untauglich. Man hat dann immer noch den "Müll" auf dem Stack von der Funktion, die durch die ISR unterbrochen wurde, und von der Funktion in der die unterbrochene Funktion aufgerufen wurde, und von deren "Mutterfunktion", und von ...

Manu_91
15.02.2009, 11:35
wirklich? wird die isr nicht normal beendet, der speicher freigegeben und anschließend zur manipulierten Rücksprungadresse gegangen?

http://www.hs-augsburg.de/~sandman/c_von_a_bis_z/c_025_000.htm#RxxobKap02500004002C271F04F1B1

wird das ganz nett beschrieben, wie das machbar sein sollte:
Man nimmt die Adresse des ersten Parameters (Bei ISR leider nicht vorhanden... gibts da Alternativen?) und geht 1 Byte zurück und schon hat man einen Zeiger auf die Rücksprungadresse.

Aber nungut... wenn diese Methode untauglich ist, dann will ich dir das mal glauben - ich komm eigentlich aus der Java Ecke und bin deshalb nicht so fit im Umgang mit Speicheroperationen etc...

Schönen Dank euch allen ;)

Manu_91
15.02.2009, 11:37
achso verstehe :D
Der Stackrahmen der ISR wird zwar beendet, aber der "Müll der Mutterfunktion", wie du es genannt hast ist noch da - das klingt einleuchtend!

Rofo88
15.02.2009, 11:40
@sternst : Ja, da haste recht, in Assembler brauche ich den Stack weniger da kann man mir den Registern schon unheimlich viel machen

p_mork
15.02.2009, 13:46
@ Manu

Oder du machst es eben mit setjmp() am Anfang der mainLoop() und einen longjmp() in der ISR. Siehe auch http://en.wikipedia.org/wiki/Longjmp#Simple_example

MfG Mark

Manu_91
15.02.2009, 14:00
Hab mir grade den wiki-artikel durchgelesen...
das scheint ja genau das zu sein, was ich suche:
"to provide 'non-local jumps', or control flow besides the usual subroutine call and return sequence."

"A problem with the use of setjmp/longjmp is that cleanup" - könnte das vielleicht auch ein problem mit dem "stackmüll" geben?

naja jedenfalls nochmal vielen dank an alle, die mir bisher geantwortet haben ;)

ich mach mir erstmal nen kaffe - will irgendwer einen?

sternst
15.02.2009, 15:39
"A problem with the use of setjmp/longjmp is that cleanup" - könnte das vielleicht auch ein problem mit dem "stackmüll" geben? Nein, mit dem Stack hast du bei setjmp/longjmp keine Probleme. Das "cleanup" bezieht sich auf "höhere Ebenen", z.B. Dateien, die offen bleiben, oder Speicher, der nicht mehr freigegeben wird.


das scheint ja genau das zu sein, was ich suche
Trotzdem solltest du über eine Umstrukturierung deines Programms nachdenken. Der Wunsch, Funktions übergreifend herumzuspringen, ist fast immer das Resultat eines "vermurksten" Grundkonzepts. Es gibt nur sehr wenige wirklich sinnvolle Anwendungsfälle für setjmp/longjmp.

Iqon
17.09.2015, 08:56
Ich löse sowas meistens mit einem JobStack. Du legst in der ISR einen Pointer, der auf die Funktion zeigt, die ausgeführt werden soll, auf den JobStack. Den JobStack arbeitest du dann in der Main-Loop ab. Damit ist die Funktion aus dem Interrupt-Kontext gelöst und du hast kein Problem mit unaufgeräumten Stacks und anderen Laufzeit-Problemen, da alles mit C-Board mitteln gelöst wird.