Forum: Mikrocontroller und Digitale Elektronik ATMega8 Interrupts extrem langsam


von Sebastian T. (xheli)


Lesenswert?

Hallo,

ich beschäftige mich seit einige Teit mit den ATMega8 und habe im 
aktuellen Projekt das Problem, das der Interrupt (INT0) eine extrem 
lange Ausführungszeit hat.
Konkret versuche ich ein Taktsignal (Messschieber) von 83KHz zu tasten. 
Bei jeder fallenden Flanke wird der Interrupt ausgelöst, der zu 
Testzwecken keinerlei Anweisungen beeinhaltet. Durch Togglen eines Ports 
in der Hauptschleiche (die auch nur das macht und nichts anderes), sehe 
ich das der Interrupt zu einer Verzögerung von rund 73uS führt. Dies 
sind bei 8 MHz interner Taktung etwas über 600 Takte ! Dies erscheint 
mir extrem viel.
Ich nutze BASCOM. Ist das normal ? Gibt es hier gewisse Einstellungen, 
die man treffen muss ?

Gruß Sebastian

von J.-u. G. (juwe)


Lesenswert?

Da ich Dein Programm nicht kenne kann ich dazu nichts sagen. Aber Deine 
Rechnung verstehe ich nicht. Ein Signal von 80kHz hat alle 12.5µs (bzw. 
alle 100 Takte des 8MHz-Controllers) eine fallende Flanke. Wie kannst Du 
da eine Verzgerung von 73µs bzw. 600 Takte feststellen? Woher weißt Du 
auf welche Flanke des Signals Du Dich bei der Berechnung beziehen musst?

von Sebastian T. (xheli)


Lesenswert?

Hallo,

das komplette Programm kann ich heute Abend zur Verfügung stellen, hier 
mal die wichtgsten Sachen:
1
on INT0 InterruptHandler
2
3
do
4
   toggle portb.2
5
loop
6
end
7
8
InterruptHandler:
9
return

Das Taktignal liegt an INT0-Pin an und das Osszi am Port B2.
Daher sehe ich ja wie lange die Hauptschleife aussetzt. Heute Abend
mach ich davon mal ein Bild.

Gruß Sebastian

von Uwe (Gast)


Lesenswert?

> Ich nutze BASCOM. Ist das normal ?
Denke schon
Nimm doch mal C oder ASM

von Hannes L. (hannes)


Lesenswert?

Sebastian T. schrieb:
> Ich nutze BASCOM. Ist das normal ?

Ja, Bascom sichert bei Aufruf der ISR unsinnigerweise (fast) alle 
Register, auch wenn sie von der ISR nicht verwendet werden. Das 
dauert...

...

von Hannes L. (hannes)


Lesenswert?

Uwe schrieb:
> Nimm doch mal C oder ASM

Was meinst Du, warum er Bascom nimmt? Unabhängig davon kann man mit 
Bascom auch brauchbare Projekte realisieren, ein bissel 
Hintergrundwissen (zu dem auch die Architektur, also ASM gehört) schadet 
dabei aber nicht.

...

von Hannes L. (hannes)


Lesenswert?

Sebastian T. schrieb:
> sind bei 8 MHz interner Taktung etwas über 600 Takte !

Vergessen...

Bist Du sicher, dass der Mega8 mit 8 MHz rennt?

Ich vermute, dass er mit 1 MHz klappert, dann wären es etwa 75 Takte, 
was realistisch ist.

Hast Du den Takt per Fusebits eingestellt oder hast Du nur im Quelltext 
die Taktangabe verändert?

...

von Sebastian T. (xheli)


Lesenswert?

Hallo,

ich bin mir recht sicher, da ich es auf 8Mhz über die Fuses eingestellt 
habe (direkt im Studio). Wenn ich bspw folgenden Code verwende:
1
do
2
   toggle portb.2
3
loop
4
end

...dann komme ich auf ca. 1.2 MHz Rechtecksignal am Ozzi. Da der toggle 
Befehl vermutlich auch einige Takte benötigt erscheint es mir gerade 
noch logisch. Wenn ich auf 4MHz Fuse, dann komme ich auch auf noch länge 
Zeiten für den Interrupt.
Mich irritiert es extrem, da man überall was von 100 Takten zu lesen 
bekommt.

Gruß Sebastian

von J.-u. G. (juwe)


Lesenswert?

Sebastian T. schrieb:
> Mich irritiert es extrem, da man überall was von 100 Takten zu lesen
> bekommt.

Ja. Die Abstände der fallenden Flanken Deines 83kHz-Signals sind aber 
kürzer als 100 Takte. Dein µC kommt vor lauter Interrupts kaum noch zur 
Ausführung der Main-Funktion.

von Sebastian T. (xheli)


Lesenswert?

Hallo,

ja das ist sehr deprimierend, das der Interrupt so gigantisch lange 
braucht. Ich poste heute Abend mal Fotos davon. Es ist so das der 
Interrupt grobe 4-5 mal aufgerufen wird, wobei der Takt in der selben 
Zeit ca. 50 mal eine fallende Flanke aufweißt. Ohne Interrupt, mit 
pollen des Portzustandes komme ich immerhin auf ca. 40 von den 50 
Flanken.
Überall liest man, das die Interruptausführung 100 Takte dauert, bei mir 
sind es 600. Das kann irgendwie nicht hinkommen, aber das Ozzi lügt 
nicht.

Gruß Sebastian

von J.-u. G. (juwe)


Lesenswert?

Sebastian T. schrieb:
> Überall liest man, das die Interruptausführung 100 Takte dauert, bei mir
> sind es 600.

Wie kommst Du auf die 600? Du misst mit Deinem Oszi doch nur die 
Tätigkeit der Main-Funktion. Bevor diese es schafft, den Pin einmal zu 
toggeln, wird sie wohl 4-5 mal von Interrupts unterbrochen (die dann 
meinetwegen jeweils 100 Takte dauern). Mehr kannst Du doch mit Deinem 
Messaufbau gar nicht nachprüfen.

von Ccccc (Gast)


Lesenswert?

Kann BASCOM kein ASM-Listing rausgeben?
Das sollte doch erklären wie's läuft.

von J.-u. G. (juwe)


Lesenswert?

Ccccc schrieb:
> Kann BASCOM kein ASM-Listing rausgeben?
> Das sollte doch erklären wie's läuft.

Genau. Das und ein Oszibild. Dann hat die Spekuliererei ein Ende.

von Bloofart (Gast)


Lesenswert?

> Ich vermute, dass er mit 1 MHz klappert, dann wären es etwa 75 Takte,
> was realistisch ist.

1 MHz geteilt durch 83 KHz ergibt rund 12.

von Hannes L. (hannes)


Lesenswert?

Bloofart schrieb:
> 1 MHz geteilt durch 83 KHz ergibt rund 12.

Meine Aussage bezog sich aber nicht auf 83 kHz, sondern auf 600 Takte. 
Und die Zeitdauer der 600 Takte bei vermuteten 8 MHz entspricht etwa der 
bei realen 1 MHz.

Aber das ist es ja nicht, wie uns bereits bewiesen wurde. Da bleibt nur 
noch, wie bereits erwähnt, dass die ISR aufgrund der kompletten 
Registersicherung zu langsam für die Anwendung ist.

Abhilfe könnte der ISR-Aufruf mit dem Parameter "nosave" schaffen, dann 
muss man die benutzten Register aber selbst sichern und 
wiederherstellen. Dazu ist dann aber wieder etwas Wissen darüber 
erforderlich, wie Bascom intern (auf ASM-Ebene) arbeitet...

...

von Jonas B. (jibi)


Lesenswert?

Hast du überhaupt ein externes Quarz angeschlossen? Das würde alles 
erklären.

Gruß
J

von Bernd S. (bernds1)


Lesenswert?

Jonas Biensack schrieb:
> Hast du überhaupt ein externes Quarz angeschlossen? Das würde alles
> erklären.
>
> Gruß
> J

Erstens das, und dann reicht es auch nicht, wenn der Quarz (egal ob 
intern oder extern) auf 8 MHz läuft. Man muß auch noch CKDIV8 
zurücksetzen, damit nicht die 8 MHz durch 8 geteilt werden. Das würde 
bedeuten, man hat doch nur 1 MHz. Schau dort mal nach...

von Spess53 (Gast)


Lesenswert?

Hi

>Man muß auch noch CKDIV8
>zurücksetzen, damit nicht die 8 MHz durch 8 geteilt werden.

Kleiner Schönheitsfehler: Der ATMega8 hat keine CKDIV8-Fuse.

MfG Spess

von Bernd S. (bernds1)


Lesenswert?

Ok, mein Fehler. Ich bin vom Mega88 ausgegangen, der hat sie.
Ich nehm' alles zurück :-)

Gruß Bernd

von Sebastian T. (xheli)


Angehängte Dateien:

Lesenswert?

Hallo,

anbei die Screenshots. Das Gelbe ist das Signal des Messchiebers. Das 
Grüne der Ausgang PB2. Das Ganze in verschiedenen Zoomstufen. Hier der 
Code:
1
$regfile = "m8def.dat"
2
$crystal = 8000000
3
$baud = 9600
4
5
on INT0 OnInterrupt
6
7
DDRB.2 = 1                              'Oszi-Kontrollausgang
8
9
DDRD.2 = 0                              'INT 0
10
MCUCR = &B00000010                      'int 0 fallende flanke
11
GICR = &B01000000                       'int 0 aktivieren
12
13
SREG.7 = 1                              'interrupts ein
14
15
Do
16
 toggle portb.2
17
Loop
18
19
OnInterrupt:
20
return
21
22
End

Das mit dem Nosave werde ich probieren.

Mir ist da gerade was aufgefallen. In dem 2.Screenshot rechts bei der 
letzten fallenden Flanke ist der Hauptschleifenausetzer wesentlich 
geringer und damit die Interruptausführzeit. Mein Messmethode hat hier 
vermutlich einen Fehler. Der Interrupt wird bestimmt direkt 
hintereinander ausgelöst und es erscheint die lange Abarbeitungszeit in 
der Phase der "dichten" Clock.


Gruß Sebastian

von J.-u. G. (juwe)


Lesenswert?

Sebastian T. schrieb:
> n dem 2.Screenshot rechts bei der
> letzten fallenden Flanke ist der Hauptschleifenausetzer wesentlich
> geringer und damit die Interruptausführzeit.

Zumindest kannst Du da sehr schön ablesen, wie lange es von der 
fallenden Flanke bis zum Toggeln des Pins dauert. Und diese Zeit ist 
etwas größer als der Abstand zweier fallender Flanken. Deine 
main-Funktion schafft es also nicht in der Zeit zwischen zwei 
Interrupts, alle für das toggeln des Pins erforderlichen Operationen 
durchzuführen (sie wird immer wieder unterbrochen). Erst nach fünf- oder 
sechsmaligem Ausführen der ISR, ist endlich der Pin getoggelt.

von Sebastian T. (xheli)


Lesenswert?

Hallo,

nach Korrektur meiner Messmethode komme ich nun ohne NoSave auf rund 125 
Takte und mit NoSave und Nutzung von Assembler im Interrupt auf 100 
Takte. Kann das normal sein ? Die Interruptfunktion sieht nun so aus:
1
OnInterrupt:
2
   push R16
3
   push R17
4
   in R16,SREG
5
   push R16
6
   in R16,portB                         'PortB invertieren
7
   ldi R17,4                            'XOR Bit 2 (2^2)
8
   eor R16,R17
9
   !Out PortB , R16
10
   pop R16
11
   !Out Sreg , R16
12
   pop R17
13
   pop R16
14
return

Was macht er in der restlichen Zeit ? Der Assemblercode sind ja nicht 
100 Takte.

Gruß Sebastian

von tobi (Gast)


Lesenswert?

Int0 Flanke oder Pegel?

von Sebastian T. (xheli)


Lesenswert?

Hallo,

auf fallende Flanke eingestellt.

Gruß Sebastian

von Hola (Gast)


Lesenswert?

Sebastian T. schrieb:
> Was macht er in der restlichen Zeit ? Der Assemblercode sind ja nicht
> 100 Takte.

Schon mal den Simulator probiert?

von hins (Gast)


Lesenswert?

Wieso schreibst du das Togglen des Ports nicht einfach direkt in die 
Interrupt-Routine? Oder geht es dir darum, zu wissen, wie lange der 
Interrupt braucht bis er das Programm wieder in der  main-Funktion 
ackert?

von Peter D. (peda)


Lesenswert?

Sebastian T. schrieb:
> Dies
> sind bei 8 MHz interner Taktung etwas über 600 Takte !

Die 600 Zyklen kannst Du in der Pfeife rauchen, die stimmen nicht.

Sobald der Handler zu lange dauert, wird sofort wieder ein Interrupt 
ausgeführt. Dazwischen führt das Main nur einen Befehl aus.

Die Pin-Toggle-Loop dauert n Befehle, also sind die 600 Zyklen die Dauer 
von n Interrupts und nicht nur eines einzigen.
Ein Interrupt dauert also (600-1) / n.

Wie groß n ist, kannst Du ermitteln, indem Du die Interrupts sperrst 
oder die 83kHz abschaltest.

von Peter D. (peda)


Lesenswert?

Um die Dauer nur eines Interrupts zu ermitteln geht auch:

Loop:
sei
setze Pin
<- hier haut nun der Interrupt rein
cli
lösche Pin

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.