Forum: Compiler & IDEs Register in Assembler Interruptfunktionen?


von bluemole (Gast)


Angehängte Dateien:

Lesenswert?

So noch einmal eine Frage zum Einbinden von Assembler-Funktionen in
C-Programmen...

Welche Register sollte mann in asm-Interrupt-Routinen verwenden?
Und kann man falls nötig benötigte Register einfach pushen und popen?

Ich suche jetzt schon bald den ganzen Tag nach dem Fehler in der
Funktion im Anhang. Kann mir jemand mal auf die Sprünge helfen.
Meine Orginalfunktion die ich in einem reinem Assembler-Programm
benutze funktioniert super. Anscheinend habe ich bei der Umsetzun in
eine C-taugliche Funktion irgendwo einen Bug drin. Ich bin da noch
ziemlich neu auf dem Gebiet...

Beschreibung:
Die Interrupt Funktion decodiert die Positive-Flanke des
Manchester-codierten Signals (Positive Flanke am Eingang).Es gibt auch
noch das Gegenstück, eine Funktion die auf die negative Flanke
reagiert.Eigentlich funktioniert das Programm, bis zu einen gewissen
Zeitpunkt. Leider stimmt ab circa der neunten Flankenauswertung das
Ergebnis nicht mehr. Im AVR-Studio debugge ich das Programm. Allerdings
kommt da immer das richtige Ergebnis raus. Meine Vermutung ist ja, dass
es irgendwann die globale Variable FlankeFlg zerlegt :-(....

Implementierung in C-Main:

volatile extern void SIG_INTERRUPT (void);

unsigned char FlankeFlg;

void main (void)
{......}

Ich hab' die Assembler Dateien mit xxx.S eingebunden....

Danke schoen,
bluemole

PS:Hab' schon ziemlich viel rumprobiert, daher schaut die Funktion ein
bisschen unkoordiniert aus.

von Jörg Wunsch (Gast)


Lesenswert?

Natürlich mußt Du in Deiner ISR alle Register retten, einschließlich
SREG.  Du kannst ja nie wissen, wann der Interrupt zuschlägt.

Schreibe am besten eine ISR in C und sieh Dir den generierten
Assemblercode an, dann hast Du ein Gerippe.

So komplex wie Deine ISR ist, kannst Du sie vermutlich effektiver
gleich in C schreiben.  Was ist denn der Grund für Assembler?

> volatile extern void SIG_INTERRUPT (void);

Wofür soll das denn gut sein?

von bluemole (Gast)


Lesenswert?

Der Grund ist ziemlich einfach. Ich habe bisher nur in Assembler die
Atmels programmiert. Daher habe ich ziemlich viele Assembler-
Funktionen, die ich weiterhin benutzen will ohne sie erst aufwendig in
C zu übersetzen.

>volatile extern void SIG_INTERRUPT (void);

volatile

ich will nicht, dass der Compiler die Funktion SIG_INTERRUPT zu
aggressiv optimiert. Aber wie gesagt, ich hab' zu diesem Zeitpunkt
dann schon viel rumprobiert.

Ansonsten ist doch der Aufruf völlig normal, oder?

PS: Die Funktion läuft immer noch nicht ordentlich...

von Jörg Wunsch (Gast)


Lesenswert?

> Der Grund ist ziemlich einfach. Ich habe bisher nur in Assembler die
> Atmels programmiert. Daher habe ich ziemlich viele Assembler-
> Funktionen, die ich weiterhin benutzen will ohne sie erst aufwendig
> in C zu übersetzen.

Vermutlich wäre das komplette Neuschreiben in C in einem Zehntel der
Zeit getan, die Du zum Debuggen der Assemblereinbindung brauchst.

> ich will nicht, dass der Compiler die Funktion SIG_INTERRUPT zu
> aggressiv optimiert.

Du hast den Sinn von `volatile' überhaupt nicht verstanden.

> Ansonsten ist doch der Aufruf völlig normal, oder?

Sorry, erstens ist es kein Aufruf, sondern eine Deklaration, und
zweitens fürchte ich, daß sie einfach nur völliger Unsinn ist (der
aber zum Glück bloß ignoriert wird).

> PS: Die Funktion läuft immer noch nicht ordentlich...

Klar, wenn Du Dir nicht die Mühe machst, die benutzten Register zu
retten, wird sie auch nicht richtig laufen können.

von bluemole (Gast)


Lesenswert?

T'schuldigung für mein volatile Mist und meinem Interrupt Aufruf. Aber
in der Not hat man die lustigsten Ideen

Meine Interrupt-Funktio läuft :-).
Ich hab'mir mal eine leere Interrupt-Funktion übersetzen lassen. Da
wird eigentlich nur das Statusregister und die benutzten Register (r0
und r1) gepusht. Ok nach dem Schema hab' ich meine Funktio dann auch
gebastelt.
Funktionierte dann immer noch nicht.
Erst als ich dann den Funktionsaufruf rcall serout (Anzeige des
empfangenen Bits) eleminiert habe ging's. Komisch ist es, wenn der ein
ganzer Datenstrom empfangen wurde gebe ich alle drei empfangenen Bytes
testhalber auch aus der Interrupt-Funktion mittels rcall serout aus und
es funktioniert einwandfrei...

Irgendwie scheint da noch der Hund begraben. Daher noch eine Frage.

Wie rufe ich aus einer Interruptroutine eine andere Assembler-Funktion
auf.

Mein Code Aufruf aus Assembler- Interrupt- Funktion:

ldi r24,0xAA   // r24 Übergabe register  0xAA Test Byte
rcall serout

Assembler-Code serout:

#define temp r24
....
serout:
sbis UCSRA,UDRE
rjmp serout
out UDR,temp
ret

.endfunc

Danke...

Ich rette nun das Statusr

von Stefan Kleinwort (Gast)


Lesenswert?

>Wie rufe ich aus einer Interruptroutine eine andere >Assembler-Funktion
auf.

Ganz normal - so wie Du es machst ist es schon ok.

Aber hast Du alle verwendeten Register von serout auch (auf dem Stack)
gerettet? R24?
ALLE Register, die innerhalb eines IR angefasst werden, müssen vorher
auf dem Stack gesichert werden. Sonst bekommst Du (ev. nur ab und an)
hässliche Fehler.
Ist Dein Stack groß genug definiert?

>serout:
>sbis UCSRA,UDRE
>rjmp serout

Das ist innerhalb eines IR nicht besonders schön. Der IR wartet
solange, bis der UART wieder frei ist. D.h. Du blockierst Dein System
für mehrere ms, auch für andere IR.

Stefan

von bluemole (Gast)


Lesenswert?

Ja ich weiß, dass das mit der Wartezeit in serout nicht so toll ist.
Aber zum Debuggen hat mir die Funktion schon oft sehr große Dienste
geleistet. Hier scheint sie mir echt einen Strich durch die Rechnung
gemacht zu haben.
Das Register 24 rette ich schon am Anfang der Interrupt-Funktion. Also
brauche ich es nicht ein zweites mal zu retten, oder doch?
Ist die Funktion serout wirklich so langsam.
Vielleicht entsteht ja wirklich irgendwie ein Laufzeitfehler. Also ein
Bit kommt alle 1000us Sekunden an. Somit wird alle 1ms ein Byte '1'
oder '0' zum veranschaulichen am PC ausgegeben.
Das müsste doch die USART-Schnittstelle mit 9600kBaud locker schaffen.
Wenn ich mich nicht irre.
9600kBaud == 9600 Bits pro Sekunde
Das heißt maximal könnte ich alle...rechne

1/9600*Bit/s = 0.000104 s/Bit

also pro 100us ein Bit verschicken...
Moment ein Bit.... Ich verschicke ein Byte

also 8* 100us = 800 us werden für ein Byte benötigt...

Ok, kann knapp werden.....

von Stefan Kleinwort (Gast)


Lesenswert?

Doppelt sichern musst Du R24 nicht, wenn die IR-fkt. das nicht
erfordert.

Vergiss Start/Stopbit nicht, unter 10 Bit geht (fast) nichts. Wie
langsam serout ist, hängt rein von der Baudrate ab.

Stefan

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.