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 Jürgen, könntest Du den kompletten Source Code als Datei dranhängen ? Gruß, Frank
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
... und hier die Version mit USART wie sie bei mir läuft ... Gruß, 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
1 | sei(); |
2 | |
3 | // Init environment
|
4 | |
5 | init_ports(); |
6 | init_usart(); |
7 | init_interrupt(); |
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...
STK500-Besitzer schrieb:
>
1 | >
|
2 | > sei(); |
3 | >
|
4 | > // Init environment |
5 | >
|
6 | > init_ports(); |
7 | > init_usart(); |
8 | > init_interrupt(); |
9 | >
|
10 | >
|
> > 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!
> Ihr redet aneinander vorbei
Jetzt bin ich auch drauf reingefallen...
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?"
Rolf Magnus schrieb: > Das stimmt. Es wird nämlich nicht vom GCC, sondern vom Prozessor selbst > bereits gemacht. AVRs sichern SREG nicht von sich aus.
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
Super Tipp!!! ATOMIC_BLOCK (ATOMIC_RESTORESTATE){} hat auch mit bei INT1 geholfen. Danke Karsten
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.