www.mikrocontroller.net

Forum: Compiler & IDEs Register in Assembler Interruptfunktionen?


Autor: bluemole (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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.

Autor: Jörg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: bluemole (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Jörg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: bluemole (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan Kleinwort (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: bluemole (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.....

Autor: Stefan Kleinwort (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.