Kampis Elektroecke

XMega – RTC

XMega Blockdiagramm

Einige der XMega Chips sind mit einer internen RTC (Real-Time Clock) ausgestattet, welche für sehr präzise Zeitmessungen verwendet werden kann. Hierfür wird ein 32 kHz Quarz an den Pins TOSC1 und TOSC2 (PQ.1 – Pin 85 und PQ.0 – Pin 84) benötigt, welches ggf. bei den Entwicklungsboards noch angelötet werden muss. Zusätzlich kann diese RTC auch noch über eine externe Batterie versorgt werden, sodass die RTC auch bei Verlust der Versorgungsspannung weiterarbeiten kann.

RTC initialisieren:

Da für die RTC ein zweites Quarz benutzt wird, muss das Quarz am Clocksystem noch aktiviert werden. Dazu wird als erstes mit

OSC.XOSCCTRL = OSC_X32KLPM_bm | OSC_XOSCSEL_32KHz_gc;

der externe 32 kHz Oszillator zugeschaltet und anschließend in den Low Power Mode versetzt. Anschließend wird der Oszillator aktiviert:

OSC.CTRL = OSC_XOSCEN_bm;

Um dem Oszillator genug Zeit zum einschwingen zu geben, wird das Programm solange angehalten bis durch ein Bit im Statusregister signalisiert wird das der Oszillator bereit ist. Dieses Bit wird wie folgt abgefragt:

while(!(OSC.STATUS & OSC_XOSCRDY_bm));

Der letzte Schritt besteht darin, den Takt auf 1024 kHz zu senken und die RTC zu aktivieren:

CLK.RTCCTRL = CLK_RTCSRC_TOSC_gc | CLK_RTCEN_bm;

RTC konfigurieren:

Da die Taktquelle für die RTC nun fertig initialisiert ist, muss nur noch die RTC eingestellt werden. Als erstes wird mit

RTC.PER = 1023;

das Periodenregister der RTC auf 1023 gestellt. Da ein Takt von 1024 Hz für die RTC eingestellt wurde, dauert es genau eine Sekunde bis die RTC bis 1023 hoch gezählt hat. Der Vorteiler für den RTC-Takt wird zudem auf 1 gesetzt:

RTC.CTRL = RTC_PRESCALER_DIV1_gc;

Um zu überprüfen ob beide Taktquellen (RTC-Takt und Systemtakt) synchron laufen und die Registerinhalte des CNT-, CTRL-, PER– und des COMP-Registers geschrieben worden sind, muss das SYNCBUSY-Bit im Statusregister abgefragt werden. Solange dieses Bit nicht gesetzt ist laufen beide Taktquellen nicht synchron zueinander. 

while(OSC.STATUS & RTC_SYNCBUSY_bm);

Nun muss noch der Interruptlevel und der Auslösegrund des Interrupts festgelegt werden. Diesen wird auf Niedrig gesetzt. Als Quelle soll der Overflow-Interrupt genutzt werden.

RTC.INTCTRL = RTC_OVFINTLVL_LO_gc;

Jetzt müssen noch die Interrupts aktiviert werden. Dazu wird einmal das Global Interrupt Enable-Bit gesetzt, sowie Interrupts mit der Priorität Niedrig im Interrupcontroller freigeschaltet.

PMIC.CTRL = PMIC_LOLVLEN_bm;
sei();

Nun löst die RTC jede Sekunde einen Overflow-Interrupt aus und springt in die entsprechende ISR. Diese kann wie folgt genutzt werden.

ISR(RTC_OVF_vect)
{
   // Code der in der ISR ausgeführt werden soll
}

In der ISR kann z. B. eine Variable hochgezählt werden um damit eine Uhr zu realisieren. Auch sind mit der RTC sehr einfache Zeitmessungen für größere Zeiträume problemlos möglich. So muss keiner der kostbaren Timer für
z. B. eine 5 Sekunden Pause genutzt werden. Durch die Möglichkeit eines Compare Match-Interrupts kann die RTC auch nach einer bestimmten Zeit einen Interrupt auslösen (z. B. alle 0,7 Sekunden).

Das komplette Projekt ist in meinem GitHub-Repository zu finden.

2 Kommentare

  1. Um dafür zu sorgen das beide Taktquellen (RTC Takt und Systemtakt) synchron laufen, wird das “SYNCBUSY” Bit im Statusregister abgefragt und solange dieses Bit nicht auf High steht, sprich beide Taktquellen sind synchron, läuft das Programm nicht weiter:
    while(RTC.STATUS & RTC_SYNCBUSY_bm);?
    or while(!(OSC.STATUS & RTC_SYNCBUSY_bm)); ?

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert