www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Interrupts richtig einsetzen


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

Bewertung
0 lesenswert
nicht lesenswert
Schönen guten Morgen zusammen,

wollte meine Frage vom 20.12.2006 16:25 nochmal verkürzt formulieren. 
Würde gerne den ADC mit höchster Priorität durch den AIC "triggern", 
während "im Hintergrund" kontinuierlich Nebensächliche Programmschritte 
ablaufen. Häng irgendwie total fest. Was könnte ich denn Dummes 
vergessen haben oder falsch gemacht haben, bin leider blutiger Anfänger 
bzgl. µC? Welche grundsätzliche Ablauf ist bei Interrupts wichtig?

Vielen, vielen Dank auf jedenfall schon mal für eure Mühen,


euer Max

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Max wrote:

> bin leider blutiger Anfänger
> bzgl. µC?

Dann hätte ich nicht gleich mit nem 32Bit-Boliden mit tausendenden 
Seiten Datasheet, Usermanual, Core- und Peripheriebeschreibung 
angefangen.
Man wird sprichwörtlich erschlagen damit.
Und das Erlernen des effektiven Programmierens wird stark erschwert.


Allgemein sollte man erstmal den Core-Typ, das konkrete Derivat, den 
Compiler, die IDE nennen, denn Gedanken lesen ist anstrengend.


Ich weiß ja nicht, wie schnell der Interrupt ist, aber darin ne Divison 
auf ner CPU ohne Divisionsbefehl ist Ober-bäh.


Peter

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry,

bei meinem ersten Eintrag hatte ich ein paar mehr Infos angefügt. Ist 
das Olimexboard SAM7-H64 mit dem AT91SAM7S64 von Atmel. Ich verwende den 
WinARM und Dev-C++ als Umgebung.
Leider MUSS ich mit dem 32bit-er arbeiten, ist ne Studienarbeit :-/ Hab 
mich schon intensiv mit dem Verhalten befasst, komm auch gut voran, nur 
eben mit diesem Interruptbereich bin ich mit meinem Latein seit en paar 
Tagen am Ende.

Die Modulo-Division wär nicht wirklich nötig, könnte ja einfach 
langsamer Interrupten und dann direkt die Fkt. aufrufen, oder?

Mit IRH_Entry und ...Exit kannst du mir nicht zufällig weiterhelfen?


VG Max

Autor: antworter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also generell kann ich wenig helfen (habe diesen uC nie benutzt)

aber:

(1) check mal deine Syntax - der Begriff "NACKEDFUNC" sollte bestimmt 
"NAKEDFUNC" heißen

(2) google mal nach "at91sam7 examples interrupt download". Gleich der 
erste Eintrag ist super

(3) In solchen Fällen erstmal Interrupts weglassen, dann das Ganze mit 
Polling zum laufen bringen, dann mit Polling aber gesetzter 
"Signal-/Statusvariable" im Interrupt und dann mit komplettem Interrupt

/ hoffe geholfen zu haben

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke schon mal für die Antworten,

wie funktioniert denn das Polling einer Fkt. genau?

... dann mit Polling aber gesetzter "Signal-/Statusvariable" im 
Interrupt?

was ist damit denn genau gemeint?


VG Max

Autor: antworter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
du setzt im interrupt nur eine variable, die dann anzeigt, daß ein 
interrupt aufgetreten ist (z.b. ereignis = 1) wobei die variable global 
und volatile ist

z.b.: volatile uint8_t ereignis;

in der hauptschleife wartest du dann, und reagierst, sobald sich die 
variable ändert:

while(1)
{
  while(ereignis != 1);   // warte auf ereignis == 1
  ereignis = 0;           // variable zurücksetzen

  meine_aktion();         // nun das tun, was später der INT macht
}

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

Bewertung
0 lesenswert
nicht lesenswert
Hab das Bsp. jetzt mal nachgebaut und in meinen Programmablauf 
integriert. Leider stehe ich nach wie vor vor dem gleichen Problem. 
Sobald der Interrupt aktiviert wird, geht gar nichts mehr, sprich ich 
käme gar nicht in die oben vorgeschlagene while(1)-Schleife :-/

Hab jetzt den ganzen Nachmittag auch mit dem Interrupt-Beispiel von 
dieser Seite gespielt, dieses ist zwar anders aufgebaut ( Triggert 
mittels TC ), aber immer noch das gleiche Problem. Die auskommentierte 
Zeile hab ich in der main-Schleife unmittelbar vor meiner 
while(1)-Schleife eingefügt.

Hab mal meine aktuelle Version angefügt?!


Mit bitte um weitere Ratschläge,

Max

Autor: antworter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
- ich kann keine main() entdecke
- ereignis muß global sein (ist momentan lokal)
- ereignis wird nirgends gepollt

Autor: Philipp Burch (philipp_burch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Je nach Controller und Compiler kann es erforderlich sein, ein 
Interrupt-Flag nach dessen Abarbeitung händisch zu löschen. Vielleicht 
müsste das noch rein.

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

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,
hallo Philipp,

herzlichen Dank für die Nachrichten. Die main () hab ich schon 
integriert, aber nicht dem Code.txt beigefügt. Hab aber jetzt auch das 
noch mit angefügt (Neuer-Code.txt), da lösche ich doch das 
Interrupt-flag "ereignis" händisch, oder?

Kann es auch ein Timing- oder Taktproblem sein? Mein Problem ist, dass 
der ARM WEDER die Interruptroutine NOCH die main-Schleife weiter 
ausführt, sondern schlichtweg hängen bleibt, bzw. nur noch interruptet?!

Ich hoffe auf weitere gute Ideen von euch,


VG euer Max

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habs jetzt zum Ausschluss von Fehlern/Defekten der Hardware auf ein 
Eval-Board gespielt. da läufts komplett gleich ab.

Das Verhalten ist folgendes:

Die Main-Schleife läuft an, zunächst Initialisierungen etc. (LED1 
blinkt!). Dann kommt unmittelbar vor der while(1)-Schleife noch der 
AIC-Enable. Die Interruptfkt. wird genau ein Mal angestossen (LED2 
blinkt genau ein Mal!!!).
Dannach würde in der while(1)-Schleife die LED1 blinken, das passiert 
allerdings nicht mehr.

Warum stößt der Interrupt nur EIN MAL die Fkt. an und hängt dannach 
alles andere auf??????

Ich hoffe sehnlichst auf einen heißen Tipp ;-)

VG Max

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Könnte es nicht sein, dass ISR_ENTRY() das absolut unbedingt erste 
codeerzeugende Statement einer ISR sein muss?

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum eigentlich NAKEDFUNC/ISR_ENTRY statt des dafür vorgesehenen 
__attribute__((interrupt("IRQ")))? Letzteres hatte zwar früher einen 
Bug, sollte heute aber ok sein.

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab mit den Fkt. ISR_ENTRY und ISR_EXIT auch schon herumprobiert. Das 
einzige, was sich verändert, ist dass er jetzt nicht mal mehr bis an die 
Stelle LED2 kommt, solange ISR_ENTRY() davor steht ???

Was ist denn genau mit __attribute__((interrupt("IRQ"))) gemeint?

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
=> GCC Doku.

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aber das ändert doch eigentlich nichts an dem prinzipiellen Problem, 
dass er nur einmal in die durch den Interrupt aufgerufene Fkt. geht und 
in dieser lediglich den ersten Befehl (LED2 Ein-Aus) abarbeitet, obwohl 
nachfolgend lediglich dieser Befehl wiederholt wird?

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Code der ausgeführt wird, bevor die Register gesichert werden, richtet 
Schaden an.

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und an welcher Stelle werden genau die Register gesichert? Ist doch noch 
im Bereich der AIC-Initialisierung, oder? Mich wundert, dass die Fkt. 
nicht mal zu Ende gearbeitet wird, die der Interrupt aufruft.
Zumindest müsste dass aber doch bei jedem neuen Interrupt bis zu der 
Stelle ständig wiederholt laufen?!

Verhalten:
LED1 blinkt 4 mal ( Inits OK?! ), danach nur EIN EINZIGES MAL KURZ LED2 
( Interrupt kommt nur einmal und hängt dann? )

Das momentane Code-Bsp. hab ich nochmal angefügt!

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

Bewertung
0 lesenswert
nicht lesenswert
ANHANG! ;-)

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Um mal Peter zu zitieren: "Dann hätte ich nicht gleich mit nem 
32Bit-Boliden mit tausendenden Seiten Datasheet, Usermanual, Core- und 
Peripheriebeschreibung angefangen."

Dir fehlen elementare Grundlagen der Interrupt-Programmierung, 
entsprechend betreibst du dabei Blindflug.

Es ist sehr hilfreich, wenn man mal Interrupts in Assembler programmiert 
hat. Dann erschliesst sich einem der Sinn von dem ganzen Zirkus mit 
__attribute__((interrupt("IRQ"))), __attribute__((naked)), ISR_ENTRY() 
usw nämlich erst so richtig. Nur sollte man damit nicht grad beim ARMs 
beginnen.

Eine Interrupt-Routine muss alle benutzten Register vor Verwendung 
sichern. Entweder indem die Routine als solche gekennzeichnet wird 
__attribute__((interrupt("IRQ"))) oder indem man dem Compiler sagt, dass 
man alles selber macht __attribute__((naked)) aka NAKEDFUNC und das dann 
mit ISR_ENTRY/EXIT auch an der richtigen Stelle macht. Sehr hilfreich 
kann es dabei sein, den entstehenden Assembler-Code zu verstehen.

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke dennoch für deine Antworten,

leider werde ich vom ARM nicht loskommen, ist nun mal ne vorgegebene 
Studienarbeit. Mit Assembler hatte ich in der Tat noch nie etwas zu tun. 
Gibt es da gerade im Hinblick auf Interrupts Bsp., über die man sich 
langsam herantasten kann?

Brauch ja ne vernünftige Beschäftigung während den Feiertagen ;-)

Frohes Fest,

Max

Autor: antworter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mal ein hinweis:

wie oft feuert denn dein timer interrupt pro sekunde ?

deine ereignisfunktion/int-handler ist ja voller warteschleifen... das 
sollte man in einer interruptfunktion unbedingt vermeiden

mach es lieber so, daß der interrupt alle paar hundert ms feuert, und du 
in der ereignisfunktion/int-handler nur den pin umschaltest

also in etwa so ein verhalten:

  - int kommt: led aus
  - int kommt: led an
  - int kommt: led aus

usw.

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die Antwort,

die Delays sind lediglich aufgrund meiner 1000 Versuche, das Ding zum 
Laufen zu bringen, hinzugekommen ;-) Die Brauch ich später auch nicht. 
Der TC wird mit MCK/1024 betrieben ( MCK ~ 48MHz ), dieser hat einen 
16bit Counter. Immer bei Inkrementierung sollte der interrupten. Da komm 
ich auf so ca. 1,4 sec.

Mit Pin-Umschaltung wird auch lediglich der aller erste Interrupt 
angestoßen?!

VG Max

Autor: antworter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Mit Pin-Umschaltung wird auch lediglich der
>aller erste Interrupt angestoßen?!

Der Interrupt wird durch den Timer ausgelöst, und die Interrupt-Routine 
(bei Dir "Ereignisfunktion") toggelt die LED.

Autor: antworter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ach übrigens:

viele übersehen wichtige Parameter des Timers, da diese oftmals mehrere 
Funktionen zur Verfügung stellen.

Deshalb ist es immer sinnvoll in solchen Fällen das Kapitel über den 
Timer im Datenblatt nochmal durchzugehen:

Wichtige Stichpunkte: Überlaufverhalten, Interrupt-Maske etc.

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.