Hallo an alle,
ich versuche verzweifelt den externen interrupt des Atmega16 zu nutzen.
Mein Problem ist, das der interrupt an sich funktioniert, jedoch der
Atmega ab und an danach einen reset macht. Scheint ein Problem mit der
Rücksprungadresse oder der interruptroutine selbst zu sein. Derzeit
toggle ich zum testen eine LED, wenn ein interrupt über int0 (Taster,
über RC entprellt) erzeugt wird.
Hier meine config für den interrupt 0:
#include <avr/interrupt.h>
...
MCUCR |= ( (1<<ISC01) | (1<<ISC00)); //The rising edge of INT0
generates an interrupt request.
GICR |= (1<< INT0); //enable external interrupt 0
sei(); //global interrupt enable
Ich habe schon sehr sehr viel gegoogelt und hier im Forum gelesen und
ich hätte gerne ein Beispielprogramm für den Atmega 16 welches den
externen interrupt nutzt und keinen reset erzeugt.
Noch einige Fragen:
1. Wo muss die Interruptroutine stehen? Vor oder nach dem main()
2. Wie muss die Routine für den Atmega 16 aussehen
ISR(INT1_vect) {...}
SIGNAL(INT1_vect) {...}
oder das hab ich auch noch gefunden
#ifdef _GNUC_
ISR(INT1_vect)
#else
interrupt [EXT_INT1] void ext_int1_isr(void)
#endif
{...}
Vieleicht hat jemand eine funktionierendes Testprogramm (in c#)
Viele Grüsse,
Jürgen
Juergen schrieb:
> Vieleicht hat jemand eine funktionierendes Testprogramm (in c#)
Seit wann gibt es einen C# Compiler für AVR :-)
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Programmieren_mit_Interrupts
(Dein Problem ist wahrscheinlich gar nicht in dieser ISR zu suchen. Ich
denke, du hast irrtümlich noch einen anderen Interrupt freigegeben, für
den du keinen Handler hast)
Hallo Frank,
ich habe meine main.c angehängt.
Das Programm blinkt nach dem Start mit LED1. Dadurch erkenne ich einen
reset. Ansonsten wird mit dem external Interrupt LED2 getoggelt.
Vieleicht liegt der Fehler in der Initialisierung der seriellen
Schnittstelle?
Gruß,
Jürgen
> 1. Wo muss die Interruptroutine stehen? Vor oder nach dem main()
Das ist egal. Wichtig ist nur der richtige Name.
> 2. Wie muss die Routine für den Atmega 16 aussehen> ISR(INT1_vect) {...}> SIGNAL(INT1_vect) {...}
Für avr-gcc: Ersteres. Das Zweite ist deprecated, wird aber (noch) als
gleichwertig erkannt.
Juergen schrieb:
> Hallo Frank,>> ich habe meine main.c angehängt.
... die ich mal etwas umgestaltet habe - siehe angehängte Datei. Das
funktioniert so bei mir.
Ich habe die USART Schnittstelle rausgenommen, um Fehler dort
auszuschliessen. Kannst Du mal probieren und berichten, ob das so bei
Dir stabil läuft ?
Grüße
Frank
Hallo Frank,
so ich hatte eben Zeit deinen Code zu testen.
Hat leider nicht funktioniert. Ich sehe zwei Fehlerszenarien die
scheinbar ohne Systematik auftreten, wenn ich nach dem Einschalten der
Versorgungsspannung auf Taster 1 (=int0) drücke:
1. Fehler: Sobald der externe interrupt abgearbeitet ist erfolgt sofort
der reset und die LED1 blinkt 10mal. :/
oder
2. Es passiert, dass ich den interrupt0 ausführen kann (d.h. die LED2
blinkt kurz), danach passiert kein reset, und es geht auch kein weiterer
int0 (d.h. kein erneutes blinken der LED2) mehr. Der Atmega hängt.
Wenn ich deinen code anschaue sehe ich, dass du das SREG sicherst. Das
sollte aber vom GCC selbst übernommen werden.
Außerdem kommt bei mir beim kompilieren von
"ISR(SIG_UART0_RECV)" >>> misspelled signal handler
dass muss "ISR(SIG_UART_RECV)" heissen.
Jedenfalls hats nichts geholfen. Der externe interrupt bleibt ein
Mysterium. Schade. :(
Sonst noch Vorschläge?
Juergen schrieb:
> Hallo Frank,>> so ich hatte eben Zeit deinen Code zu testen.>> Hat leider nicht funktioniert.
Schade ;-)
> Ich sehe zwei Fehlerszenarien die> scheinbar ohne Systematik auftreten, wenn ich nach dem Einschalten der> Versorgungsspannung auf Taster 1 (=int0) drücke:>> 1. Fehler: Sobald der externe interrupt abgearbeitet ist erfolgt sofort> der reset und die LED1 blinkt 10mal. :/>> oder>> 2. Es passiert, dass ich den interrupt0 ausführen kann (d.h. die LED2> blinkt kurz), danach passiert kein reset, und es geht auch kein weiterer> int0 (d.h. kein erneutes blinken der LED2) mehr. Der Atmega hängt.>> Wenn ich deinen code anschaue sehe ich, dass du das SREG sicherst. Das> sollte aber vom GCC selbst übernommen werden.
Komisch, das hat schonmal jemand behauptet. Ist aber schlicht nicht
so!!! Einfach mal den generierten Code anschauen.
> Außerdem kommt bei mir beim kompilieren von> "ISR(SIG_UART0_RECV)" >>> misspelled signal handler>> dass muss "ISR(SIG_UART_RECV)" heissen.
Kann sein, habe das geändert, weil bei mir ein ATmega32 zum Einsatz
kommt. Hab's allerdings auch mit einem ATmega8515 getestet, da lief's
auch. Und auf dem STK500v2 von Atmel läuft das auch...
> Jedenfalls hats nichts geholfen. Der externe interrupt bleibt ein> Mysterium. Schade. :(
Das heisst für mich: Hardware-Problem. Wie sieht denn die Anschaltung
des Tasters an INT0 aus? Kannst Du ein Bild des Schaltplans dranhängen?
> Sonst noch Vorschläge?
Noch geben wir nicht auf... ;-)
Grüße
Frank
Hier der Schaltplan,
es handelt sich um das hier im Forum relativ bekannte Pollin Atmel
Evaluationsboard.
Die Taster funktionieren ansich wenn ich sie per software auslesen
lasse. Nur bei Verwendung des int0 kommt immer früher oder später ein
reset.
Grüße,
Jürgen
Juergen schrieb:
> Hier der Schaltplan,>> es handelt sich um das hier im Forum relativ bekannte Pollin Atmel> Evaluationsboard.
Ah - das Board hat die Taster mit Pull Down Widerständen drin. Dann
sollte INT0 als Falling Edge Interrupt konfiguriert werden (geht
natürlich auch anders, ist aber einen Test wert). Damit geht der
Interrupt erst los, wenn Du den Taster los lässt.
>> Die Taster funktionieren ansich wenn ich sie per software auslesen
Jau, da wird auch auf High Pegel direkt abgefragt. Das geht mit der Pull
Down Konfiguration so nicht am Taster 1 für INT0.
> lasse. Nur bei Verwendung des int0 kommt immer früher oder später ein> reset.
Und deswegen habe ich jetzt mal einen Generic Interrupt Handler
eingebaut in den angehängten Source Code. Der feuert immer dann, wenn
ein Interrupt auftritt, für den keine explizite ISR angegeben ist. Siehe
main() und ISR( __vector_default ).
>> Grüße,> Jürgen
Happy Testing.
Grüße
Frank
>> Wenn ich deinen code anschaue sehe ich, dass du das SREG sicherst. Das>> sollte aber vom GCC selbst übernommen werden.>> Komisch, das hat schonmal jemand behauptet. Ist aber schlicht nicht> so!!!
Das stimmt. Es wird nämlich nicht vom GCC, sondern vom Prozessor selbst
bereits gemacht. Ein manuelles Sichern ist unnötig.
Rolf Magnus schrieb:
>>> Wenn ich deinen code anschaue sehe ich, dass du das SREG sicherst. Das>>> sollte aber vom GCC selbst übernommen werden.>>>> Komisch, das hat schonmal jemand behauptet. Ist aber schlicht nicht>> so!!!>> Das stimmt. Es wird nämlich nicht vom GCC, sondern vom Prozessor selbst> bereits gemacht. Ein manuelles Sichern ist unnötig.
Na, das ist aber doch ein Idiom:
1. Sichere SREG in Variable
2. cli();
3. Mach was hier, was ohne Interrupt durchgeführt werden muss.
4. SREG wieder setzen aus Variable
Wie das durch den AVR selbst gemacht werden soll, ist mir schleierhaft
!! Denn: Der AVR müßte ahnen, wann die Operationen, die ohne Interrupt
durchgeführt werden müssen, zu Ende sind. Die AVRs sind zwar richtige
kleine Künstler, aber dass die KI haben, ist mir neu ;-)
Oder aber: Ich habe da was völlig missverstanden in den letzten 5 Jahren
AVR Programmierung - was dann gerne zugebe ;-)
Grüße
Frank
Und nochmal SREG:
Lest Euch mal die Funktion
void NichtUnterbrechenBitte(void)
im AVR-GCC Tutorial in diesem Wiki in Kapitel 13.5 durch. Das macht dann
hoffentlich klar, was ich meine.
Grüße
Frank
Falsche Reihenfolge!
Das sei() kommt immer erst nachdem sämtliche Interrupt-Quellen
konfiguriert wurden.
So gehört das:
1
// Init environment
2
3
init_ports();
4
init_usart();
5
init_interrupt();
6
7
sei();
>Wie das durch den AVR selbst gemacht werden soll, ist mir schleierhaft>!! Denn: Der AVR müßte ahnen, wann die Operationen, die ohne Interrupt>durchgeführt werden müssen, zu Ende sind. Die AVRs sind zwar richtige>kleine Künstler, aber dass die KI haben, ist mir neu ;-)
Da hast du was falsch verstanden:
Eine ISR des AVR kann nicht durch eine andere unterbrochen werden;
dafür sorgt der AVR.
Andere Funktionen sind vor der Unterbrechung durch einen Interrupt nicht
geschützt.
>void NichtUnterbrechenBitte(void)
Darin soll verhindert werden, dass ein Interrupt die Funktion
unterbricht.
Das kann den Grun haben, dass sie einen Wert manipuliert (oder auch nur
ausliest), der auch durch eine ISR geändert werden kann.
Dafür gibt es inzwischen aber das Atomic-Makro...
>> Falsche Reihenfolge!> Das sei() kommt immer erst nachdem sämtliche Interrupt-Quellen> konfiguriert wurden.
Jadoch, hast ja Recht.
>> So gehört das:>
1
>
2
>// Init environment
3
>
4
>init_ports();
5
>init_usart();
6
>init_interrupt();
7
>
8
>sei();
9
>
>>>Wie das durch den AVR selbst gemacht werden soll, ist mir schleierhaft>>!! Denn: Der AVR müßte ahnen, wann die Operationen, die ohne Interrupt>>durchgeführt werden müssen, zu Ende sind. Die AVRs sind zwar richtige>>kleine Künstler, aber dass die KI haben, ist mir neu ;-)>> Da hast du was falsch verstanden:> Eine ISR des AVR kann nicht durch eine andere unterbrochen werden;> dafür sorgt der AVR.
Nee, hatte ich nicht, denn:
>> Andere Funktionen sind vor der Unterbrechung durch einen Interrupt nicht> geschützt.>>void NichtUnterbrechenBitte(void)> Darin soll verhindert werden, dass ein Interrupt die Funktion> unterbricht.
das ist genau das, was erreicht werden soll.
> Das kann den Grun haben, dass sie einen Wert manipuliert (oder auch nur> ausliest), der auch durch eine ISR geändert werden kann.
Ach ... ;-)
> Dafür gibt es inzwischen aber das Atomic-Makro...
Ja, aber das macht genau dasselbe wie die von mir dargestellte Sequenz.
Ich bin halt einer, der schon vor util/atomic.h AVRs programmiert hat.
;-)
Grüße
Frank
Ihr redet aneinander vorbei
>> Jürgen>> Wenn ich deinen code anschaue sehe ich, dass du das SREG sicherst. Das>> sollte aber vom GCC selbst übernommen werden.>> Frank> Komisch, das hat schonmal jemand behauptet. Ist aber schlicht nicht> so!!! Einfach mal den generierten Code anschauen.
Jürgen hat nicht geschnallt, was der Grund für die SREG Sicherung ist.
Er hat nur SREG gesehen und sofort auf Pfui plädiert.
Und Frank hat ihm nicht erklärt, dass der Grund für diese Sicherung das
Abschalten der Interrupts zum Zwecke der Nichtunterbrechnung einer
Codesequenz ist.
Jürgen redet von der SREG Behandlung in einer ISR
Frank von einer SREG Behandlung ausserhalb einer ISR
Aber keiner nennt die Dinge beim Namen und so reden sie aneinander
vorbei.
Trotzdem mach der AVR beim Eintritt in eine Interruptroutine das SGER
sichern und Interrupts abschalten von selber. Dazu braucht er auch keine
KI, denn der Prozessor weiß, wann er eine ISR ausführt!
Karl heinz Buchegger schrieb:
> Ihr redet aneinander vorbei>>>>> Jürgen>>> Wenn ich deinen code anschaue sehe ich, dass du das SREG sicherst. Das>>> sollte aber vom GCC selbst übernommen werden.>>>> Frank>> Komisch, das hat schonmal jemand behauptet. Ist aber schlicht nicht>> so!!! Einfach mal den generierten Code anschauen.>> Jürgen hat nicht geschnallt, was der Grund für die SREG Sicherung ist.> Er hat nur SREG gesehen und sofort auf Pfui plädiert.>> Und Frank hat ihm nicht erklärt, dass der Grund für diese Sicherung das> Abschalten der Interrupts zum Zwecke der Nichtunterbrechnung einer> Codesequenz ist.
Ok, ja, nicht direkt, sicher. Dass die fragliche Code Sequenz aber nicht
in einer ISR stand, war aber doch hoffentlich allen klar.
Es ging ja um das Setzen einer zwischen ISR und main() gemeinsam
genutzten Variablen: nInterruptOccured .
> Jürgen redet von der SREG Behandlung in einer ISR> Frank von einer SREG Behandlung ausserhalb einer ISR>> Aber keiner nennt die Dinge beim Namen und so reden sie aneinander> vorbei.
Danke.
;-)
Gruß,
Frank
Frank Goenninger schrieb:
>> Dafür gibt es inzwischen aber das Atomic-Makro...>> Ja, aber das macht genau dasselbe wie die von mir dargestellte Sequenz.
Aber auf eine etwas andere Art, was Vorteile hat:
1) Innerhalb des Schutzes steht auch genau das, was du selber dort
reingeschrieben hast. Bei deiner Lösung kann dir der Optimizer durch
Reordering schon mal einen Strich durch die Rechnung machen.
2) SREG wird auf jeden Fall zurückgeschrieben, egal wie der Block
verlassen wird. Du kannst sogar innerhalb des geschützten Blocks
"return" verwenden.
Stefan Ernst schrieb:
> Frank Goenninger schrieb:>>>> Dafür gibt es inzwischen aber das Atomic-Makro...>>>> Ja, aber das macht genau dasselbe wie die von mir dargestellte Sequenz.>> Aber auf eine etwas andere Art, was Vorteile hat:> 1) Innerhalb des Schutzes steht auch genau das, was du selber dort> reingeschrieben hast. Bei deiner Lösung kann dir der Optimizer durch> Reordering schon mal einen Strich durch die Rechnung machen.
Guter Punkt. Und genau das richtige Argument, um mich zu überzeugen,
doch mal in atomic.h reinzuschauen. Wieder was gelernt. Danke!!
> 2) SREG wird auf jeden Fall zurückgeschrieben, egal wie der Block> verlassen wird. Du kannst sogar innerhalb des geschützten Blocks> "return" verwenden.
Das ist zwar auch wichtig, würde aber bei mir aus Stilgründen schon
wegfallen.
Siehe main.c anbei. So besser ? ;-)
Gruß,
Frank
Frank Goenninger schrieb:
> Siehe main.c anbei. So besser ? ;-)
Ähm, naja, ...
Ich sehe überall nur ATOMIC_FORCEON. Warum dann im Original-Code das
SREG-Sichern statt eines einfachen cli/sei-Pärchens?
Stefan Ernst schrieb:
> Frank Goenninger schrieb:>>> Siehe main.c anbei. So besser ? ;-)>> Ähm, naja, ...> Ich sehe überall nur ATOMIC_FORCEON. Warum dann im Original-Code das> SREG-Sichern statt eines einfachen cli/sei-Pärchens?
Sh*t. Ok, wer lesen kann ist klar im Vorteil.
Also sollte es ATOMIC_RESTORESTATE heissen. For the records: Neue
Version main.c anbei. Ich dachte nicht, dass ich in diesem Thread noch
die amotic.h lesen würde <g>.
Danke!!!
Gruß,
Frank
Wenn wir schon dabei sind ... :-)
> Es ging ja um das Setzen einer zwischen ISR und main() gemeinsam> genutzten Variablen: nInterruptOccured .
Du meinst wohl nInterruptHappened. Das ist ein uint8_t. Das Schreiben
ist eh schon atomar, wozu der zusätzliche Schutz?
Was allerdings nötig ist (und fehlt), ist ein "volatile".
Stefan Ernst schrieb:
> Wenn wir schon dabei sind ... :-)>>> Es ging ja um das Setzen einer zwischen ISR und main() gemeinsam>> genutzten Variablen: nInterruptOccured .>> Du meinst wohl nInterruptHappened.
Ja.
> Das ist ein uint8_t. Das Schreiben> ist eh schon atomar, wozu der zusätzliche Schutz?
Pure Faulheit. Ich kann dann den Typ ändern, ohne daran denken zu
müssen, dass ich dann auch noch die Unterbrechungsfreiheit dazu kodieren
muss.
> Was allerdings nötig ist (und fehlt), ist ein "volatile".
Ja.
Gruß,
Frank
Frank Goenninger schrieb:
> Pure Faulheit. Ich kann dann den Typ ändern, ohne daran denken zu> müssen, dass ich dann auch noch die Unterbrechungsfreiheit dazu kodieren> muss.
Sorry, aber dann bist du ziemlich inkonsequent. Das Schreiben wird
geschützt, das Lesen aber nicht?
Stefan Ernst schrieb:
> Frank Goenninger schrieb:>>> Pure Faulheit. Ich kann dann den Typ ändern, ohne daran denken zu>> müssen, dass ich dann auch noch die Unterbrechungsfreiheit dazu kodieren>> muss.>> Sorry, aber dann bist du ziemlich inkonsequent. Das Schreiben wird> geschützt, das Lesen aber nicht?
Ja doch.
Und weil's sonst langweilig wird, habe ich auch noch einen reset()
Funktion eingebaut. Denn: Wenn's nen unbehandelten Interrupt gibt, dann
könnte man ja auch einen Reset machen... Nur so als Illustration.
Rückmeldung ? Danke !
Gruß,
Frank
Bei dem Thread fällt mir nur wieder die Frage ein: "Machen sich die
Leute schon Gedanken zum Programm, bevor sie es tippen, oder erst, wenn
es beim Kunden ist?"
STK500-Besitzer schrieb:
> Bei dem Thread fällt mir nur wieder die Frage ein: "Machen sich die> Leute schon Gedanken zum Programm, bevor sie es tippen, oder erst, wenn> es beim Kunden ist?"
Kunde? Wer hat was von Kunde gesagt ? Es ging darum, den INT0 auf einem
bestimmten Eval-Board zu nutzen. Das haben manche hier mit konkreten
Code Beispielen versucht, hinzubekommen. Leider hat das bisher wohl
nicht geklappt. Dann ist aus dem Thread ein "Ich zeige Dir wie und wann
man die Makros aus atomic.h benutzt.
Ich als Gelegenheits-µC-Programmierer habe dabei was gelernt -
technisch und was über andere ;-)
Gruß,
Frank
>> Das stimmt. Es wird nämlich nicht vom GCC, sondern vom Prozessor selbst>> bereits gemacht.>> AVRs sichern SREG nicht von sich aus.
Ich hatte mich verwirren lassen, wahrscheinlich durch den Namen
init_initerrupt. Ich hatte irgendwie 'interrupt' gelesen und es dann mit
einer ISR verbunden, in der man das nicht explizit sichern müßte. Ich
fürchte, daß ich damit noch einige andere verwirrt hab. Man sollte eben
doch nicht morgens, bevor man zur Arbeit fährt, schnell noch ein Posting
schreiben.
Mea Culpa
Halli Hallo,
ich bin gerade ganz guter Laune :)
zuerst zu Frank: Dein Code vom 30.10.2009 12:03 main.c hat
funktioniert!
Vielen vielen Dank.
Ich hoffe du bist mir nicht böse wenn ich deinen code etwas entrümpelt
habe. Im Anhang befindet sich nun die Version deines Programmes welche
mein ursprünglich geplantes Testscenario enthält.
Kurz zu diesem Testprogramm:
> nach dem Start des Atmega 16 blinken beide LEDs (an PD5/PD6)> im main() endlosschleife die nicht tut> bei einem externen interrupt (int0) soll die LED2 getoggelt werden
wichtigstes Feature :) kein reset während dem Programmablauf
zuletzt noch einen Dank an alle anderen die hier was gepostet haben.
Ich kann zwar nicht nachvollziehen ob das alles was geschrieben wurde zu
meiner Problemlösung beigetragen hat (das sollte sich jeder selbst
überlegen)...
jedenfalls ist das Problem für mich gelöst. Ich habe mein Testprogramm
als Grundgerüst, mit dem ich nun weiterarbeiten kann.
Gruß,
Jürgen
Juergen schrieb:
> Halli Hallo,>> ich bin gerade ganz guter Laune :)>> zuerst zu Frank: Dein Code vom 30.10.2009 12:03 main.c hat> funktioniert!> Vielen vielen Dank.
Immer gerne! ;-)
>> Ich hoffe du bist mir nicht böse wenn ich deinen code etwas entrümpelt> habe. Im Anhang befindet sich nun die Version deines Programmes welche> mein ursprünglich geplantes Testscenario enthält.
Das kann man dann aber noch weiter entrümpeln ..
>> Kurz zu diesem Testprogramm:>>> nach dem Start des Atmega 16 blinken beide LEDs (an PD5/PD6)>> im main() endlosschleife die nicht tut>> bei einem externen interrupt (int0) soll die LED2 getoggelt werden>> wichtigstes Feature :) kein reset während dem Programmablauf
Was wohl letzten Endes auf den geänderten INT0 Trigger zurückzuführen
ist. Die Pull Down Konfiguration auf dem Board ist wohl nicht für Rising
Edge geeignet.
> jedenfalls ist das Problem für mich gelöst. Ich habe mein Testprogramm> als Grundgerüst, mit dem ich nun weiterarbeiten kann.> Gruß,> Jürgen
Grüße,
Frank