AVR64DD: TCA0.SINGLE.PER verändert util/delay-Verhalten

OP #7557447
Lesenswert?

Hallo,

vorab: mein erster Einsatz der neuen DD-Familie, bisher immer Atmega und Attiny (alt)

Nach einigen Versuchen aufgrund eines seltsamen Verhalten beim AVR64DD habe ich folgendes eingegrenzt:

Ich betreibe den Chip mit 3.3V und einem externen 3,6864MHz Quarz und nutze auch die util/delay.h. Den TCA0 nutze ich zum Zählen von 50ms-Einheiten. Sobald ich bei der Initialisierung des TCA0 einen Wert in TCA0.SINGLE.PER schreibe, wird delay_ms nun massiv langsamer.

Ich benutze an anderer Stelle die RTC - daher hier der TCA.

Initialisierung auf 3,6864 MHZ - kontrolliert mit DSO über aktivierten PA7:

1
int main(void) {
2
  //Systemspeed 3,6864 MHz using external crystal
3
  ccp_write_io((uint8_t *)&CLKCTRL.XOSCHFCTRLA, 
4
    CLKCTRL_RUNSTDBY_bm
5
    | CLKCTRL_CSUTHF_4K_gc
6
    | CLKCTRL_FRQRANGE_8M_gc
7
    | CLKCTRL_ENABLE_bm);
8
  while(!(CLKCTRL.MCLKSTATUS & CLKCTRL_EXTS_bm)){;}
9

10
  /* Clear Main Clock Prescaler */
11
   _PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, 0);
12

13
  //activate external clock    
14
  ccp_write_io((uint8_t *)&CLKCTRL.MCLKCTRLA, 
15
    CLKCTRL_CLKSEL_EXTCLK_gc
16
    | CLKCTRL_CLKOUT_bm  //output clock on PA7
17
    );
18
  while(CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm){;}

nun das interessante:

1
  _delay_ms(5000);  //wartet 5 Sekunden
2

3
  //Initialisierung TCA0
4
  /* set the period */
5
  TCA0.SINGLE.PER = 180;    //das hier ist die kritische Zeile...
6
  /* enable with prescaler */
7
  TCA0.SINGLE.CTRLA =
8
    TCA_SINGLE_CLKSEL_DIV1024_gc // -> 3600Hz
9
    | TCA_SINGLE_ENABLE_bm; /* start timer */
10

11
  /* enable overflow interrupt */
12
  TCA0.SINGLE.INTCTRL = TCA_SINGLE_OVF_bm;
13
  /* set Normal mode */
14
  TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_NORMAL_gc;
15
  /* disable event counting */
16
  TCA0.SINGLE.EVCTRL &= ~(TCA_SINGLE_CNTAEI_bm);
17

18
  sei();
19

20
  _delay_ms(5000);  //wartet ca. 170 (vermutlich 180) Sekunden
21
}
22

23
volatile uint8_t sensor_counter_50ms = 0;
24
ISR(TCA0_OVF_vect) {
25
  sensor_counter_50ms++;
26
  TCA0.SINGLE.INTFLAGS &= ~TCA_SINGLE_OVF_bm;
27
}

Ich habe zunächst vermutet, dass der TCA-Prescaler aus irgendeinem Grund den Systemtakt ändert. Via DSO habe ich aber verifiziert, dass auch im zweiten Delay der Systemtakt an PA7 noch bei den 3,68 MHz ist.

Sobald ich das Setzen der PER aus dem TCA0 rausnehme, sind auch der untere delay 5 Sekunden (es reicht die eine Zeile auszukommentieren).

Es scheint nun, dass der delay als Basis nicht den System Takt nimmt, sondern 5000 mal den Overflow von TCA0 (das wären dann ca. 250 Sekunden was hinkommenm könnte). Da ich hierzu aber keinerlei Hinweis im Datasheet finde und ich auch nicht von so einem Hardware-Bug ausgehe, ist die tatsächliche Ursache aber vermutlich eine andere.

Kann hier jemand zur Aufklärung und Lösung beitragen?

Grüße Micha

OP #7557464
Lesenswert?

Hi Peter,

Peter D. schrieb:

Das Delay-Macro läuft im Main-Kontext. Es verlängert sich daher bei hoher Interruptlast, z.B. durch fehlendes Löschen des Interruptflags. Beim AVR ist eine beliebte Fallgrube, daß Interruptflags durch Setzen gelöscht werden.

Aktuell sind keine weiteren IRQ aktiv.

Das IRQ-Flag für den TCA lösche ich doch dadurch - oder nicht?

1
TCA0.SINGLE.INTFLAGS &= ~TCA_SINGLE_OVF_bm;

Grüße Micha

#7557479
Lesenswert?

Michael W. schrieb:

Das IRQ-Flag für den TCA lösche ich doch dadurch - oder nicht?

TCA0.SINGLE.INTFLAGS &= ~TCA_SINGLE_OVF_bm;

Den Read Modify Write kannst du dir vermutlich noch sparen und direkt das Bit schreiben:

1
TCA0.SINGLE.INTFLAGS=TCA_SINGLE_OVF_bm;

Normalerweise werden Interrupt Flags ja sowieso immer mit der 1 an der richtigen Stelle gelöscht.

Beitrag #7557482 wurde von einem Moderator gelöscht.
Gast #7557658
Lesenswert?

Peter D. schrieb:

Beim AVR ist eine beliebte Fallgrube, daß Interruptflags durch Setzen gelöscht werden.

Vorsicht. Nicht immer (nur). Zu allem Überfluß ist/war das in manchem Datenblatt der neuen AVRs auch noch falsch beschrieben, Copy&Paste aus alten Dokus ist hier offensichtlich die bevorzugte Erstell-Methode gewesen...

Die althergebrachte Methode "IFlag wird beim Ausführen des Interrupt-Vektor gelöscht" ist bei SPI bis heute falsch im AVR128DA Blatt beschrieben, beim DB inzwischen korrigiert. Die richtige Methode zum Löschen ist da das pure Auslesen von INTFLAGS und Zugriff aufs DATA Register, hintereinander im Interrupt.

#7557802
Lesenswert?

Peter D. schrieb:

S. L. schrieb:

Das ist hier doch der Fall, oder?

Stimmt, in den aktuellen Datenblättern ist wieder alles drin. Da haben sich wohl welche beschwert. Ich hab noch ein altes ATmega3209/4809 Datenblatt, was nur 68 Seiten kurz ist. Und dazu ein extra megaAVR 0-series Manual.

Hallo Peter,

das hatte ich dir schon einmal geantwortet. Als die megaAVR0 Serie frisch rauskam gab es tatsächlich 2 getrennte Manuals. Alles danach hat nur noch eins. Man sollte seine Dokumente hin und wieder aktualisieren. ;-) Vor paar Monaten kamen für viele Controller neue Manuals raus. Ein nachschauen lohnt sich. Die TCB Kaskadierung für alle Mess-Modi steht bspw. im ARVxDB Manual jetzt drin.

PS: Wer Fehler findet kann das ruhig an Microchip melden. Kann zwar über ein Jahr dauern, aber man hat die Chance genutzt.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren