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!
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.
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.
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.
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.
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.
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. :-)
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!
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 denAVR. 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!
StuporInterruptus schrieb:> Es gibt nicht denAVR. 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.
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.