AVR64DD32: TCA-Overflow-Interrupt deaktiviert RTC

#7827930
Lesenswert?

Hi,

ich nutze erfoglreich bei einem AVR64DD28 den RTC und TCA im Interruptmodus (RTC für Interrupt alle 1 Sekunde, und den TCA alle 50ms) - siehe auch Beitrag "AVR64DD: TCA0.SINGLE.PER verändert util/delay-Verhalten"

Wenn ich das selbe beim AVR64DD32 versuche, funktioniert die RTC nicht mehr, sobald ich den Overflow-Interrupt beim TCA0 aktiviere. Beide haben einen externen 3.6864MHZ-Quarz. Ich finde im Datenblatt hier keinen Hinweis, auf abweichendes Verhalten zwischen den beiden Controller.

Kann das jemand hier auflösen? Kann ich die beiden Timer hier nicht unabhängig voneinander verwenden und müsste auf einen gemeinsamen ISR gehen (was ich ungern würde, da das zwei völlig getrennte Funktionen sind)?

Danke und Gruß

Micha

Hier der relevante code für die beiden:

1
//RTC
2
RTC.CTRLA = RTC_RTCEN_bm; // RTC aktivieren
3
while (RTC.STATUS > 0);   // Warten, bis der RTC bereit ist
4
ccp_write_io((uint8_t *)&CLKCTRL.XOSC32KCTRLA, CLKCTRL_ENABLE_bm | CLKCTRL_RUNSTDBY_bm);
5
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_OSC32KS_bm));
6
  
7
RTC.PITINTCTRL = RTC_PI_bm;
8
RTC.PITCTRLA = RTC_PERIOD_CYC32768_gc | RTC_PITEN_bm;
9
RTC.CLKSEL = RTC_CLKSEL_OSC32K_gc;
10

11
//TCA
12
TCA0.SINGLE.PER = 180;
13
TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1024_gc | // 3600Hz source
14
TCA_SINGLE_ENABLE_bm; // start timer
15

16
TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_NORMAL_gc; // set Normal mode
17
TCA0.SINGLE.EVCTRL &= ~(TCA_SINGLE_CNTAEI_bm); // disable event counting
18

19
//FIXME: aktivieren des Interrupt deaktiviert RTC!
20
//TCA0.SINGLE.INTCTRL = TCA_SINGLE_OVF_bm;
21

22
//und die ISRs
23
ISR(RTC_PIT_vect) {
24
  seconds++;
25
  RTC.PITINTFLAGS = RTC_PI_bm;
26
}
27
ISR(TCA0_OVF_vect) {
28
  sensor_counter_50ms++;
29
  TCA0.SINGLE.INTFLAGS = TCA_SINGLE_OVF_bm;
30
}
#7828218
Lesenswert?

Kann das jemand hier auflösen?

Kann ich nicht, aber ein paar Gedanken beitragen:

Da beide Typen im selben Errata-Blatt geführt werden, ist ein solcher Unterschied sehr unwahrscheinlich, die Kerne sollten gleich sein.

Was passiert, wenn der "irrelevante" Teil des Programms entfernt wird? Mit anderen Worten, wie immer: das Programm auf das absolute Minimum reduzieren, in den beiden ISR jeweils eine LED blinken lassen; dafür TCA-PER erhöhen. (apropos: da fehlt '-1').

Die Hex-Dateien müssen gleich sein, also vielleicht auch mal die des AVR64DD32 direkt auf den 28 übertragen (und umgekehrt).

#7828270
Lesenswert?

Hi,

bevor ich einen neuen Thread aufmache, teste ich das natürlich selbst erstmal entsprechend detailiert aus. Daher konnte ich das Problem auf die obigen Zeilen reduzieren. Den ganzen Rest hatte ich auskommentiert und auch entsprechend ein LED-Blinken eingefügt.

Zwecks Lesbarkeit (das ist sonst ein ZIP mit haufenweise irrelevantem =totem Code) habe ich dann die noch vorhandenen Restcode entsprechend hier reinkopiert. D.h. das oben ist bereits das Minimalprogramm, lediglich reduziert noch um das LED-Blinken (weil ich kein Problem mit Blinken habe, sondern dass der ISR schlicht nicht mehr ausgeführt wird):

sobald die Zeile mit FIXME einkommentiert wird, hört das Blinken auf

Grüße Micha

#7828457
Lesenswert?

Hallo,

ein Schuß ins Blaue.

1
CPU_CCP = CCP_IOREG_gc;
2
CLKCTRL.XOSC32KCTRLA = CLKCTRL_ENABLE_bm | CLKCTRL_RUNSTDBY_bm;

oder

1
#include <avr/cpufunc.h>
2
ccp_write_io((void*) &(CLKCTRL.XOSC32KCTRLA), (CLKCTRL_ENABLE_bm | CLKCTRL_RUNSTDBY_bm));

oder

1
#include <avr/xmega.h>
2
_PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, (CLKCTRL_ENABLE_bm | CLKCTRL_RUNSTDBY_bm));

Funktionseinheiten wie RTC oder TCA usw. sollte man allein schon von der Logik her erst aktivieren, wenn die gesamte Konfiguration durchgelaufen ist. Kann ansonsten für unangenehme Überraschungen sorgen. Die RTC Status Überprüfung ist an der Stelle sinnfrei. Das wird nach der Konfiguration geprüft, vorm aktivieren der RTC. Zudem dort noch zwischendrin der CPU Takt konfiguriert wird. Erst CPU Takt konfigurieren, diesen mittels Status Register prüfen ob das Ding läuft, dann den Rest konfigurieren. Kann mir schon vorstellen das dieses Durcheinander für Probleme sorgen könnte. Minimalprogramm muss ein für uns kompilierbares Programm sein was den Fehler noch zeigt. Ansonsten läuft das immer auf das gleiche Problem hinaus. Der TO denkt der Fehler liegt hier, der liegt aber tatsächlich woanders. Fehlender Code wird gedanklich ausgeblendet usw. Irgendwo ist immer noch was, kannste glauben. Genau da wo man als TO nicht denkt.

#7828518
Lesenswert?

Beim ersten Überfliegen dachte ich, dass Michael W. mit zwei Quarzen arbeitet: 3.6864 MHz als Hauptoszillator, 32 KiHz für den RTC-PIT.

Nur ohne Minimalprogramm steck ich da nicht meinen Kopf weiter rein.

Das sagte ich mir dann auch - aber ein interessanter Fall ist es schon. finde ich.

#7828538
Lesenswert?

Hi,

die CPU läuft mit dem externen Quarz, für die RTC nutze ich den internen Oszillator, weil ich damit eine einfache Sekunde hinbekomme.

Den starte ich natürlich vorher:

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

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

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

Das Hex kann ich leider nicht einfach auf den 28er packen, da der seine LEDs an anderen Ports hat (Das ist kein Steckbrett sondern fertige PCBs).

Wenn ich das nochmal zusammenschreiben muss, muss ich das erst wieder zusammenbauen. Das ist ein größerer Act, weil ich da einiges aus dem Projekt rausnehmen muss, umkommentieren etc. Da komm ich frühestens am Wochenende dazu.

Vermutlich ist es weniger Aufwand, die RTC auf 50ms zu packen und dann halt bis 20 zu zählen für die Sekunden - dann brauche ich den TCA0 nicht mehr.

Grüße und Danke Micha

#7828558
Lesenswert?

... Das ist ein größerer Act ... Wochenende

Verstehe ich nicht - Sie brauchen doch bloß das zusammenzufügen, was Sie uns (mittlerweile) fast vollständig gezeigt haben, und die LED-Pins ergänzen. Also mehr oder weniger das, was Sie von uns erwarten, und was ich inzwischen selbst hingebogen habe (auch wenn's wie Kraut und Rüben aussieht und nur auf einem AVR32DD28 läuft, mangels AVR64DD32, leider).

Aber vielleicht liest ja ein Bereitwilliger mit einem 32er mit und nimmt sich die zehn Minuten Zeit, um es auszuprobieren.

PS: Programm angehängt, vielleicht hilft es Ihnen. Man sieht auch sehr schön das Auseinanderlaufen der LEDs, der OSC32K ist nun mal nicht sehr genau.

Angehängte Dateien:
#7828673
Lesenswert?

S. L. schrieb:

Aber vielleicht liest ja ein Bereitwilliger mit einem 32er mit und nimmt sich die zehn Minuten Zeit, um es auszuprobieren.

Gelesen, getan: Bei mir funktioniert das Programm aus dem Anhang des vorhergehenden Beitrags von S. L. (sldt), 13.02.2025 19:49, (leicht angepasst, siehe unten) wie zu erwarten auf einem meiner AVR64DD32; die an PA7 und PA6 angeschlossenen LEDs blinken etwa im Sekundentakt, wobei die Abweichung der beiden Oszillatoren anhand der "Schwebung" sichtbar wird.

Allerdings habe ich gerade keinen 3,6864-MHz-CXO zur Hand, sodass ich ersatzweise die Default-Einstellung von 4 MHz internem Oszillator belassen habe. Zudem habe ich das Programm in Assembler umgeschrieben (siehe Anhang), weil ich gerade keine Lust hatte, mir extra einen Compiler zu installieren. Sollte ja aber hier beides keinen wesentlichen Unterschied machen.

Angehängte Dateien:
#7830369
Lesenswert?

Der TCA ist ein vollwertiger Universalcounter mit drei Compare Channels. Der RTC ist ein Ultra Low Power Langzeitcounter - "Sleep Counter". Für einfachere Aufgaben wie z.B. Periodic Interrupt kann man die TCBs benutzen. https://www.mikrocontroller.net/attachment/615726/AVR_TCB.png

1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3

4
ISR(TCB1_INT_vect)
5
{
6
  PORTD.OUTTGL =  PIN4_bm;                            // toggle PD4 (50ms)
7
  TCB1.INTFLAGS = TCB_CAPT_bm;                        // clear TCB1 interrupt flag
8
} 
9

10
ISR(TCB2_INT_vect)
11
{
12
  PORTD.OUTTGL =  PIN5_bm;                            // toggle PD5 (1s)
13
  TCB2.INTFLAGS = TCB_CAPT_bm;                        // clear TCB2 interrupt flag
14
} 
15

16
int main(void)
17
{
18
  EVSYS.CHANNEL0 = EVSYS_CHANNEL0_TCB0_CAPT_gc;       // event generator: TCB0 CAPT
19
  EVSYS.USERTCB1COUNT = EVSYS_USER_CHANNEL0_gc;       // event user: TCB1 count
20
  EVSYS.USERTCB2COUNT = EVSYS_USER_CHANNEL0_gc;       // event user: TCB2 count
21

22
  TCB0.CCMP = 0x4E1F;                                 // 10 ms
23
  TCB0.CTRLA = TCB_CLKSEL_DIV2_gc | TCB_ENABLE_bm;    // select clock, enable TCB0
24

25
  TCB1.CCMP = 0x0004;                                 // 50 ms
26
  TCB1.INTCTRL = TCB_CAPT_bm;                         // enable capture/timeout interrupt
27
  TCB1.CTRLA = TCB_CLKSEL_EVENT_gc | TCB_ENABLE_bm;   // select clock, enable TCB1
28

29
  TCB2.CCMP = 0x0063;                                 // 1 s
30
  TCB2.INTCTRL = TCB_CAPT_bm;                         // enable capture/timeout interrupt
31
  TCB2.CTRLA = TCB_CLKSEL_EVENT_gc | TCB_ENABLE_bm;   // select clock, enable TCB2
32

33
  PORTD.DIRSET = PIN4_bm;                             // PD4 output
34
  PORTD.DIRSET = PIN5_bm;                             // PD5 output
35

36
  sei();                                              // enable interrupts
37

38
  while(1) 
39
  {
40
    
41
  }
42
}

(getestet am AVR128DB48)

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