Forum: Mikrocontroller und Digitale Elektronik Unverständliches Verhalten bei XMega32e5


von ArduStemmi (Gast)


Lesenswert?

Guten Morgen,

leider habe ich wieder einmal ein Verständnisproblem. Es geht um 
folgenden Code:
1
#define F_CPU 2000000L
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <util/delay.h>
5
6
volatile uint8_t tmp = 0;
7
8
9
ISR( TCD5_OVF_vect )
10
{
11
  
12
  PORTD.OUTTGL = PIN6_bm;
13
}
14
15
16
int main(void)
17
{
18
19
  //Oszillator auf 2Mhz stellen
20
  OSC.CTRL |= OSC_RC2MEN_bm;
21
  // Warten bis der Oszillator bereit ist
22
  while(!(OSC.STATUS & OSC_RC2MRDY_bm));
23
  //Schützt I/O Register, Interrupts werden ignoriert
24
  CCP = CCP_IOREG_gc;
25
  //aktiviert den internen Oszillator
26
  CLK.CTRL = (CLK.CTRL & ~CLK_SCLKSEL_gm) | CLK_SCLKSEL_RC2M_gc;
27
28
  PORTD.DIR |= PIN5_bm | PIN6_bm | PIN7_bm;    // PORTD Pins 5, 6 und 7 sind Ausgang
29
30
  
31
  
32
  PMIC.CTRL |= PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm; 
33
34
  TCD5.CTRLA |= TC45_CLKSEL_DIV1024_gc;      // Timer 4 Vorteiler 1024
35
  TCD5.CTRLB |= TC45_WGMODE_NORMAL_gc;      // NormalMode
36
  TCD5.INTCTRLA |= TC45_OVFINTLVL_HI_gc;      // Interrupt hat höchste Priorität
37
  TCD5.PER = 0x07A1;                // entspricht 1.953, sollte eine Sekunde ergeben
38
  //TCD5.CNT = 65000L;
39
40
  sei();
41
  
42
    /* Replace with your application code */
43
    while (1) 
44
    {
45
  PORTD.OUTTGL = PIN5_bm;
46
  for (uint8_t i = 0; i < 100; i++)
47
  {
48
    _delay_ms(5);
49
  }
50
51
    }
52
53
}

Was sollte passieren? Nun: es sollten Pin D5 (in der Hauptschleife 
getoggelt) mit 2 Hz und Pin D6 (über den Timer getoggelt) mit 1 Hz 
blinken! Was tun sie: Nach Reset gehen Sie sofort an und blinken dann 
unregelmäßig (!!!!!!!!!!!!!!!!!) mit einer Periode zwischen 1 und 10 
sec. (Oder so!)

Nein, das Programm hat keinen Sinn! Es ist nur zum Verständnis 
geschrieben.

Ja, wenn ich den ganzen Timerzirkus rausnehme, dann blinkt PIN D5 wie 
erwartet. Ich habe den Eindruck, dass der Timerkrempel den ganzen µC 
blockiert!

von Falk B. (falk)


Lesenswert?

@ ArduStemmi (Gast)


>ISR( TCD5_OVF_vect )
>{

>  PORTD.OUTTGL = PIN6_bm;
>}

Beim Überlauf von TCD5 soll IO in PD6 umgeschaltet werden.


>
>  //Oszillator auf 2Mhz stellen
>  OSC.CTRL |= OSC_RC2MEN_bm;
>  // Warten bis der Oszillator bereit ist
>  while(!(OSC.STATUS & OSC_RC2MRDY_bm));
>  //Schützt I/O Register, Interrupts werden ignoriert
>  CCP = CCP_IOREG_gc;
>  //aktiviert den internen Oszillator
>  CLK.CTRL = (CLK.CTRL & ~CLK_SCLKSEL_gm) | CLK_SCLKSEL_RC2M_gc;

Das ist Unsinn, denn der 2 MHz Oszillator ist nach dem Reset 
standardmäßuig aktiv. Kann man alles weglassen.

>  TCD5.CTRLA |= TC45_CLKSEL_DIV1024_gc;      // Timer 4 Vorteiler 1024

Sowas ist hier ungünstig bis falsch. Eine direkte Zuweisung ist das 
Mittel der Wahl.

   TCD5.CTRLA = TC45_CLKSEL_DIV1024_gc;      // Timer 4 Vorteiler 1024

>  TCD5.CTRLB |= TC45_WGMODE_NORMAL_gc;      // NormalMode
>  TCD5.INTCTRLA |= TC45_OVFINTLVL_HI_gc;      // Interrupt hat höchste Priorität

Hier ebenfalls.

>  TCD5.PER = 0x07A1;                // entspricht 1.953, sollte eine Sekunde 
ergeben

Warum schreibst du das in Hex, das kann kein Mensch verstehen.

2 MHz / 1024 = 1953 Hz.

Also eher

   TCD5.PER = 1953;

  sei();

>    /* Replace with your application code */
>    while (1)
>    {
>  PORTD.OUTTGL = PIN5_bm;
>  for (uint8_t i = 0; i < 100; i++)
>  {
>    _delay_ms(5);
>  }

>    }

Hier läßt du PD5 per Software blinken.


>
>Was sollte passieren? Nun: es sollten Pin D5 (in der Hauptschleife
>getoggelt) mit 2 Hz und Pin D6 (über den Timer getoggelt) mit 1 Hz
>blinken! Was tun sie: Nach Reset gehen Sie sofort an und blinken dann
>unregelmäßig (!!!!!!!!!!!!!!!!!) mit einer Periode zwischen 1 und 10
>sec. (Oder so!)

Klingt nach einem Watchdogreset. Ist der per Fuses ausgeschaltet?

>Ja, wenn ich den ganzen Timerzirkus rausnehme, dann blinkt PIN D5 wie
>erwartet. Ich habe den Eindruck, dass der Timerkrempel den ganzen µC
>blockiert!

Dann läuft was schief ;-)

Mach mal wie oben geschrieben normale Zuweisungen beim Timer-Init.

von ArduStemmi (Gast)


Lesenswert?

Danke für Deine Erläuterungen! Ich verstehe nicht, warum die direkte 
Zuweisung anders funktionieren sollte! Kannst Du das bitte kurz 
erläutern?

Die Einstellung des Taktes ist nur zur Sicherheit drin! Ich wollte halt 
sicher gehen, dass es nicht am falschen Takt liegt!

Wie sollten denn die Fuses stehen, um den Watchdog zu unterdrücken? Und, 
warum kann man beim XMega alles per SW einstellen, nur den WD 
ausgerechnet nicht?

von ArduStemmi (Gast)


Lesenswert?

Keiner eine Idee?

von Falk B. (falk)


Lesenswert?

@  ArduStemmi (Gast)


>Danke für Deine Erläuterungen! Ich verstehe nicht, warum die direkte
>Zuweisung anders funktionieren sollte! Kannst Du das bitte kurz
>erläutern?

Das kommt auf den vorherigen Zustand des Registers an. Manchmal will man 
das, manchmal eben nicht.

>Wie sollten denn die Fuses stehen, um den Watchdog zu unterdrücken? Und,
>warum kann man beim XMega alles per SW einstellen, nur den WD
>ausgerechnet nicht?

Frag das Atmel.

Prbier einfach mal die aufgeräumte Version.
1
#define F_CPU 2000000L
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <util/delay.h>
5
6
volatile uint8_t tmp = 0;
7
8
ISR( TCD5_OVF_vect )
9
{
10
  
11
  PORTD.OUTTGL = PIN6_bm;
12
}
13
14
15
int main(void)
16
{
17
18
  PORTD.DIR |= PIN5_bm | PIN6_bm | PIN7_bm;      // PORTD Pins 5, 6 und 7 sind Ausgang
19
  
20
  TCD5.CTRLA = TC45_CLKSEL_DIV1024_gc;        // Timer 4 Vorteiler 1024
21
  TCD5.CTRLB = TC45_WGMODE_NORMAL_gc;          // NormalMode
22
  TCD5.INTCTRLA = TC45_OVFINTLVL_HI_gc;        // Interrupt hat höchste Priorität
23
  TCD5.PER = 1953;                        // 1s Periodendauer
24
25
  PMIC.CTRL |= PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm; 
26
  sei();
27
  
28
  /* Replace with your application code */
29
  while (1) 
30
  {
31
    PORTD.OUTTGL = PIN5_bm;
32
    for (uint8_t i = 0; i < 100; i++)
33
    {
34
      _delay_ms(5);
35
    }
36
  }
37
}

von Josef H. (josefh0)


Lesenswert?

Hei,
mit TCD5.INTFLAGS |= 1;
in interrupt Flag löschen.

von ArduStemmi (Gast)


Lesenswert?

Wo und wann? Und warum?

von dodel (Gast)


Lesenswert?

also ich hab das gerade mal nachgestellt. Auch mit einem ATxmega32e5. 
Bei mir blinkt PD5 regelmäßig ... allerdings komischerweise zu langsam 
(statt 2 Hz eher mit 0,3 Hz). Dafür leuchtet PD6 durchgehend. Zumindest 
sieht es so aus. Tatsächlich wird jedoch die ISR ständig aufgerufen. 
Laut Oszi toggelt PD6 alle 14,5 us.

von ArduStemmi (Gast)


Lesenswert?

Josef H. schrieb:
> Hei,
> mit TCD5.INTFLAGS |= 1;
> in interrupt Flag löschen.

Winn ich im ISR für den Overflow Interrupt den Interrupt Flag jedesmal 
lösche, dann klappt es. Soll das so sein? Das macht man aber beim Atmega 
nicht so! Also ich jedenfalls. Und es steht meines Erachtens auch 
nirgends.

von dodel (Gast)


Lesenswert?

PS: aufgeräumte Version + Interrupt-Flag löschen funktioniert zumindest 
bei mir ;-)

Lustigerweise blinkt auch PD5 jetzt im erwarteten Takt und nicht wie 
zuvor zu langsam ;-)

von ArduStemmi (Gast)


Lesenswert?

Kotzmodus an: Das ist, was ich an diesem Hobby so hasse: völlig 
unerwartetes Verhalten, durch triviale Änderung beherrschbar, aber nicht 
erklärbar!
Kotzmodus aus!

von ArduStemmi (Gast)


Lesenswert?

Josef H. schrieb:
> Hei,
> mit TCD5.INTFLAGS |= 1;
> in interrupt Flag löschen.


und warum |=1; und nicht |= 6; ?

von Gerhard G. (xmega)


Lesenswert?

Hallo,

ISR( TCD5_OVF_vect )
{
  TCD5.INTFLAGS = TC5_OVFIF_bm;
  PORTD.OUTTGL = PIN6_bm;
}

dann funktioniert es!!

Beim XMega32e5 wird vermutlich das Interrupt-Flag  beim ISR-Aufruf nicht 
automatisch gelöscht!


Gruß G.G.

von Moby A. (moby-project) Benutzerseite


Lesenswert?

Gerhard G. schrieb
> Beim XMega32e5 wird vermutlich das Interrupt-Flag  beim ISR-Aufruf nicht
> automatisch gelöscht!

Nicht nur vermutlich.
Einfach mal vorher das Datenblatt lesen.
Ist eine Besonderheit bei den E5...

von ArduStemmi (Gast)


Lesenswert?

Zeig' mir mal, wo es im Datenblatt steht! Viele andere und auch ich, 
haben des so explizit nicht herauslesen können! Bitte sag mir jetzt 
nicht: Nirgends steht, dass es gelöscht wird, daraus folgt ...! Das ist 
schon klar! Aber, da es sich um eine Besonderheit handelt, hätte man 
explizit drauf aufmerksam machen müssen.

Für mich ist das Thema damit erledigt. Geärgert habe ich mich auch 
genug. Ich spiele weiter mit dem Mega rum!

von Hameg (Gast)


Lesenswert?

13.13.11, S191:

OVFIF will not be cleared when the interrupt vector is executed. The 
flag is cleared by writing a one to its bit location.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

ArduStemmi schrieb:
> Und, warum kann man beim XMega alles per SW einstellen, nur den WD
> ausgerechnet nicht?

Weil ein Wachhund, der sich von einer irrlaufenden Firmware
abschlachten lässt, kein sinnvoller Wachhund ist.

Man kann ihn natürlich auch per Software schalten, aber wenn
man ihn per Fuse aktiviert, dann ist das eine Nummer sicherer, und
er darf sich nicht wieder lahmlegen lassen.

(Hat mit deinem Problem nun nichts mehr zu tun, aber die Frage war
noch nicht beantwortet worden.)

: Bearbeitet durch Moderator
von ArduStemm (Gast)


Lesenswert?

Hameg schrieb:
> 13.13.11, S191:
>
> OVFIF will not be cleared when the interrupt vector is executed. The
> flag is cleared by writing a one to its bit location.

Ok, Du hattest Recht! Ich habe das nicht gesehen!

von Willi (Gast)


Lesenswert?

ArduStemm schrieb:
>> OVFIF will not be cleared when the interrupt vector is executed. The
>> flag is cleared by writing a one to its bit location.


Das trifft bei dem E5 übrigens auf fast alle IRQ Flags zu. Über die 
Nummer bin ich auch schon gestolpert. Ist man nicht gewöhnt und 
überliest es gleich mal im Datenblatt. Beim OVFIF steht es wenigstens 
noch drin, das es nicht gelöscht wird ;-) Wenn da einfach nur "nichts" 
steht, fängst Du richtig an zu suchen, weil beim AVR rechnet man nicht 
damit...

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Willi schrieb:
> Das trifft bei dem E5 übrigens auf fast alle IRQ Flags zu.

Das stimmt nicht. Es trifft lediglich auf die Flags zu, die einen 
DMA-Tansfer auslösen und von dem DMA-Transfer auch zurückgesetzt werden 
und bei denen dieses Verhalten sinnvoll ist, da ein automatisches 
Löschen in Verbindung mit DMA eher Fehler provozieren würde. Flags, die 
ohnehin durch die Hardware (DRE, RXD...) oder durch Interrupte gelöscht 
werden, sind davon nicht betroffen. Es schadet daher nicht, beim 
Programmieren jedes verwendete Flag im DB auf sein Verhalten hin zu 
überprüfen. Einige dieser "besonderen" Flags sind auch in den anderen 
XMEGAs der Serien A-D zu finden.

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.