ATMega8 Interrupts

Hero_123

Mitglied
17 Sep 2010
154
3
18
Sprachen
C
Hallo!

Ich bin etwas verwirrt bezüglich der Interrupts (beim ATMega8 z.B).
ich war bislang der Meinung, dass die Interrupts per per sei() freigegeben werden (ist klar), ein dann auftretender Interrupt seine ISR ausführt, dabei die Interruptfreigabe sperrt (ist auch klar) und ein 2.ter Interrupt, der während der Ausführung der ISR des 1.ten Interrupts auftritt, gespeichert und nach Beendigung der Ausführung der ISR des 1.ten Interrupts ausgeführt wird (da gespeichert) und dann wieder die Interrupts global freigegeben werden.
Tritt während der Ausführung der ISR des 1.ten Interrupts zusätzlich ein weiterer Interrupt auf, wird dieser "verworfen" (nicht gespeichert).

Jetzt steht aber auf S/15 des _ATMega8_L_datasheet.pdf (Rev Rev.2486AA–AVR–02/2013) dass - wenn mehrere Interrupts auftreten, diese gespeichert werden und dann entsprechend ihrer Priorisierung abgearbeitet werden (Stichwort "nested interrupts") - habe ich das falsch verstanden?

Die Priorisierung der Interrupts ist ja festgelegt - kann man diese ändern?

mfg

Hero_123
 

LotadaC

Sehr aktives Mitglied
22 Jan 2009
3.341
61
48
Marwitz
Sprachen
BascomAVR, Assembler
ich war bislang der Meinung, dass die Interrupts per per sei() freigegeben werden (ist klar),
SEI ist eigentlich ein Assembler Mnemonic, und ist die Abkürzung für "Set Global Interrupt Flag". BASCOM (und sicher auch andere Hochsprachen) bedient sich nur des Assembler-Befehls.
Der tatsächliche Maschinencode von SEI wäre 1001 0100 0111 1000.
Noch deutlicher wird's wenn man weiß (;)), daß 1001 0100 0xxx 1000 der Maschinencode für "Bit Set in SREG" (BSET) ist, wobei "xxx" das zu setzende Bit festlegt.
SEI setzt also Bit7 im Statusregister (und das ist eben das Globale Interrupt Flag "I"), nichts weiter.

Das SREG wiederum wird (z.B.)im Datenblatt des Mega8 (S.11) erklärt, zu "I"-Flag steht da unter anderem:
If the Global Interrupt Enable Bit is cleared, none of the interrupts are enabled independent of the individual Interrupt enable Settings.
Ein nicht gesetztes "I" blockiert also generell (global) alle IRQs, auch wenn die für sich (lokal) enabled sein sollten.

und ein 2.ter Interrupt, der während der Ausführung der ISR des 1.ten Interrupts auftritt, gespeichert und nach Beendigung der Ausführung der ISR des 1.ten Interrupts ausgeführt wird (da gespeichert) und dann wieder die Interrupts global freigegeben werden.
Tritt während der Ausführung der ISR des 1.ten Interrupts zusätzlich ein weiterer Interrupt auf, wird dieser "verworfen" (nicht gespeichert).
Nein, da wird nicht wirklich was gespeichert (also nicht so, wie Du es möglicherweise denkst). Eigentlich ist es ganz einfach:

Der Mega8 hat zB (abgesehen vom Reset, was kein Interrupt ist) 18 mögliche Interruptquellen (siehe Datenblatt Seite 46).
Jede dieser Quellen besitzt irgendwo sowas wie ein eigenes (lokales) Interrupt Enable Bit.

Jede dieser Quellen besitzt außerdem auch irgendwo sowas wie ein Interrupt-Anforderungsflag. Das muß nicht immer ein Bit in einem I/O-Register sein.

Die Interrupt-Anforderungsflags werden meist durch die Quelle bei entsprechenden Ereignissen gesetzt, und bleiben dann gesetzt.
Ist gleichzeitig das lokale Enable-Bit und das "I" in SREG gesetzt, wird der Interrupt bei der nächsten Gelegenheit behandelt. Das heißt, das Programm wird "unterbrochen": "I" wird gelöscht, der Programmzähler (zeigt normalerweise auf die nächste Instruktion im Programmspeicher) wird automatisch auf den Stack kopiert, Der Programmzähler wird "auf den Interruptvektor" gesetzt (=mit der Adresse beladen). Dort steht dann üblicherweise (bei Hochsprachen quasi immer, bei ASM kann jeder machen, was er will) ein Sprunginstruktion in die ISR.
Die ISR wiederum wird (üblicherweise) mit einem speziellen "Return from Subroutine" beendet, bei der nebenbei auch das "I" wieder gesetzt wird (RET nimmt die Adresse vom Stack, und springt dahin - RETI macht dasselbe, und setzt nebenbei das "I".
Ganz klar ist mir das bei BASCOM noch nicht - das Return am Ende einer Subroutine wird eigentlich in RET übersetzt, zeigt ein angelegter Interruptvektor ("On Interrupt...") auf die Adresse, wird es stattdessen in RETI übersetzt.

Ok, es gibt also Interruptquellen die ein richtiges Interrupt-Anforderungsflag haben (z.B. die Überlaufs- und Compare-Ereignisse der Timer, diverse "hab-fertig-Ereignisse" bei seriellen Schnittstellen, dem ADC usw), da zieht das Ereignis salopp gesagt die Fahne hoch, und die bleibt oben bis irgendwer sie wieder runterzieht.
Viele dieser Fahnen werden automatisch beim "behandeln" des Interruptes (also während des "Sprunges" in die IVT) durch die "Interrupt-Maschine" wieder runtergezogen (die Timer-Interrupts z.B.) - aber eben nicht alle, der TWI-Interrupt zB nicht.
Die meisten dieser Fahnen können aber "zu Fuß" wieder runtergezogen werden (indem man das Flag selbst mit einer "1" beschreibt (auch hier gibt's Ausnahmen).
Nehmen wir also mal an, der Timer wäre übergelaufen. Dann würde automatisch das TOV-Flag gesetzt werden (egal, ob "I" oder das lokale Enable-Bit gesetzt ist).
Nehmen wir weiter an, beide Bits sind gesetzt, dann würde also die korrespondierende ISR angesprungen werden, "I" wird vorerst gelöscht (Interrupts global gesperrt), Außerdem wird das TOV-Fähnchen runtergezogen.
Was passiert also, wenn der Timer nochmal überläuft, bevor die ISR beendet wurde?
Da "I" gelöscht ist, erstmal nichts, TOV bleibt oben. Egal ob der Timer währenddessen einmal, dreimal oder hundertmal überläuft - TOV bleibt gesetzt.
Wenn aber die ISR beendet wird, und "I" wieder gesetzt wird, schlägt der TOV sofort wieder zu, klar? (abgesehen von anderen gesetzten Interrupt-Fähnchen, die 'ne höhere Priorität haben, die sind dann vorher dran, und Dein TOV bleibt weiterhin oben, bis es irgendwann dann doch mal behandelt wird).

Neben diesen Quellen mit richtigem Interrupt-Anforderungsflag (also einem tatsächlichen Bit in irgendeinem I/O-Register) gibt es aber auch Quellen, bei denen irgendein Zustand oder Pegel den Interrupt anfordert. Der Low-Level-Interrupt bei den Externen IRQs zB. Solange das Bein Low ist, wäre hier die Fahne oben, ist das Bein nicht low, ist die Fahne unten. Dieser Zustand wird also nicht in irgendeinem Bit "gespeichert", wenn des Bein wieder hochgeht, bevor der Interrupt behandelt werden konnte (Sprung in die IVT), weil zB "I" grad nicht gesetzt war, wird der Interrupt nicht erkannt/ausgelöst. Die Fahne ist wieder unten.
Ein anderes Beispiel ist das UART-Data-Register-Empty-Flag. UDRE ist immer gesetzt genau dann wenn der Transmit-Buffer des UART leer ist. Wenn also der korrespondierende Interrupt lokal ("UDRIE") und global("I") freigegeben ist, und man nichts sendet, würde UDRE ununterbrochen triggern...

Stichwort "nested interrupts"
Bisher sind wir davon ausgegangen, daß während der Behandlung eines Interruptes "I" gelöscht ist, und weitere Unterbrechungen somit global blockiert sind. Etwaige Ereignisse ziehen ihre Fähnchen im Hintergrund trotzdem hoch, "speichern" die Anforderung (mehr oder weniger dauerhaft) in Form ihrer Anforderungs Flags, bis "I" wieder frei ist.
Und jetzt setzt Du selbst mal innerhalb der ISR das "I". Was geschieht (wenn währenddessen ein weiteres Interrupt-Fähnchen oben ist)?
Genau, der Interrupt wird sofort durch den nächsten IRQ unterbrochen (welcher erstmal seinerseits "I" wieder löscht - aber auch da kannst Du "I" ja wieder setzen)
Wird dieser zweite Interrupt beendet, kehrt der Controller wieder zum Unterbrechungspunkt zurück, was ja der erste Interrupt war. Und wird dieser beendet, bist Du wieder zurück im Hauptprogramm.
Die Interrupts sind also verschachtelt (nested). Ein Interrupt kann sich so insbesondere auch selbst unterbrechen.
Wie oft geht das, gibt's da 'ne Grenze?
Bei jeder Unterbrechung wird wie gesagt die Rücksprungadresse auf den Stack gelegt, und bei der Rückkehr wieder runtergenommen. Der Stack liegt im SRAM (i.a. am Ende, und wächst nach vorn), jede Adresse belegt (beim Mega8) ein Word, also zwei Bytes. Der Mega8 besitzt 1KByte SRAM, also 512 Words. Mit jeder weiteren Verschachtelungstiefe wächst der Stack also um mindestens dieses Adressword, und um das, was die ISR so nimmt. Bei Bascom wird zB jedesmal SREG auf den Stack gelegt, und diverse Rechenregister. Von "vorne" legt Bascom seinen "SoftStack" und den "Farmesize" an, und dann alle Variablen. Wenn der (Hardware-)Stack in diesen Bereich hineinwächst, gibt's lustige (und schwer lokalisierbare) Fehlerbilder.
Aber auch, wenn dem Stak der ganze SRAM zur Verfügung steht, ist bei 512 Words Schluß. Der Stackpointer würde dann theoretisch in die I/O-Register wandern, ein Push auf den Stack verpufft im Nirvana, ein Pop holt 'ne Null vom "Stack".

Die Priorisierung der Interrupts ist ja festgelegt
Es wird einfach immer derjenige aktive Interrupt mit der niedrigsten Adresse in der IVT abgearbeitet. Insbesondere kann also ein dauertriggernder Interrupt alle anderen (und das Hauptprogramm) ausbremsen.
kann man diese ändern?
Nein.
Also zumindest bei den klassischen AVR nicht.
Bei den X-Core-AVR kannst Du einigen Interrupts salopp gesagt 'ne höhere Priorität zuweisen - da wird aber das "I" auch nicht mehr Automatisch gelöscht usw. Da müßte ich mich aber selbst erst einarbeiten, falls Dich das wirklich interessiert … Mikro23 hat da sicher mehr Ahnung von - meiner Meinung nach verunsichert Dich das aber im Moment eher...
 
Zuletzt bearbeitet:

Hero_123

Mitglied
17 Sep 2010
154
3
18
Sprachen
C
Hallo LodataC

Vielen Dank für Deine tolle und ausführliche Erklärung :good3:

Zu den "nested Interrupts" - wenn ich diese nutzen wollte, müsste ich also in der "ersten" ISR die globalen Interrupts ("I"-Flag") wieder freigeben, damit ein 2.ter Interrupt quasi "innerhalb" der ersten ISR seine ISR arbarbeiten kann (wobei dieser Interrupt dann auch wieder die Globale Freigabe der Interrupts sperren würde, wenn ich sie nicht wieder selbst freigäbe), dann nach Abarbeitung dieser ISR erfolgt der Rücksprung in die erste ISR und diese wird abgearbeitet.

Was geschieht in diesem Fall mit der Globalen Freigabe der Interrupts? In der ersten ISR hatte ich sie freigegeben, damit der zweite Interrupt seine ISR ausführen kann, und wenn ich in der 2.ten ISR nicht die Globale Freigabe gemacht habe, werden ja hier die Interrupts gesperrt (durch die ISR).
Wenn nun der Rücksprung in die erste ISR erfolgt (die ja in "Wartestellung" ist) dann müssten hier die Interrupts immer noch gesperrt sein (wurden ja durch die 2te ISR gesperrt) - und nach Beendigung der ersten ISR automatisch wieder freigegeben werden, oder? Oder werden auch die Interruptregister auf dem Stack gesichert?

Ein Sichern und Zurückspeichern des SREG bei "nested interrupts" ist wahrscheinlich sinnvoll, oder?

Nur zu meinem Verständnis (jeweils in ISR Vector 5 und ISR Vector 9 manuell die Interrupts freigegeben, in ISR11 nicht; "=>" Aufruf ISR):
z.B: Programm => ISR Vector5 => ISR Vector9 => ISR Vector11 (RETI) => ISR Vector9 (RETI) => ISR Vector5 (RETI) => Programm - Globale Interrupts freigegeben.
Wenn während der Abarbeitung von ISR Vector 11 (hier KEINE manuelle Freigabe der Interrupts) ein Interrupt Vector10 aufträte - würde er nach Beendigung aller Interrupts ausgeführt werden?


mfg

Hero_123
 
Zuletzt bearbeitet:

LotadaC

Sehr aktives Mitglied
22 Jan 2009
3.341
61
48
Marwitz
Sprachen
BascomAVR, Assembler
Was geschieht in diesem Fall mit der Globalen Freigabe der Interrupts? In der ersten ISR hatte ich sie freigegeben, damit der zweite Interrupt seine ISR ausführen kann, und wenn ich in der 2.ten ISR nicht die Globale Freigabe gemacht habe, werden ja hier die Interrupts gesperrt (durch die ISR).
Wenn nun der Rücksprung in die erste ISR erfolgt (die ja in "Wartestellung" ist) dann müssten hier die Interrupts immer noch gesperrt sein (wurden ja durch die 2te ISR gesperrt) - und nach Beendigung der ersten ISR automatisch wieder freigegeben werden, oder? Oder werden auch die Interruptregister auf dem Stack gesichert?
Was meinst Du mit Interruptregistern?
Wenn mindestens ein Interruptanforderungsflag eines "scharfen" Interruptes gesetzt ist, und "I" gesetzt ist, schlägt die Interrupt-Maschine zu:
Das Programm wird, wie ober beschrieben unterbrochen, und die Abarbeitung des "wartenden" Interruptes (= Flag und Enable gesetzt) mit der höchsten Prio beginnt.
Dabei wird automatisch immer(! - wir reden nicht über X-Cores) erstmal das "I" gelöscht (aber das kannst Du in der ISR ja selbst wiederherstellen).
Ums nochmal genau zu sagen:
Der Controller selbst, die Hardware, die Interrupt-Maschine macht bei einem auftretenden scharfen ("I" und lokales Enable) Interrupt nicht mehr als:
  • (aktuelle (Maschinen-) Instruktion benden (kann ja eine mit mehreren Takten sein))
  • "I" in SREG löschen
  • Rückkehradresse auf den Stack pushen
  • Flashadresse des IVT-Einsprungpunktes des wirksamen in den Program-Pointer laden (entspricht Sprung in die IVT)
Mehr nicht.
Was auch immer Du (oder Deine Hochsprache) da hingecodet hast/hat, wird ausgeführt.
Im allgemeinen wird von dort aus irgendeine Adresse im Flash angesprungen, die Du für Dich als ISR bezeichnest, aber dem Controller selbst ist das Wurscht.
Du kannst (also unter Assembler - Hochsprachen beschneiden da Deine Möglichkeiten) auch direkt da Interrupt-Behandlungscode platzieren, statt des Sprunges.
Da aber hinter den meisten IVT-Einsprungadressen Einsprungadressen anderer Interrupts liegen, und bereits das RET/RETI eine Word Code belegt, wirst Du fast immer raushüpfen lassen müssen. (Aber bei Controllern mit Zwei-Word-breiter IVT passen zwei ein-Word-Instruktionen rein, wenn die eigentliche ISR also mit einer supersimplen ein-word-Instruktion ohne Manipulation des SREG umgesetzt werden kann (setze/lösche/toggle Bein x oder sowas), und im zweiten Word das RETI steht, geht sowas.
Also im allgemeinen hast Du 'nen Sprung aus der IVT in eine ISR - das ist aber Software - für den Controller ganz allgemeiner Code. Der weiß icht, daß er "in einer ISR" ist.
Und wenn "DEIN" Code da "I" wieder setzt, kann eben irgendein beliebiger weiterer IRQ triggern (auch dieselbe Quelle). Dann wird wieder "I" gelöscht, der neue Rücksprungpunkt auf den vorherigen drauf (und alles, was Deine ISR inzwischen draufgepackt hat) gepackt, und der IVT-Einsprungpunkt des "neuen" IRQs "angesprungen".
Die Rückkehr implementierst DU, eben entweder mit RET oder mit RETI (Bascom verwendet Return, was als RETI übersetzt wird, was C macht, weiß ich nicht).
Aber für den AVR gibts keinen Unterschied zwischen erster, zweiter ISR und Hauptprogramm.
RET quasi nichts anderes als ein indirekter Sprung, wobei das Sprungziel "vom Stack genommen wird". RETI macht dasselbe, und setzt als Bonus das "I".
Sinnigerweise sollte eben dieses Ziel irgendwann mal vorher auf den Stack gepackt worden sein - ansonsten gibts auch lustige (schwer lokalisierbare) Fehler...
Die Controller sind eigentlich viel simpler, als "Ihr" Hochsprachler denkt. Die machen genau das, was man ihnen sagt, zwar wahnsinnig schnell, aber nicht mehr.
 

Hero_123

Mitglied
17 Sep 2010
154
3
18
Sprachen
C
Hallo LotadaC

Vielen Dank für Deine ausführliche Erklärung!

Als "Hochsprachler" muss ich mich nicht um mov, push, pop, jmp, ret, reti kümmern, auch nicht um die Rückkehr aus einer ISR in das Hauptprogramm (außer ich habe in der ISR z.B eine Endlosschleife programmiert, sodaß die ISR nie verlassen wird), ebenso nicht darum, ob mein Controller eine 2-Word-breite IVT hat. Auch der program counter ist für mich nicht von Bedeutung.

Mir ist aber jetzt klar, was bei einem IRQ, dem Abarbeiten einer ISR und "nested Interrupts" passiert; auch verstehe ich jetzt die Bedeutung der IVT UND ich weiß jetzt, warum & wie bei einer ISR mit gesperrten Interrupts ein auftretender Interrupt gehandelt wird => sein individuelles Maskenbit wird gesetzt und nach Beendigung & Freigabe der Interrupts wird DIESER Interrupt abgearbeitet, und warum ein weiterer, gleicher Interrupt "verworfen" wird (da ja sein individuelles Maskenbit = "Anforderungsflag" schon gesetzt worden ist!).

Und ich muss mir im Klaren darüber sein, wie lange die ISR maximal dauern darf, damit keine Interrupts "verloren" gehen ;)

mfg

Hero_123
 

LotadaC

Sehr aktives Mitglied
22 Jan 2009
3.341
61
48
Marwitz
Sprachen
BascomAVR, Assembler
& wie bei einer ISR mit gesperrten Interrupts ein auftretender Interrupt gehandelt wird => sein individuelles Maskenbit wird gesetzt und nach Beendigung & Freigabe der Interrupts wird DIESER Interrupt abgearbeitet,
Wie gesagt gibt es Ausnahmen. Der externe Low-Level-Interrupt zB. hat kein richtiges solches Interruptflag, der Zustand des Beines ist quasi das Bit, und wenn das wieder high geht, bevor der Interrupt angegangen werden konnte wird der IRQ später nicht mehr erkannt.

Natürlich mußt Du Dich als Hochsprachler nicht drum kümmern - war ja nur für's Verständnis...
 

Hero_123

Mitglied
17 Sep 2010
154
3
18
Sprachen
C
Hallo LotadaC

Externe Low-Level-Interrupts INT0, INT1 - claro ;)

Und Deine Erklärungen waren für mich als "Hochsprachler" zum Verständnis sehr hilfreich!!! Deshalb :good2:

mfg

Hero_123
 

Hero_123

Mitglied
17 Sep 2010
154
3
18
Sprachen
C
Hallo

Ich habe eine Frage zu den Externen Interrupts INT0 und INT1 des ATMega8.

Gemäß _ATMEga8_L_datasheet Rev.2486AA–AVR–02/2013 steht auf S/66, "The external
interrupts are triggered by the INT0, and INT1 pins. Observe that, if enabled, the
interrupts will trigger even if the INT0..1 pins are configured as outputs. This
feature provides a way of generating a software interrupt..."

Wenn ich den INT0 Pin als "Eingangs-Interrupt" deklariert habe, sieht meine Deklaration ja so aus:


CodeBox C
DDRD &= ~(1 << DDD2);                /* PD2 als Eingang => ISR 0 */
PORTD |= (1 << PD2);                    /* PullUp Widerstand PD2 aktivieren */
MCUCR |= (1 << ISC01);                /* Int Trigger fallende Flanke PD2 */
GICR |= (1 << INT0);                       /* Interrupt INT0 aktivieren PD2 */


1.) Wie kann ich einen "software interrupt erzeugen", wenn ich diese INT0/INT1 Pins als Ausgang konfiguriert
habe?

2.) Kann ich dafür das GIFR nehmen und Bit 6 bzw 7 beschreiben (INT0 bzw INT1 "falling edge")?

Edit:
GIFR - im o.g. Datenblatt steht auf S/67 bezgl GIFR:
"When an event on the INT1 pin triggers an interrupt request, INTF1 becomes set (one). If the I-
bit in SREG and the INT1 bit in GICR are set (one), the MCU will jump to the corresponding
Interrupt Vector. The flag is cleared when the interrupt routine is executed. Alternatively, the flag
can be cleared by writing a logical one to it. This flag is always cleared when INT1 is configured
as a level interrupt."
Somit kann ich GIFR als Quelle für den Interrupt wohl nicht nehmen ...
Frage 2.) somit obsolet ...
Aber wofür wird dann das GIFR benötigt?
Und wie kann ich einen "software interrupt erzeugen", wenn ich diese INT0/INT1 Pins als Ausgang konfiguriert
habe?

mfg

Hero_123
 
Zuletzt bearbeitet:

LotadaC

Sehr aktives Mitglied
22 Jan 2009
3.341
61
48
Marwitz
Sprachen
BascomAVR, Assembler
Wie kann ich einen "software interrupt erzeugen", wenn ich diese INT0/INT1 Pins als Ausgang konfiguriert
habe?
Gemäß _ATMEga8_L_datasheet Rev.2486AA–AVR–02/2013 steht auf S/66, "The external
interrupts are triggered by the INT0, and INT1 pins. Observe that, if enabled, the
interrupts will trigger even if the INT0..1 pins are configured as outputs.
This
feature provides a way of generating a software interrupt..."
Vergiß mal, ob Ausgang oder Eingang.
Der IRQ triggert, wenn der entsprechende Pegel anliegt, oder die entsprechende Flanke erfolgt (je nachdem, was Du bei den Interrupt Sense Control Bits (in MCUCR) eingestellt hast - und natürlich nur, wenn der IRQ lokal (in GICR) und global (in SREG) aktiviert/enabled ist)
Die externen Interrupt-Flags (in GIFR) werden nur durch die Flanken-IRQs gesetzt (auch wenn lokal und/oder global disabled - dann erfolgt lediglich kein IRQ) - nicht durch den Pegel-IRQ (hatten wir ja oben - bei den Flanken IRQs ist das Fähnchen quasi ein Merker, beim Pegel ist der low-Pegel quasi das Fähnchen, und das merkt sich nichts)
Wenn Du also das Bein als High-Ausgang setzt, und dann den IRQ auf fallende Flanke konfigurierst (und komplett scharf machst), und anschließend das Bein auf low-Ausgang setzt, hast Du 'ne fallende Flanke, auf die der IRQ triggert...

Nochmal komplett:
  • "I" in "SREG" blockiert alle Interrupts global oder eben nicht (global enable)
  • "INTn" in "GICR" blockiert den externen Interrupt "n" (n=1..0) oder eben nicht (local enable)
  • "ISCn1..0" in "MCUCR" legen fest, wann der externe Interrupt "n" triggern soll (Pegel oder Flanke und ggf welche Flanke)
  • "INTFn" in "GIFR" enthält das Interrupt Flag von Interrupt "n" - aber nur bei Flanken-IRQs. Das Flag wird bei der entsprechenden Flanke automatisch gesetzt, und "wartet". Sind "I" und "INTn" gesetzt, wird der IRQ "bearbeitet", dabei wird automatisch das Flag gelöscht. Alternativ kannst Du (also das Programm) das Flag löschen, indem eine "1" reingeschrieben wird. Wird der externe IRQ als Pegel-IRQ verwendet, ist "INTFn" immer "0" - der tatsächliche Pegel am Bein dient dann quasi als Flag, und darauf hast nur Zugriff, indem Du entweder extern was anderes auf das Bein schaltest, oder eben intern (->DDR/PORT)
P.S.: in das Thema spielt auch noch der SLEEP mit rein, darauf bin ich nicht eingegangen
 
Zuletzt bearbeitet:

Hero_123

Mitglied
17 Sep 2010
154
3
18
Sprachen
C
Hallo LotadaC

Wiederum vielen Dank für Deine tolle Erklärung :good2:

Wenn Du also das Bein als High-Ausgang setzt, und dann den IRQ auf fallende Flanke konfigurierst (und komplett scharf machst), und anschließend das Bein auf low-Ausgang setzt, hast Du 'ne fallende Flanke, auf die der IRQ triggert...
=> "software interrupt" - somit klar ;)

SLEEP Modi - das ist ein weiteres Thema, mit dem ich mich noch eingehend beschäftigen muss (war bislang noch nicht im Fokus...)

mfg

Hero_123
 

LotadaC

Sehr aktives Mitglied
22 Jan 2009
3.341
61
48
Marwitz
Sprachen
BascomAVR, Assembler
Wobei sich mir(!) spontan der Sinn nicht erschließen will...
Wenn ich an irgendeinem Punkt im Programm die Entscheidung treffen lasse, den IRQ durch low-Setzen des Beines auszulösen, kann ich doch dort ebenso IRQs sperren ("CLI"), und mit "Call Subroutine" in die ISR des externen IRQs hüpfen lassen.
Hat genau denselben Effekt, und ist sogar etwas schneller.

Was übersehe ich?
 

Dirk

Administrator
Teammitglied
28 Jan 2007
4.282
141
63
Mittelhessen, Giessen
Sprachen
C, C++, C#, Pascal, Assembler, PHP, Java
Wobei sich mir(!) spontan der Sinn nicht erschließen will...
Wenn ich an irgendeinem Punkt im Programm die Entscheidung treffen lasse, den IRQ durch low-Setzen des Beines auszulösen, kann ich doch dort ebenso IRQs sperren ("CLI"), und mit "Call Subroutine" in die ISR des externen IRQs hüpfen lassen.
Hat genau denselben Effekt, und ist sogar etwas schneller.

Was übersehe ich?
Für den einen oder anderen ist es einfacher oder verständlicher, den Interrupt durch low-Setzen des Pins auszulösen.
In einer Hochsprache ist es unter Umständen einfacher oder sicherer, dies einfach über den Pin zu machen.
Interruptpriorität wird beibehalten.
Es ist ein Effekt bedingt durch die Hardware, darauf wird hingewiesen.
 

LotadaC

Sehr aktives Mitglied
22 Jan 2009
3.341
61
48
Marwitz
Sprachen
BascomAVR, Assembler
Es ist ein Effekt bedingt durch die Hardware, darauf wird hingewiesen.
Alles klar. Beim USI geht sowas natürlich auch, und auch da findet man 'nen entsprechenden Hinweis im Datenblatt.

Konsequenterweise kann man natürlich ach alle möglichen anderen periphären Komponenten (von innen) als Software-Interruptquelle mißbrauchen...
  • Timercompare- und/oder -überlaufsinterrupts (sogar mit einstellbarer Verzögerung)
  • Pinchangeinterrupts
  • Transfer-Complete-Interrupts von UART/TWI/SPI (auch einstellbar)
  • Analog-Comperator
  • ADC-Konversionszeit (bedingt einstellbar)
  • Watchdog-Timer (bei Controllern mit WD-IRQ - einstellbar)
(da wird kein expliziter Hinweis gegeben)
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)