Forum: Mikrocontroller und Digitale Elektronik AVR: Wie kann das sein? (Timer1)


von Torsten C. (torsten_c) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich stehe vor einem Rätsel. Ein einfaches Programm, was einen Pin 
toggelt erzeugt komische hochfrequente Toggles (rot im Bild), dazwischen 
die 4ms-Zeitabstände, wie es laut Programm sein sollte:
1
#include <avr/io.h>                     // importiert im Wesentlichen iom328p.h
2
#include <avr/interrupt.h>              // ISR(vector, ...), sei, cli, ...
3
4
volatile bool toggle = true;
5
6
int main(void) {
7
  DDRC |= _BV(0);                  // Port C0: Debugging Port (Toggle)
8
  DDRC |= _BV(2);                  // Port C2: Debugging Port (Toggle)
9
  
10
  // Der 16-bit Timer/Counter1 läuft mit der höchsten Geschwindigkeit und bis zu seinem Wert von 0xFA00 = 64000 (OCR1A).
11
  // "No prescaling", siehe "Table 15-5 Clock Select Bit Description" (doc8161.pdf)
12
  // Bei 16MHz läuft der Timer also alle 4ms über, 250 Überläufe ergeben genau eine Sekunde.
13
  // Siehe Mode 15 in "Table 15-4 Waveform Generation Mode Bit Description" (doc8161.pdf)
14
  
15
  TCCR1A = _BV(WGM11) + _BV(WGM10);
16
  TCCR1B = _BV(WGM12) + _BV(WGM13) + _BV(CS10);
17
  OCR1A = 64000;
18
  TIMSK1 |= _BV(TOIE1);              // Timer 1 overflow Interrupt Enable 
19
  sei();
20
    while(1)
21
    {
22
    // mach nix.
23
    }
24
}
25
ISR(TIMER1_OVF_vect) {
26
  if (toggle) {
27
    PORTC = _BV(0);
28
    toggle = false;
29
  } else {
30
    PORTC = _BV(2);
31
    toggle = true;
32
  }
33
}

Hat jemand 'ne Idee? Das wäre toll.

Ich blick's nicht!

VG Torsten

von Detlef K. (adenin)


Lesenswert?

Die Skalierung der Zeitleiste unten im Bild ist etwas verwirrend. :)

Ist dies das originale Programm?
Also ich kann da erstmal nicht ungewöhnliches dran sehen.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Detlef Kunz schrieb:
> Ist dies das originale Programm?
Ja.

> Also ich kann da erstmal nicht ungewöhnliches dran sehen.

Und woher kommen die rot eingekringelten Toggles? Eigentlich soll der 
Timer genau alle 4ms von 64000 auf 0 springen und dann nur einmal 
toggeln.

Detlef Kunz schrieb:
> Die Skalierung der Zeitleiste unten im Bild ist etwas verwirrend. :)

Die untere ist vergrößert, die Skala macht das Programm so, aber das 
dürfte nun kein Problem sein.

: Bearbeitet durch User
von tommy (Gast)


Lesenswert?

gehört in die while(1) Schleife nicht mindestens
ein Semikolon?

von Karl H. (kbuchegg)


Lesenswert?

Das Programm ist in Ordnung. Du verwendest einen Mega328?

Hmm. Hast du schon mal kontrolliert, ob du unabsichtliche Resets hast 
oder ob sonst hardwaremässig alles in Ordnung ist?

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

tommy schrieb:
> gehört in die while(1) Schleife nicht mindestens
> ein Semikolon?

Das macht keinen Unterschied. Ich hatte alles rausgelöscht, um den Code 
für die Frage so kurz wie möglich zu halten, dann compiliert und dann 
gemessen.

von Torsten C. (torsten_c) Benutzerseite


Angehängte Dateien:

Lesenswert?

Karl Heinz schrieb:
> Das Programm ist in Ordnung. Du verwendest einen Mega328?

Ja, ein ATMega328p auf einem Arduino Pro Mini Derivat aus China.

> Hmm. Hast du schon mal kontrolliert, ob du unabsichtliche Resets hast
> oder ob sonst hardwaremässig alles in Ordnung ist?

Also ich habe nun die Verbindung zum AVR Dragon Board getrennt, RESET an 
VCC gepinnt und die Stromversorgung auf eine Batterie umgestellt. Selbst 
das kleine Voltmeter im Bild habe ich noch entfernt. Es bleibt wie im 
ersten Bild.

Ich habe auch noch:
1
TCCR1A = _BV(WGM11);
2
ICR1 = 64000;
ausprobiert (Mode 14), das gleiche in Grün.

Das kann doch nicht sein. ?!

: Bearbeitet durch User
von Markus (Gast)


Lesenswert?

Und der Analyser selber macht keine Probleme?
Und Probiere doch mal, wenn es langsamer togelt, ob der Effekt dann auch 
noch da ist.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Markus, ich hab's auch mit dem Oszilloskop genau so beobachtet. Bei 6400 
und 64000 ist der Effekt ähnlich. Nur wewnn ich z.B. in der ISR den 
Timer-Wert auf 63000 setze, dann gibt's gleichmäßige Impulse. Von 63000 
bis 64000 gibt's also keine Probleme.

Ich hab' nochmal den Watchdog kontrolliert: Ausgeschaltet und trotzdem 
in der while-Schleife resettet. Auch kein Unterschied.

Ich kann mir nicht vorstellen, dass der Prozessor defekt ist, aber ich 
probiere nach dem Frühstück mal einen zweiten aus, muss nur noch die 
PIN-Leisten anlöten.

: Bearbeitet durch User
von Markus M. (adrock)


Lesenswert?

Hi,

also am Programm kann ich auch keinen Fehler sehen, es sollte doch 
eigentlich ein Rechteck rauskommen.

Es scheint aber so, als ob das Programm jedesmal nachdem in der ISR die 
Pins gesetzt wurden irgendein Murks passiert (scheinbar wird die ISR 
gleich nochmal aufgerufen... und das mehrmals, komisch ist aber, dass 
die beiden Pins (C0/C2) anscheinend immer symmetrisch verändert werden, 
d.h. das geschieht wirklich durch die ISR. Würde ein anderer Zustand 
z.B. durch einen Reset auftreten, wären beide Pins gleichzeitig 
kurzzeitig auf "1".

Außerdem ist die Anzahl der Togglevorgänge immer gerade, sonst wäre in 
den 4ms Intervallen auch mal der Zustand von C0/C2 andersrum.

Auch ein Problem mit dem LA (Bitkipper o.ä.) scheidet eigentlich aus, da 
der Zustand von C0/C2 immer genau andersrum ist.

Bin auf die Lösung gespannt...
Markus

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Markus M. schrieb:
> Außerdem ist die Anzahl der Togglevorgänge immer gerade

Bei kleinen Modifikationen (6400 usw., s.o.) ist die Anzahl auch mal 
ungerade.

Zumindest scheint das Problem nicht trivial zu sein, daher schon mal 
danke für die Antworten.

> Bin auf die Lösung gespannt...

Und ich erst ...

PS: Der hochfrequente Teil entspricht einem Timer-Wert von 62937 = 
0xF5D9 vor einem RETI. Aber das hilft wohl auch nicht ...

: Bearbeitet durch User
von Conny G. (conny_g)


Lesenswert?

Auch wenn ich es nicht glaube, ein paar spontane Gedanken:
Stack-Problem?
Compileroptimierung und Registerüberschreibung?
Compilerbug?

von Herr M. (herrmueller)



Lesenswert?

Ich habe ein sehr ähnliches Problem mit
>ein ATMega328p auf einem Arduino Pro Mini Derivat aus China.

INT0 Interrupt eingestellt auf steigende Flanke.

        ldi temp, (1<<ISC00)|(1<<ISC01) ; INT0 steigende Flanke
        sts EICRA,temp
        ldi temp, (1<<INT0)             ; INT0 erlauben
        out EIMSK,temp



 In der IR Routine wird zum Test nur kurz PortC4 an und aus geschaltet.
;------------------------------------------------------------------
INT0_IR:
        in R0,sreg
sbi portc,4
nop
nop
nop
nop
nop
nop
nop
nop
nop
cbi portc,4
        out sreg,R0
        reti
;------------------------------------------------------------------

Beim 2313 funktioniert das mit meinem Eingangssignal einwandfrei, bei 
dem Ard. Pro mini löst er oft bei steigender und fallender Flanke - und 
oft 2* kurz hintereinander aus.
Das kann natürlich am Rechteck-Eingangssignal liegen, aber beim 2313 
klappts und der Logic Analyzer ist auch damit zufrieden.

Vielleicht haben die Billig Prozessoren irgendein Problem. Ich habe es 
aber mit 2 Platinen probiert.

von Helmut H. (helmuth)


Angehängte Dateien:

Lesenswert?

Das Programm scheint ok zu sein, mit einem ATMega328p auf einem Arduino 
Pro Mini Derivat aus China siehts an PC2 wie erwartet aus.

von c-hater (Gast)


Lesenswert?

Torsten C. schrieb:

> Markus M. schrieb:

>> Bin auf die Lösung gespannt...
>
> Und ich erst ...

Interessiert mich auch.

Kannst du mal den vom Compiler generierten Asm-Code posten? Ich habe 
einen Verdacht, was da passieren könnte, dieser Verdacht läßt sich aber 
nur anhand des Asm-Code überprüfen.

Notfalls reicht auch die erzeugte *.hex-Datei.

von Kaj (Gast)


Lesenswert?

c-hater schrieb:
> dieser Verdacht läßt sich aber
> nur anhand des Asm-Code überprüfen.
>
> Notfalls reicht auch die erzeugte *.hex-Datei.

Ich ziehe immer wieder meinen Hut vor Leuten die Asm beherrschen :o

von Helmut H. (helmuth)


Angehängte Dateien:

Lesenswert?

c-hater schrieb:
> Kannst du mal den vom Compiler generierten Asm-Code posten?

Gerne.

von Torsten C. (torsten_c) Benutzerseite


Angehängte Dateien:

Lesenswert?

Danke, Helmut! :-) Du warst schneller.

c-hater schrieb:
> Kannst du mal den vom Compiler generierten Asm-Code posten? Ich habe
> einen Verdacht, was da passieren könnte, dieser Verdacht läßt sich aber
> nur anhand des Asm-Code überprüfen.

Sie vollständige Datei ist in der Anlage. Am Interrupt kann ich nichts 
falsches erkennen:
1
__vector_13:
2
  push r1
3
  push r0
4
  lds r0,95
5
  push r0
6
  clr __zero_reg__
7
  push r18
8
  push r24
9
  push r25
10
  push r30
11
  push r31
12
  push r28
13
  push r29
14
  in r28,__SP_L__
15
  in r29,__SP_H__
16
  lds r24,toggle
17
  tst r24
18
  breq .L4
19
  ldi r24,lo8(40)
20
  ldi r25,0
21
  ldi r18,lo8(4)
22
  movw r30,r24
23
  st Z,r18
24
  sts toggle,__zero_reg__
25
  rjmp .L3
26
.L4:
27
  ldi r24,lo8(40)
28
  ldi r25,0
29
  ldi r18,lo8(1)
30
  movw r30,r24
31
  st Z,r18
32
  ldi r24,lo8(1)
33
  sts toggle,r24
34
.L3:
35
  pop r29
36
  pop r28
37
  pop r31
38
  pop r30
39
  pop r25
40
  pop r24
41
  pop r18
42
  pop r0
43
  sts 95,r0
44
  pop r0
45
  pop r1
46
  reti

Also bei meinem zweiten "Pro Mini Derivat" habe ich auch die "roten 
Kringel". :(

Heute hat mir der Postbote ein "Arduino Uno" und ein "Arduino Mega" 
gebracht. Ich probier's damit mal ...

: Bearbeitet durch User
von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Lass doch parallel mal die Stromversorgung aufzeichnen, eventuell ist da 
was im argen (fehlende Ablockkondensatoren o.ä.) ist der BOD aktiv?

von LostInMusic (Gast)


Lesenswert?

Was ich machen würde:

Eine blaue (grüne, gelbe...) LED an irgendeinen noch unbenutzten Pin 
eines noch unbenutzten Ports hängen und ganz an den Anfang des Codes ein 
paar geeignete Instruktionen einfügen, die diese LED bei jedem 
Programmstart kurz aufblitzen lassen. Es ist unendlich wertvoll, sehen 
zu können, ob und wann der µC resettet (übrigens bei jedem Projekt).

Weiße (orangene, violette...) LED an einen weiteren unbenutzen Pin eines 
noch unbenutzen Ports hängen. Alle unbenutzten Interruptvektoren 
definieren und auf eine Extra-ISR zeigen lassen. Diese ISR mit Code 
bestücken, der die weiße LED kurz aufblitzen lässt.

Eine kleine, simple Delayroutine schreiben. Verzögerungszeit sinnvoll 
wählen - so, dass Du sie auf dem Oszi/Logikanalyzer gut erkennen kannst. 
Dann die Delayroutine an allen möglichen "interessanten" Stellen im Code 
einfügen. Programm laufen lassen und anhand der auf dem Oszi sichtbaren 
Wirkung die Ursache herauszufinden versuchen.

von c-hater (Gast)


Lesenswert?

Torsten C. schrieb:

> Danke, Helmut! :-) Du warst schneller.

> Sie vollständige Datei ist in der Anlage. Am Interrupt kann ich nichts
> falsches erkennen

Ich habe mir beide Varianten angeschaut und kann auch nix wirklich 
falsches am Code erkennen.

Aufgefallen ist mir nur eins in der Version von Helmut (was allerdings 
in diesem Zusammenhang sicher keine Rolle spielt): Warum wird eigentlich 
der Stackpointer nicht auf's RAM-Ende initialisiert? Eventuell für 
Mega168(P)A übersetzt?

Bei deiner Version ist mir aufgefallen, daß es scheinbar gar keinen Code 
zur Initialisierung des Stackpointers gibt. Nun gibt es zwar AVRs, bei 
denen das tatsächlich nicht nötig ist, aber der M328P gehört laut 
Datenblatt nicht zu diesen, dort steht:

> The Stack in the data SRAM must be defined by the program before any
> subroutine calls are executed or interrupts are enabled.

von spess53 (Gast)


Lesenswert?

Hi

>dort steht:

>> The Stack in the data SRAM must be defined by the program before any
>> subroutine calls are executed or interrupts are enabled.

Das mag zwar dort stehen. Aber Initial Value ist für den Stackpointer 
RAMEND. Also keine Initialisierung im Programm notwendig.

MfG Spess

von c-hater (Gast)


Lesenswert?

spess53 schrieb:

> Das mag zwar dort stehen. Aber Initial Value ist für den Stackpointer
> RAMEND.

Stimmt, das hatte ich übersehen.

Also kann's auch am Stack nicht liegen. Also Programmfehler 
ausgeschlossen, Compilerfehler ausgeschlossen, es bleibt nur die 
Hardware.

von Sebastian W. (wangnick)


Lesenswert?

Hallo Torsten,

ich bin auch gespannt was sich als Grund für dieses komische Verhalten 
herausstellt.

Torsten C. schrieb:
> PS: Der hochfrequente Teil entspricht einem Timer-Wert von 62937 =
> 0xF5D9 vor einem RETI. Aber das hilft wohl auch nicht ...

a) Die Periode im hochfrequenten Teil von einem Toggle zum nächsten 
scheint ja so um die 100μs lang zu sein, aber wie lang ist sie genau? 
Vielleicht führt uns der genaue Wert auf eine Spur.

b) Was für einen Pro Mini hast du? 3.3V oder 5V? 8MHz oder 16MHz? 3.3V 
mit 16MHz könnte zu so lustigen Effekten führen.

c) Kannst du mal mit avrdude die Fuses auslesen?

d) Kannst du mal in der ISR
     PORTC = _BV(0);
   ersetzen durch
     PORTC = PORTC & ~_BV(2) | _BV(0);
   und
     PORTC = _BV(2);
   ersetzen durch
     PORTC = PORTC & ~_BV(0) | _BV(2);
   Sollte keinen Effekt haben wiel ja nur zwei Pins auf Ausgang stehen, 
aber vielleicht übersehen wir ja was ...

e) Kannst du mal im Anschluss an
     DDRC |= _BV(0);                  // Port C0: Debugging Port 
(Toggle)
     DDRC |= _BV(2);                  // Port C2: Debugging Port 
(Toggle)
   einfügen:
     PORTC |= _BV(2) | _BV(0);
     PORTC &= ~(_BV(2) | _BV(0));
   Dies, um sicher zu gehen, das tatsächlich kein Reset ststtfinden.

LG, Sebastian

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Ich habe alles ausprobiert, es gibt keine Resets, es werden keine 
unbenutzten ISRs angesprungen usw. Danke für die vielen Vorschläge.

Ich habe das gleiche Problem mit 'nem "Arduino Uno" und 'nem "Arduino 
Mega". Für meinen Teil: Ich vertage das Problem, gehe nun schlafen und 
fange morgen auf einem STM32F4Discovery neu an.

Ich will mit meinem Projekt weiter kommen und mich nicht mit diesem 
"Mist" herum schlagen. Ich hoffe, Ihr habt Verständnis.

Wenn die Peripherie-Hardware läuft, die Platine vom Platinensammler da 
ist und alles funktioniert, versuche ich es nochmal mit 'nem AVR. Dann 
mache ich ein SW-Update meiner Toolkette und wenn das nicht hilft, lege 
ich den Timer als 16-Bit-Wert parallel auf einen Port.

: Bearbeitet durch User
von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Hallo zusammen,

nachdem sich mein Frust wieder gelegt hat, bin ich Euch noch eine 
Antwort schuldig. Ich bin nochmal alle Eure Hinweise durchgegangen, und 
nun gehts. :-)

Ich wurde misstrauisch, als es nach einem POR manchmal ging, obwohl der 
LA weiter falsche Pulse anzeigte. Es war eine Kombination aus zwei 
Dingen:

1. Der Watchdog

Bei neueren AVR-Typen bleibt der Watchdog auch nach einem Reset durch 
den Watchdog aktiviert, siehe AVR-GCC-Tutorial/Der Watchdog.

2. Der LA

Da der LA aber (durch kapazitives Übersprechen?) weiter falsche Pulse 
anzeigte, habe ich das erst nicht gemerkt.

Fazit:

Nach dem einfügen der void get_mcusr(void) in der section(".init3") sah 
auf dem Oszilloskop alles OK aus. Der LA geht im 250ns-Sample-Mode nun 
auch, bei schlelleren Samples kommt halt Müll raus, der so ählich 
aussieht, wie das, was ich bei falsch initialisertem WD auf dem Oszi 
sah.

Danke nochmal Euch allen. ! :-)

von spess53 (Gast)


Lesenswert?

Hi

>1. Der Watchdog

>Bei neueren AVR-Typen bleibt der Watchdog auch nach einem Reset durch
>den Watchdog aktiviert, siehe AVR-GCC-Tutorial/Der Watchdog.

Warum fummelst du auch am Watchdog rum?

Den aktiviert man, wenn überhaupt, erst dann, wenn ein Programm stabil 
läuft.

MfG Spess

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

spess53 schrieb:
> Warum fummelst du auch am Watchdog rum?

Ohne "Fummeln" war der bei mir an. Ist das nicht bei jedem µC so? Gut, 
mache arbeiten mit 'nem Bootloader. Der muss den WD aber m.E. auch 
erstmal ausschalten.

: Bearbeitet durch User
von spess53 (Gast)


Lesenswert?

Hi

>Ist das nicht bei jedem µC so?

AVRs werden mit abgeschaltetem WD ausgeliefert.

MfG Spess

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

spess53 schrieb:
> AVRs werden mit abgeschaltetem WD ausgeliefert.

An welcher Stelle "abgeschaltet"? Meinst Du die WDTON Fuse? Die war bei 
mir auch "inaktiv", der WDT lief m.E. aber trotzdem ohne "Fummeln". Die 
Fuse verhindert ja nur das ausschalten. An ist der WD nach einem POR 
m.E. trotzdem immer.

: Bearbeitet durch User
von spess53 (Gast)


Lesenswert?

Hi

>An welcher Stelle "abgeschaltet"? Meinst Du die WDTON Fuse?

Ja. WDTON ist gelöscht (1)

> Die Fuse verhindert ja nur das ausschalten.

Nein, die bewirkt erst mal, das der WD ohne weitere Aktionen 
eingeschaltet ist. Bei gelöschter WDTON-Fuse muss der WD durch dein 
Programm eingeschaltet werden.

>Die war bei mir auch "inaktiv", der WDT lief m.E. aber trotzdem ohne
>"Fummeln".

Da dein Programm keine Einschaltsequenz enthält kann es nur die 
WDTON-Fuse sein. Es sei denn du glaubst an unbefleckte Empfängnis.

>Fazit:

>Nach dem einfügen der void get_mcusr(void) in der section(".init3")

Und was macht das genau?

MfG Spess

von Markus M. (adrock)


Lesenswert?

...diese get_mcusr() Funktion merkt sich den aktuellen Inhalt von MCUSR 
in mcusr_mirror und deaktiviert danach den WDT.

Anhand vom mcusr_mirror kann man dann auswerten was der Grund des 
letzten Resets war...

Aber trotzdem kann das natürlich nicht "richtig" sein, da der WDT auf 
jeden Fall deaktiviert bleiben sollte, wenn die Fuse in dem 
entsprechenden Zustand ist. Ich musste mich noch nie um den WDT kümmern.

Evtl. wird der WDT ja durch einen Fehler an einer anderen Stelle aus 
versehen aktiviert?

Grüße
Markus

von spess53 (Gast)


Lesenswert?

Hi

>Ich musste mich noch nie um den WDT kümmern.

Ich auch nicht. Deswegen macht mich das Ganze etwas stutzig.

MfG Spess

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Hmmm, dann ist da das nächste Rätsel: Wie ging der an?

> If the Watchdog is accidentally enabled, for
> example by a runaway pointer or brown-out
> condition, the device will be reset and the
> Watchdog Timer will stay enabled. If the code
> is not set up to handle the Watchdog, this might
> lead to an eternal loop of time-out resets. To
> avoid this situation, the application software
> should always clear the Watchdog System Reset Flag
> (WDRF) and the WDE control bit in the initialisation
> routine, even if the Watchdog is not in use.

Aber eigentlich ist das m.E. nun nicht mehr so wichtig.

Den BOD habe ich nun auch aus.

Frohes neues Jahr!

: Bearbeitet durch User
von Thomas (kosmos)


Lesenswert?

zu deinem Problem mit der Kapazitiven Einkopplung von Nachbarkanälen des 
LA's: Versuche mal die Kanäle leicht zu belasten z.B. mit 50kOhm ob dann 
immer noch so ein Übersprechen auftaucht, kannst ja den Wert auf 
P5robeweise immer weiter verringern, bis es weg ist.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Torsten C. schrieb:
> Den BOD habe ich nun auch aus.

Der sollte aber immer AN sein, es sei den du hast einen guten Grund 
(Ultra low power?).

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.