Forum: Compiler & IDEs Merkwürdiges Interrupt Jitter Problem bei ATxmega


von Simon K. (simon) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hi Leute!
Ich habe ein merkwürdiges Problem in einem großen Projekt mit einem 
ATxmega128a4u. Konnte das ganze jetzt aber stark eingrenzen.
Es geht darum, dass ich einen Timer Interrupt verwende um einen Pin zu 
toggeln. Das C-Programm habe ich angehangen mit der markierten 
Problemzeile in der Mainloop.

Kompilieren tu ich das Ganze mittels:
1
avr-gcc -c -mmcu=atxmega128a4u -fno-inline-small-functions -x c -Os -std=gnu99 Test.c -o Test.o
2
avr-gcc Test.o -o Test.elf -lm -mmcu=atxmega128a4u  
3
avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature Test.elf Test.hex
4
avr-objdump -h -d -S -z Test.elf > Test.lss

Nun ist das Resultat das folgende:
Ist die Problemzeile nicht auskommentiert, sehe ich auf dem Oszilloskop 
einen zufälligen Flankenjitter von etwa 250ns an dem PORTE.3 Pin, der in 
der ISR getoggelt wird. In dem großen Projekt hat es sogar für einen 
Jitter von mehreren Mikrosekunden gereicht!

Die resultierenden lss Dateien habe ich ebenfalls angehangen und durch 
ein diff laufen lassen. Neben den verschobenen Adressen ist der einzige 
Unterschied der zusätzliche rcall, der "Func" aufruft. Ohne die Zeile 
liegt der Jitter im einstelligen ns Bereich.
1
D:\Temp\Neuer Ordner>avr-gcc -v
2
Using built-in specs.
3
COLLECT_GCC=avr-gcc
4
COLLECT_LTO_WRAPPER=c:/programme/atmel/avr\ tools/avr\ toolchain/bin/../libexec/
5
gcc/avr/4.7.2/lto-wrapper.exe
6
Target: avr
7
Configured with: /data2/home/toolsbuild/jenkins-knuth/workspace/avr8-gnu-toolcha
8
in/src/gcc/configure LDFLAGS=-L/home/toolsbuild/jenkins-knuth/workspace/avr8-gnu
9
-toolchain/avr8-gnu-toolchain-win32_x86/lib CPPFLAGS= --target=avr --host=i686-p
10
c-mingw32 --build=x86_64-pc-linux-gnu --prefix=/home/toolsbuild/jenkins-knuth/wo
11
rkspace/avr8-gnu-toolchain/avr8-gnu-toolchain-win32_x86 --libdir=/home/toolsbuil
12
d/jenkins-knuth/workspace/avr8-gnu-toolchain/avr8-gnu-toolchain-win32_x86/lib --
13
enable-languages=c,c++ --with-dwarf2 --enable-doc --disable-shared --disable-lib
14
ada --disable-libssp --disable-nls --with-mpfr=/home/toolsbuild/jenkins-knuth/wo
15
rkspace/avr8-gnu-toolchain/avr8-gnu-toolchain-win32_x86 --with-gmp=/home/toolsbu
16
ild/jenkins-knuth/workspace/avr8-gnu-toolchain/avr8-gnu-toolchain-win32_x86 --wi
17
th-mpc=/home/toolsbuild/jenkins-knuth/workspace/avr8-gnu-toolchain/avr8-gnu-tool
18
chain-win32_x86 --enable-win32-registry=avrtoolchain --with-pkgversion=AVR_8_bit
19
_GNU_Toolchain_3.4.2_939 --with-bugurl=http://www.atmel.com
20
Thread model: single
21
gcc version 4.7.2 (AVR_8_bit_GNU_Toolchain_3.4.2_939)

Interessantes Problem oder? Hat irgendjemand nur eine ganz leichte 
Ahnung, was hier los ist? Im Moment stehe ich ein bisschen auf dem 
Schlauch. Irgendwas in Richtung Stack Overflow? Buggy Compiler?

Viele Grüße und Vielen Dank schon mal für irgendwelche Tipps.

: Bearbeitet durch User
von Simon K. (simon) Benutzerseite


Angehängte Dateien:

Lesenswert?

Es wird noch besser. Ein Versuch mit der avr toolchain 3.4.5 inlined 
sogar den Funktionsaufruf (Obwohl mit fno-inline-small-functions 
verboten - GRML), und das Problem besteht weiterhin! Durch einfaches 
Kommentieren der Problemzeile kann man den Jitter am Pin ein und 
ausschalten.

Siehe Anhang.
1
D:\Temp\Neuer Ordner>avr-gcc -v
2
Using built-in specs.
3
COLLECT_GCC=avr-gcc
4
COLLECT_LTO_WRAPPER=d:/programme/avrtoolchain/bin/../libexec/gcc/avr/4.8.1/lto-w
5
rapper.exe
6
Target: avr
7
Configured with: /home/jenkins/workspace/avr8-gnu-toolchain/src/gcc/configure LD
8
FLAGS=-L/home/jenkins/workspace/avr8-gnu-toolchain/avr8-gnu-toolchain-win32_x86/
9
lib CPPFLAGS= --target=avr --host=i686-pc-mingw32 --build=x86_64-pc-linux-gnu --
10
prefix=/home/jenkins/workspace/avr8-gnu-toolchain/avr8-gnu-toolchain-win32_x86 -
11
-libdir=/home/jenkins/workspace/avr8-gnu-toolchain/avr8-gnu-toolchain-win32_x86/
12
lib --enable-languages=c,c++ --with-dwarf2 --enable-doc --disable-shared --disab
13
le-libada --disable-libssp --disable-nls --with-avrlibc=yes --with-mpfr=/home/je
14
nkins/workspace/avr8-gnu-toolchain/avr8-gnu-toolchain-win32_x86 --with-gmp=/home
15
/jenkins/workspace/avr8-gnu-toolchain/avr8-gnu-toolchain-win32_x86 --with-mpc=/h
16
ome/jenkins/workspace/avr8-gnu-toolchain/avr8-gnu-toolchain-win32_x86 --enable-w
17
in32-registry=avrtoolchain --enable-fixed-point --with-pkgversion=AVR_8_bit_GNU_
18
Toolchain_3.4.5_1522 --with-bugurl=http://www.atmel.com
19
Thread model: single
20
gcc version 4.8.1 (AVR_8_bit_GNU_Toolchain_3.4.5_1522)

Das Problem lässt sich auch mit dem folgenden Code erzeugen:
1
    while(1) {
2
        asm volatile("nop"); // Problemzeile
3
    }

Das Ganze riecht irgendwie überhaupt nicht gut.

: Bearbeitet durch User
von eingast (Gast)


Lesenswert?

Vielleicht macht ja die Funktion in <Problemzeile> das Problem.

von Oliver S. (oliverso)


Lesenswert?

Der Prozessor beendet den aktuell laufenden Befehl, bevor er in die ISR 
springt. Wenn der Interrupt während des nop kommt, gibt es max. 1 Zyklus 
Verzögerung, kommt er dagegen während eines ret, können es auch 4 oder 5 
werden. (ich schau jetzt nicht extra nach).

Kannst ja mal mit deinem Prozessortakt nachrechen, ob das hinkommt.

Wenn du jitterfreies Pinwackeln haben willst, nimm die Hardware-PWM.

Oliver

von Simon K. (simon) Benutzerseite


Lesenswert?

eingast schrieb:
> Vielleicht macht ja die Funktion in <Problemzeile> das Problem.

Die Funktion enthält nur ein nop. Der von mir angehängte Quellcode ist 
komplett und kann so kompiliert werden.
Wie auch in meinem zweiten Post ersichtlich, reicht in der Problemzeile 
auch ein einfaches nop aus, um Jitter auf dem Pin zu erzeugen.

von Simon K. (simon) Benutzerseite


Lesenswert?

Oliver S. schrieb:
> Der Prozessor beendet den aktuell laufenden Befehl, bevor er in
> die ISR
> springt. Wenn der Interrupt während des nop kommt, gibt es max. 1 Zyklus
> Verzögerung, kommt er dagegen während eines ret, können es auch 4 oder 5
> werden. (ich schau jetzt nicht extra nach).

Hm, da hast du natürlich schon Recht. Es kommt ja auch ungefähr hin bei 
meinem Testprogramm.

In meinem großen Projekt sind es jedoch, wie gesagt schon Mikrosekunden 
Jitter, die dort erzeugt werden. Und in einer Mikrosekunde vergehen dann 
schon locker zig Takte, wo ich mich frage, was der Prozessor da in der 
Zeit macht?
Und das, obwohl nirgendwo Interrupts gesperrt werden und das der Einzige 
Interrupt mit HI Prio ist. Das habe ich im Disassemblat nachgeschaut.

Das ist wirklich merkwürdig.

Oliver S. schrieb:
> Wenn du jitterfreies Pinwackeln haben willst, nimm die Hardware-PWM.

Ist schon klar, dass das Pinwackeln nur zur Demonstration dienen soll...

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Simon K. schrieb:
> Das ist wirklich merkwürdig.

sleep?

Oliver

von Simon K. (simon) Benutzerseite


Lesenswert?

Oliver S. schrieb:
> Simon K. schrieb:
>> Das ist wirklich merkwürdig.
>
> sleep?
>
> Oliver

Leider nicht. Sobald ich den LUFA USB Stack in der Mainloop mitlaufen 
lasse, steigt der Jitter auf etwa 1µs an. Das wären um die 30 
Prozessortakte und das halte ich für zu viel.

Wie gesagt, habe den Code schon durchforstet, das geht bei dem LUFA 
Stack sehr gut. Allerdings habe ich nichts gefunden, was die Verzögerung 
von bis zu 30 Takten hervorrufen könnte. Interrupts werden definitiv 
nicht deaktiviert im normalen Betrieb (nur während der Enumeration 
kurzzeitig um die interne ID mittels NVM auszulesen). Und das Maximum, 
was durch die Opcodes hervorgerufen wird sind 5 Taktzyklen, also einiges 
unterhalb der zu beobachtenden Verzögerung.

Jetzt bin ich doch sehr ratlos. Das USB Modul funktioniert mit einem 
asynchronen 48MHz Takt. Gibt es hier vielleicht Verzögerungen beim 
Zugriff auf USB Register?

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Simon K. schrieb:
> LUFA USB Stack

Hm. Hab ich mir mal eben spaßeshalber runtergeladen.
Die lib scheint interruptbasiert zu sein. Bist du sicher, daß dein 
Timerinterrupt die USB-Interrupts unterbrechen kann (und auch dürfte)?

Oliver

von Simon K. (simon) Benutzerseite


Lesenswert?

Oliver S. schrieb:
> Simon K. schrieb:
>> LUFA USB Stack
>
> Hm. Hab ich mir mal eben spaßeshalber runtergeladen.
> Die lib scheint interruptbasiert zu sein. Bist du sicher, daß dein
> Timerinterrupt die USB-Interrupts unterbrechen kann (und auch dürfte)?
>
> Oliver

Danke für deine Hilfe!

Glücklicherweise kann man die Interruptpriorität für den Stack 
konfigurieren und die ist auf Medium eingestellt.
Darüberhinaus ist für die XMEGA Implementierung allerdings nur der 
BusEvent Handler implementiert, der Rest wird gepollt (Known Issues).
Deswegen macht mich das Ganze so stutzig.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@ Simon K. (simon) Benutzerseite

>Leider nicht. Sobald ich den LUFA USB Stack in der Mainloop mitlaufen
>lasse, steigt der Jitter auf etwa 1µs an. Das wären um die 30
>Prozessortakte und das halte ich für zu viel.

Dann gibt es möglicherweise atomare Sequenzen, die kurzzeitig die 
Interrupts sperren.

>von bis zu 30 Takten hervorrufen könnte. Interrupts werden definitiv
>nicht deaktiviert im normalen Betrieb (nur während der Enumeration
>kurzzeitig um die interne ID mittels NVM auszulesen).

Du hst nur bis jetzt keine gefunden. ;-)

>Jetzt bin ich doch sehr ratlos. Das USB Modul funktioniert mit einem
>asynchronen 48MHz Takt. Gibt es hier vielleicht Verzögerungen beim
>Zugriff auf USB Register?

Verschachtelte Interrupts?

von Simon K. (simon) Benutzerseite


Lesenswert?

Falk Brunner schrieb:
> @ Simon K. (simon) Benutzerseite
>
>>Leider nicht. Sobald ich den LUFA USB Stack in der Mainloop mitlaufen
>>lasse, steigt der Jitter auf etwa 1µs an. Das wären um die 30
>>Prozessortakte und das halte ich für zu viel.
>
> Dann gibt es möglicherweise atomare Sequenzen, die kurzzeitig die
> Interrupts sperren.
Gibt es, z.B. bei der Enumeration. Die geschieht aber nur einmal.

>>von bis zu 30 Takten hervorrufen könnte. Interrupts werden definitiv
>>nicht deaktiviert im normalen Betrieb (nur während der Enumeration
>>kurzzeitig um die interne ID mittels NVM auszulesen).
>
> Du hst nur bis jetzt keine gefunden. ;-)
Also mehr als im Disassemblat nach cli Instruktionen schauen, kann ich 
nicht machen. Und die clis lassen sich an einer Hand abzählen und sind 
alle nicht kritisch (werden z.B. nur während der Init ausgeführt).

>>Jetzt bin ich doch sehr ratlos. Das USB Modul funktioniert mit einem
>>asynchronen 48MHz Takt. Gibt es hier vielleicht Verzögerungen beim
>>Zugriff auf USB Register?
>
> Verschachtelte Interrupts?
Ich verwende ja einen ATxmega und eigentlich sollten jegliche USB 
Interrupts (Medium Prio) von dem Hi-Prio Interrupt unterbrochen werden 
können.

Dann werde ich mal mit der LED-Debug-Methode den Stack Stück für Stück 
untersuchen.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@ Simon K. (simon) Benutzerseite

>Ich verwende ja einen ATxmega und eigentlich sollten jegliche USB
>Interrupts (Medium Prio) von dem Hi-Prio Interrupt unterbrochen werden
>können.

Das mag sein, aber auch in den Interrupts gibt es AFAIk kurze atomare 
Sequenzen, wenn Speicher für die ISR auf dem Stack angelegt wird.

von Oliver S. (oliverso)


Lesenswert?

Simon K. schrieb:
> Darüberhinaus ist für die XMEGA Implementierung allerdings nur der
> BusEvent Handler implementiert, der Rest wird gepollt (Known Issues).

DAs kann ich nicht nachvollziehen. In den known issues steht nichts 
davon, und auch das, was ich auf die schnelle im Code dazu finden 
konnte, sieht nach Interruptnutzung aus.

Oliver

von Simon K. (simon) Benutzerseite


Lesenswert?

Oliver S. schrieb:
> Simon K. schrieb:
>> Darüberhinaus ist für die XMEGA Implementierung allerdings nur der
>> BusEvent Handler implementiert, der Rest wird gepollt (Known Issues).
>
> DAs kann ich nicht nachvollziehen. In den known issues steht nichts
> davon, und auch das, was ich auf die schnelle im Code dazu finden
> konnte, sieht nach Interruptnutzung aus.

Komisch, ich meine es dort mal gelesen zu haben. Wie auch immer, es ist 
nur der BUSEVENT Handler implementiert, wie man im Disassemblat sehen 
kann:
1
     1f0:  56 c4         rjmp  .+2220     ; 0xa9e <__bad_interrupt>
2
     1f2:  00 00         nop
3
     1f4:  0c 94 36 26   jmp  0x4c6c  ; 0x4c6c <__vector_125>
4
     1f8:  52 c4         rjmp  .+2212     ; 0xa9e <__bad_interrupt>
5
     1fa:  00 00         nop

1F4+0 -> BUSEVENT_vect
1F4+4 -> TRNCOMPL_vect

In den Busevent Handler habe ich mich schon mal reingesetzt und wie 
erwartet, wird der nur bei der Enumeration aufgerufen (um die 
Enumeration zu starten).

Jegliche Datenkommunikation wird in USB_USBTask() (Mainloop) gemacht.
Es muss also irgendwie damit zu tun haben.

: Bearbeitet durch User
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.