Forum: Mikrocontroller und Digitale Elektronik Interrupts richtig einsetzen


von Max (Gast)


Angehängte Dateien:

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

von Peter D. (peda)


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

von Max (Gast)


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

von antworter (Gast)


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

von Max (Gast)


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

von antworter (Gast)


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
}

von Max (Gast)


Angehängte Dateien:

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

von antworter (Gast)


Lesenswert?

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

von Philipp B. (philipp_burch)


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.

von Max (Gast)


Angehängte Dateien:

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

von Max (Gast)


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

von A.K. (Gast)


Lesenswert?

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

von A.K. (Gast)


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.

von Max (Gast)


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?

von A.K. (Gast)


Lesenswert?

=> GCC Doku.

von Max (Gast)


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?

von A.K. (Gast)


Lesenswert?

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

von Max (Gast)


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!

von Max (Gast)


Angehängte Dateien:

Lesenswert?

ANHANG! ;-)

von A.K. (Gast)


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.

von Max (Gast)


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

von antworter (Gast)


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.

von Max (Gast)


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

von antworter (Gast)


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.

von antworter (Gast)


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.

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
Noch kein Account? Hier anmelden.