www.mikrocontroller.net

Forum: Compiler & IDEs [AVR][GCC] Zwischen verschiedenen Interrupt Routinen umschalten.


Autor: Markus Stehr (bastetfur)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mahlzeit Forum!

Wie kann ich zwischen mehreren INTs umschalten?

Sprich, ich will zwischen mehreren von dieser Sorte umschalten können:
ISR (TIMER1_COMPA_vect){...}

Autor: Andreas Paulin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kannst Du genauer beschreiben, was Du meinst?

Autor: Philipp H. (swissrookie)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Willst du verschiedene Zeiten für COMPA haben oder verschiedene Aktionen 
in der ISR ausführen?

Autor: Markus Stehr (bastetfur)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn ich jetzt irgendetwas Zeitkritisches habe will ich nicht erst in 
der INT Routine entscheiden was ich genau will.
Also soll die INT Routine an ihrem Ende prüfen ob sie selber oder einer 
ihrer "Freunde" als nächstes dran kommt und dafür dann den INT Vektor 
passend verbiegen.

Wenn das nur in Assembler geht soll mir das auch recht sein. :)

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
auch in Assembler wird es nicht gehen, weil der adresse ja fest im Flash 
steht, du könntest natürlich das Programm zu laufzeit anpassen aber das 
macht wenig sinn.
du musst immer über eine extra Sprungtabelle gehen die im Ram liegt.

bei C z.b. über Funktionszeiger.

Autor: Markus Stehr (bastetfur)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat der AVR kein Register als Zeiger auf die INT Routine?

Also quasi sowas:
;6502 code vorraus ;)
naechsterIRQTabLo:
!byte <IRQ_Eins
!byte <IRQ_Zwei
!byte <IRQ_Drei
naechsterIRQTabHi:
!byte >IRQ_Eins
!byte >IRQ_Zwei
!byte >IRQ_Drei

IRQ_Eins:
;Register sichern...
;irgendetwas....
jmp IRQ_Ende
IRQ_Zwei:
;Register sichern...
;irgendetwas anderes....
jmp IRQ_Ende
IRQ_Drei:
;Register sichern...
;irgendetwas noch anderes....
;jmp IRQ_Ende ;Hier flüssig....

IRQ_Ende:
ldx #naechsterIRQ
lda naechsterIRQTabLo,x
sta $fffe ;6502 IRQ Vektor
lda naechsterIRQTabHi,x
sta $ffff ;6502 IRQ Vektor
;Register wiederherstellen...
rti

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
nein, hat er nicht. Die Interrupt Tabelle steht im Flash. Du kommst um 
eine Auswertung der nötigen Aktionen innerhalb der Interruptroutine 
meiner Meinung nach nicht drumherum.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Funktionszeiger kann man nehmen, aber der Aufruf externer Funktionen
führt dazu, dass der Compiler alle Register sichern muss, die laut
ABI durch den Aufruf zerstört werden könnten, da der Compiler dann
keine Möglichkeit mehr hat zu testen, was die Funktionen wirklich
benötigen.  (Effektiv hat er diese Möglichkeit eigentlich nur bei
Funktionen, die "static" deklariert sind.)

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus Stehr wrote:

> Also soll die INT Routine an ihrem Ende prüfen ob sie selber oder einer
> ihrer "Freunde" als nächstes dran kommt und dafür dann den INT Vektor
> passend verbiegen.

Sowas mache ich in einer Timer-ISR, die lange dauert weil dort Sachen 
erledigt werden müssen, die nicht in der Hauptschleife erledigt werden 
können weil das alles echtzeitig sein muss. Die Hauptschleife macht 
irgendwelche komplexen Berechnungen, aber die Aktion in der ISR muss 
innerhalt von ca. 100-150 Ticks erfolgen. Damit ist das Setzen eines 
Merkers und Abarbeitung der Aktion in der Hauptschleife obsolet:

Am Ende der ISR wird überprüft, ob das IRQ-Flag, das für die ISR 
triggert, gesetzt ist. Falls nein, wird die ISR ganz normal verlassen. 
Falls ja, wird das Flag von Hand gelöscht und zurückgesprungen an den 
Anfang der ISR.

Dadurch spare ich die Zeit eines ISR-Frames (Prolog+Epilog) von ca. 100 
Ticks, was in der Anwendung mächtig viel Zeit ist (die IRQs kommen alle 
500 Ticks, und IRQs können kaskadieren).

Falls in einer ISR ein anderes IRQ-Flag als gesetzt erkannt wird, würd 
ich aber anraten, die ISR normal zu beenden und die andere IRQ triggern 
zu lassen.

Allerdings ist denkbar, auch das Zeug der anderen IRQ zu erledigen und 
auch deren Flag von Hand zurückzusetzen. Dadurch würde man evtl. auch 
ISR-Frames sparen; nicht nur was Zeit angeht, sondern auch Stack-Bedarf. 
Abzuchecken, welche IRQ-Flags gesetzt sind und die notwendige Aktion zu 
starten dürfte je nach Größe des ISR-Frames schneller gehen. Was das für 
den Code bedeutet (entweder static inline oder Funktionsaufrufe) muss 
man sich im einzelnen überlegen, denn die Aktion wird ja in mindestens 
zwei ISRs implementiert/benötigtund.

Johann

Autor: Axel Schwenke (a-za-z0-9)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus Stehr wrote:
> Wenn ich jetzt irgendetwas Zeitkritisches habe will ich nicht erst in
> der INT Routine entscheiden was ich genau will.
> Also soll die INT Routine an ihrem Ende prüfen ob sie selber oder einer
> ihrer "Freunde" als nächstes dran kommt und dafür dann den INT Vektor
> passend verbiegen.
>
> Wenn das nur in Assembler geht soll mir das auch recht sein. :)

Dann skizziere ich mal, wie ich das in Assembler lösen würde. Die echte 
(also über den Vektor verdrahtete) ISR ist nur ein Stub und holt sich 
die Adresse der gewünschten ISR aus dem RAM (besser: einem dezidierten 
Doppelregister) und springt sie entweder über IJMP an oder pusht sie auf 
den Stack und macht RET.

Ein paar Register müßte man schon im Stub retten und natürlich alle ISRs 
so auslegen, daß sie einen geeigneten Epilog verwenden.

Beispiel mit ISR Vektor im RAM:

.data
ISRVEC: .byte 0
        .byte 0

.text

.org Timer1_CompA_addr
         rjmp STUB
...

STUB:    push r16
         in r16, SREG
         push r16
         ;das war der minimale Prolog
         lds r16, ISRVEC
         push r16
         lds r16, ISRVEC+1
         push r16
         ;das ret ist ein indirekter Sprung
         ret

und am Ziel:

         ; ... dein Code ...
         pop r16
         out SREG, r16
         pop r16
         ;das war der Epilog
         reti

Mit ein paar Verrenkungen geht das sicher auch in C. Assembler dürfte 
aber einfacher sein.


XL

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Axel Schwenke wrote:

> Mit ein paar Verrenkungen geht das sicher auch in C. Assembler dürfte
> aber einfacher sein.

Nö, sowas geht auch in C gut.  Ist letztlich weiter nichts als eine
state machine, deren state in einem Funktionszeiger gehalten wird.

Der einzige Nachteil ist halt, dass bei C erst einmal sämtliche
Register beim Eintritt in die ISR gerettet werden, die vom ABI dafür
vorgeschrieben sind.  Aber wenn die implementierte Funktionalität
hinreichend komplex ist, dann machst du das am Ende auch bei einer
Assemblerprogrammierung so.  Die wäre nur dann günstiger, wenn alle
von der ISR gerufenen Routinen nur ganz wenig machen und daher auch
nur wenige Register retten müssen.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus Stehr wrote:
> Wenn ich jetzt irgendetwas Zeitkritisches habe will ich nicht erst in
> der INT Routine entscheiden was ich genau will.
> Also soll die INT Routine an ihrem Ende prüfen ob sie selber oder einer
> ihrer "Freunde" als nächstes dran kommt und dafür dann den INT Vektor
> passend verbiegen.

Du vermutest Probleme, wo garkeine sind.

Nimm ne Switch-Anweisung und gut is.

Das Interruptgedöns (Aufruf, Prolog, Epilog) unter AVR-GCC dauert fast 
nie unter 50 Zyklen, da fallen <10 Zyklen für das Switch überhaupt nicht 
ins Gewicht.


Peter

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.