Forum: Mikrocontroller und Digitale Elektronik AVR64DD32: TCA-Overflow-Interrupt deaktiviert RTC


von Michael W. (micha124)


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
}

von Peter D. (peda)


Lesenswert?

Michael W. schrieb:
> Hier der relevante code für die beiden:

Woher willst Du wissen, was relevant ist?
Du suchst doch erst den Fehler. Also poste das compilierfähige und 
getestete Programm als Anhang (*.c, *.zip).

C&P von Schnipseln in das Posting sollte man meiden, da hierbei oft 
Fehler passieren.

von S. L. (sldt)


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).

von Michael W. (micha124)


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

von S. L. (sldt)


Lesenswert?

"Then carry it along"


Nur soviel:
> das oben ist bereits das Minimalprogramm
Es handelt sich um ein Programmfragment - wo z.B. wird der Oszillator 
für den 3.6864 MHz-Quarz eingeschaltet?

von Veit D. (devil-elec)


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.

: Bearbeitet durch User
von S. L. (sldt)


Lesenswert?

Dem letzten Absatz kann ich voll&ganz zustimmen.

Und: diese eine Zeile (4) mit dem XOSC32K habe ich ohnehin nicht 
verstanden - der RTC läuft anschließend doch mit OSC32K.

: Bearbeitet durch User
von Veit D. (devil-elec)


Lesenswert?

Hallo,

das habe ich auch nicht verstanden, wenn der AVR eigentlich mit 
3,6864MHz laufen soll. Irgendwo ist der Wurm drin, was wir nicht sehen. 
Nur ohne Minimalprogramm steck ich da nicht meinen Kopf weiter rein.

: Bearbeitet durch User
von S. L. (sldt)


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.

von Michael W. (micha124)


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

von S. L. (sldt)


Angehängte Dateien:

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.

: Bearbeitet durch User
von Johannes F. (jofe)


Angehängte Dateien:

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.

: Bearbeitet durch User
von Georg M. (g_m)


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)

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.