Forum: Mikrocontroller und Digitale Elektronik AVR: Polling von EIFR Register "verpasst" Flanken auf Pin


von mpunkt (Gast)


Lesenswert?

Hallo!

Ich möchte durch kontinuierliche Abfrage des EIFR Registers Flanken auf 
einigen Pins (innerhalb int0 - 7) erkennen. Leider verpasse ich dabei 
Flanken, was darauf hindeutet, dass ich irgendetwas grundsätzlich am 
Umgang mit diesem Register falsch verstanden habe und in Folge falsch 
mache.

Sprache ist Bascom, der zentrale Teil ist als Inline Assembler 
eingebaut. Zur Verdeutlichung des Problems habe ich den Code wie folgt 
eingekocht:
1
$regfile = "m128can.dat"
2
$crystal = 16000000
3
$framesize = 64
4
$swstack = 64
5
$hwstack = 64
6
7
Config Portb.6 = Output
8
led1  Alias Portb.6
9
10
Config PORTE.4 = input
11
12
' Hochkommata leiten Kommentare ein
13
14
' INT0 - 3: dir input pin change
15
EICRA = &b01010101
16
' INT4 - 7: step input pin change
17
EICRB = &b01010101
18
19
' enable INT4 but no ISR (direct evaluation of EIFR register)
20
enable int4
21
enable interrupts
22
23
$asm
24
25
main_loop:
26
   IN R16, EIFR
27
   OUT EIFR, R16
28
   ' no bit in EIFR set -> nothing happend on the pins
29
   CPI R16, 0
30
   BREQ main_loop
31
32
tst_dir_change:
33
   SBI PORTB, 6
34
   NOP
35
   NOP
36
   NOP
37
   NOP
38
   NOP
39
   NOP
40
   CBI PORTB, 6
41
42
loop_end:
43
   RJMP main_loop
44
45
$end asm
46
47
end

Auf E.4 liegt ein Rechteck mit ca 2.5 kHz. Ich würde nun erwarten, dass 
Pin B.6 mit ca 5 kHz "pulst", weil über EICRB definiert ist, dass bei 
jeder Flanke (pos. und neg.) der Interrupt kommt, also zu 
"tst_dir_change" gesprungen wird. Tatsächlich kommt nur bei ca. 50-60% 
der tatsächlichen Flanken auf E.4 auch ein Puls auf B.6 (grob 
abgeschätzt beim Blick aufs Oszi). Wann eine Flanke erkannt wird und 
wann nicht, sieht nach Zufall aus.

Den Umgang mit EIFR hatte ich so verstanden, dass ich unmittelbar nach 
Auslesen des Registers seinen Inhalt wieder zurückschreiben kann, um 
durch Setzen(!) der Bits, die eine erkannte Flanke anzeigen, den 
entsprechenden Interrupt wieder "scharf" zu machen. Daher das
1
   IN R16, EIFR
2
   OUT EIFR, R16

Vielleicht noch eine Zusatzinfo: wenn ich die Bascom high-level Funktion 
nutze, um eine ISR durch einen externen Interrupts auszulösen, 
funktioniert das Ganze wie erwartet und keine Flanke am Eingang wird 
übersehen. Ich denke deswegen, dass ich das EIFR Register irgendwie 
falsch verwende.

Ich bin sehr dankbar für alle Hinweise!

von S. Landolt (Gast)


Lesenswert?

Ich habe keine Ahnung von Bascom, aber ich vermute, das enable int4 
ist zuviel, mal weglassen und schauen, was passiert.

von mpunkt (Gast)


Lesenswert?

Das "enable int4" setzt nur das entsprechende Bit im External Interrupt 
Mask Register (EIMSK). Wenn ich die Zeile weglasse, wird der entspr. 
Interrupt nicht mehr ausgelöst.

von S. Landolt (Gast)


Lesenswert?

> Wenn ich die Zeile weglasse, wird der entspr.
> Interrupt nicht mehr ausgelöst.
D.h. Sie sehen jetzt am Oszilloskop gar keinen Impuls mehr?

von StuporInterruptus (Gast)


Lesenswert?

mpunkt schrieb:

Ich will mal mit diesem Satz von Dir anfangen:

> Vielleicht noch eine Zusatzinfo: wenn ich die Bascom high-level Funktion
> nutze, um eine ISR durch einen externen Interrupts auszulösen,
> funktioniert das Ganze wie erwartet und keine Flanke am Eingang wird
> übersehen. Ich denke deswegen, dass ich das EIFR Register irgendwie
> falsch verwende.

Das wirft die Frage auf, warum und zu welchem Zweck Du das 
Interrupt-Flag pollen willst. Da bin ich ganz neugierig.

Meiner Einschätzung nach, dürfte das die exotischste Frage sein, die je 
in einem Mikrocontroller-Forum gestellt wurde. Aber von Bedeutung ist 
das nicht.

Zunächst beisst Du Dir mit aller Gewalt selbst in's Knie und wunderst 
Dich, dass ein Verband am Ohr die Blutung nicht stillt. So will ich das 
mal metaphorisch zusammenfassen.

1. Falls ich mich nicht irre - leider ist der Mikrocontroller-Typ nicht 
bekannt, wenn auch aus der Bezeichnung EIFR abzuleiten ist, dass es sich 
um einen der AVRs handelt, wird das Interruptflag einer I/O-Einheit dann 
gesetzt wenn seine Bedingung zutrifft UND das entsprechende Enable-Flag 
gesetzt ist. Aber es könnte sein, dass das noch vom globalen 
Interrupt-Flag abhängt. Da niemand das so macht, wie Du es versuchst, 
weiß ich das schlicht nicht, meine aber dunkel sowas gelesen zu haben. 
Das kann ich aber im Detail nicht prüfen, da der Typ nicht bekannt ist.
2. Dein Code hat aber, vorausgesetzt, das globale Interrupt-Enable-Flag 
wird nicht gelöscht, zur Folge, dass auch die entsprechende 
Interrupt-Routine angesprungen wird. Das Flag wird aber nirgendwo 
gelöscht. Da Du aber keine ISR definiert hast, landet der uC irgendwo im 
Wald. Mich wundert dann, dass da überhaupt irgendwas sinnvolles 
passiert. Aber ich mag mich im Detail irren oder das ist genau die 
Fehlersituation, die Du beschreibst.
3. Dazu ist leider unbekannt, auf welche Weise Du den entsprechenden 
Port-Pin beeinflusst.
4. Diese Mixtur von Basic und Assembler lässt einiges im Dunklen, denn 
es ist (zumindest mir) unklar, was Bascom da noch im Untergrund 
herumbohrt. Ich empfehle Dir, daher entweder ganz in BASIC oder ganz in 
Assembler zu schreiben.

Der nächste Schritt wäre aus meiner Sicht also:
1. Nenne uns den Typen.
2. Beschreibe, wie Du den Port-Pin zum Test beeinflusst. Schaltung.

von Volker B. (Firma: L-E-A) (vobs)


Lesenswert?

mpunkt schrieb:
> Das "enable int4" setzt nur das entsprechende Bit im External Interrupt
> Mask Register (EIMSK). Wenn ich die Zeile weglasse, wird der entspr.
> Interrupt nicht mehr ausgelöst.

Bist Du Dir sicher, dass Du wirklich die Interrupts freigeben willst? 
Dann solltest Du aber auch entsprechende Interrupthandler anlegen, 
ansonsten können lustige Dinge passieren, wenn der Compiler keine(n) 
Dummy-Handler anlegt.

Die Interruptflags werden aber auch gesetzt, wenn der zugehörige 
Interrupt nicht freigegeben ist. Ich würde also stark vermuten, dass Du 
die Interrupts nicht freigeben solltest.

Grüßle,
Volker.

von MWS (Gast)


Lesenswert?

Lass das enable Int4 weg. Selbst ohne ISR wird mit enabeltem Interrupt 
der entsprechende Vektor in der IVT ausgeführt, wobei am Vektor einfach 
ein RETI steht. Das Ganze reicht jedoch, um das entsprechende 
Interruptflag zu löschen. Tritt der Interrupt gerade bei IN R16, EIFR 
ein, so wird dieser Befehl noch abgearbeitet, erst dann in die ISR 
gesprungen und das Flag gelöscht. So kann manchmal  eine Flanke erkannt 
werden.

von S. Landolt (Gast)


Lesenswert?

In Ergänzung zu MWS der Standardsatz aus dem Datenblatt:
"The flag is cleared when the interrupt routine is executed. 
Alternatively, the flag can be cleared by writing a logical one to it."
D.h. ISR und Ihr Polling&Rücksetzen konkurrieren, und so etwas ist m.E. 
nie sinnvoll.

von StuporInterruptus (Gast)


Lesenswert?

Volker B. schrieb:
>
> Die Interruptflags werden aber auch gesetzt, wenn der zugehörige
> Interrupt nicht freigegeben ist. Ich würde also stark vermuten, dass Du
> die Interrupts nicht freigeben solltest.

Ich habe gerade mal im Datenblatt vom 162 nachgeschaut. Der Satz ist aus 
meiner Sicht nicht völlig klar:

"When a logic change on any PCINT15..8 pin triggers an interrupt 
request,
..."

Er beinhaltet als Voraussetzung, dass ein Interrupt-Request ausgelöst 
wird. Ein "Interrupt-Request" ist allerdings nicht eigentlich definiert. 
In sämtlichen Kontexten in dem Dokument, wird impliziert, dass die 
Interrupt-Routine angesprungen wird, falls das globale Interrupt-Flag 
gesetzt ist.

Ich meine aber auch - wie ich oben schrieb -, dass die spezifischen 
Interrupt-Flags auch dann gesetzt werden wenn zumindest das globale 
I-Flag gelöscht ist. Müsste man mal ausprobieren. Ich weiss nur noch 
nicht wozu. :-)

von mpunkt (Gast)


Lesenswert?

Hallo!

Ich muss mich entschuldigen! Das Weglassen von "enable Int4" führt DOCH 
zum Erfolg! Und nach Euren Ausführungen verstehe ich auch warum!

nur noch kurz an @StuporInterruptus:

Controller ist in der Tat ein AVR, steht im Betreff des Threads. Ich 
möchte die angesprochene Methode ohne ISRs verwenden, weil ich mir damit 
die Zeit des "Gespringes" spare. Es geht mir nur darum, keine Flanke zu 
verpassen, das EIFR Register dient - grob gesprochen - nur als Puffer. 
Ohne das Enable funktionierts nun augenscheinlich auch.

Vielen Dank!

von StuporInterruptus (Gast)


Lesenswert?

mpunkt schrieb:
> Hallo!
>
> Ich muss mich entschuldigen! Das Weglassen von "enable Int4" führt DOCH
> zum Erfolg! Und nach Euren Ausführungen verstehe ich auch warum!
>
> nur noch kurz an @StuporInterruptus:
>
> Controller ist in der Tat ein AVR, steht im Betreff des Threads. Ich
> möchte die angesprochene Methode ohne ISRs verwenden, weil ich mir damit
> die Zeit des "Gespringes" spare. Es geht mir nur darum, keine Flanke zu
> verpassen, das EIFR Register dient - grob gesprochen - nur als Puffer.
> Ohne das Enable funktionierts nun augenscheinlich auch.
>
> Vielen Dank!

Es gibt nicht den AVR. Es gibt mehrere und viele haben kein 
EIFR-Register, bzw. mehr oder weniger leicht abweichendes Verhalten. 
Also, bitte nicht so oberschlau. Das hat schon seinen Sinn, wenn ich 
nach dem Typ frage. Du hast den Typ schlicht nicht genannt.

Mach Deinen Scheiss das nächste Mal alleine, Pfeife!

von StuporInterruptus (Gast)


Lesenswert?

Na toll. Jetzt steht da noch "m128can" im Quelltext. Selber Pfeife.

von c-hater (Gast)


Lesenswert?

StuporInterruptus schrieb:

> Es gibt nicht den AVR. Es gibt mehrere und viele haben kein
> EIFR-Register

Die haben dann Register mit anderen Namen. Das spielt überhaupt keine 
Rolle für die Funktion der IRQ-Bits. Namen sind Schall und Rauch. 
Natürlich sollte man in einem Programm die korrekten Namen sowohl für 
Register als auch für Bits darin verwenden. Aber das ist nicht der 
Punkt.

> bzw. mehr oder weniger leicht abweichendes Verhalten.

Das genau ist eben nicht der Fall. Es gibt genau zwei Sorten von 
IRQ-Bits bei der gesamten AVR8-Familie. Einmal die, die sich durch 
Schreiben einer 1 auf das entsprechende IRQ-Bit zurücksetzen lassen (um 
die geht es hier) und zum Anderen die, bei denen das Zurücksetzen an das 
Beschreiben oder Lesen irgendeines anderen Registers der zugehörigen 
Hardware gekoppelt ist (z.B.: die UART-IRQs außer TXC, das gehört schon 
wieder zu der ersten Sorte).

Bei denen, die man manuell durch Schreiben einer 1 zurücksetzen kann, 
kann das Zurücksetzen immer auch durch das ABARBEITEN des IRQ 
automatisch passieren. Sprich: in dem Moment, wenn der entsprechende 
Interruptvektor aufgerufen wird, wird auch das Flag zurückgesetzt.

Dementsprechend: wenn man manuell herumhantieren will, darf der 
entsprechende Interrupt nicht möglich sein, denn nur das garantiert, 
dass der Interupvektor nicht aufgerufen wird.

Dabei ist es völlig egal, ob der Interrupt dadurch nicht möglich ist, 
dass das entsprechende Bit im zugehörigen Maskenregister nicht gesetzt 
ist oder dadurch, dass Interrupts global verboten sind.

von mpunkt (Gast)


Lesenswert?

StuporInterruptus schrieb:
> Es gibt nicht den AVR. Es gibt mehrere und viele haben kein
> EIFR-Register, bzw. mehr oder weniger leicht abweichendes Verhalten.
> Also, bitte nicht so oberschlau. Das hat schon seinen Sinn, wenn ich
> nach dem Typ frage. Du hast den Typ schlicht nicht genannt.
>
> Mach Deinen Scheiss das nächste Mal alleine, Pfeife!

Ich kann nicht erkennen auch nur im Mindesten unhöflich Dir gegenüber 
gewesen zu sein. Ich sehe völlig ein, dass man vielleicht deutlicher auf 
den Controllertyp hätte hinweisen können, mit einer sozial derart 
inadäquaten Reaktion darauf disqualifizierst Du Deine Kritik und Dich 
allerdings vollständig.

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.