RTC

XMega Blockdiagramm

Hier zeige ich euch wie ihr die RTC vom XMega benutzen könnt.
Hierfür solltet ihr ein 32kHz Quarz an den TOSC1 und TOSC2 Pins (PQ1 – Pin 85 und PQ0 – Pin 84) anschließen, damit die RTC auch die maximale Genauigkeit erreicht.

-> RTC initialisieren:

Da wir für die RTC ein zweites Quarz benutzt wird, muss am Clocksystem noch einmal etwas eingestellt werden.
Als erstes wird mit

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

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:

Der letzte Schritt besteht darin, den Takt auf 1024 runter zu senken und die RTC zu aktivieren.
Dies geschieht so:

-> RTC konfigurieren:

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

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

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:

Nun muss noch der Interruptlevel und der Auslösegrund des Interrupts festgelegt werden.
Diesen setze ich auf High und als Quelle benutze ich den Overflow Interrupt:

Nun löst die RTC jede Sekunde einen Overflow Interrupt aus und springt in die ISR.
Diese sieht so aus:

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

 

-> Zurück zum XMega Tutorial

12 thoughts on “RTC
  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)); ?

  2. wenn du ein buch veröffentlichst, würde ich es kaufen :)
    also: ich habe gerade versucht den internen RTC als counter / timer zu benutzen weil alle anderen 24 schon anderweitig zu tun haben. dieser interne macht aber nur 1khz statt 32khz. blöd. hatte bei dir irgendwo schon gesehen, dass der durch nen 32 teiler muss und dann logischerweise nur 1k übrig bleibt. egal. muss dann mit 1khz leben.

    • Hey,

      danke für die Blumen ^.^
      Ja das mit dem Teiler steht unter „Clocksystem“ bzw. da ist der interne RC Oszi der RTC mit in dem Bildchen über die Clocksources aufgelistet.

      Gruß
      Daniel

  3. Hallo,
    Ich finde dein Tutorial sehr Hilfreich,
    jedoch habe ich das Problem, dass ich eine Variable jede Millisekunde einmal hochzählen muss und jetzt noch nicht wirklich weiß wie der Code dafür aussehen müsste. Könntest du mir vielleicht Helfen und mir zeigen, wie der Code dafür aussehen müsste?

    Danke:)

    • Hallo,

      du nimmst einfach den beschriebenen Code und änderst

      RTC.PER = 1023;

      Da die RTC mit einem Takt von 1024Hz arbeitet, brauchst du eigentlich mir die Zeile auf

      RTC.PER = 1;

      ändern. Damit erhältst du einen (ungenauen) 1ms Takt.
      Wenn du es genauer haben willst, stellst du den Takt auf 1kHz, indem du das RTC.CTRL-Register umänderst:

      CLK.RTCCTRL = CLK_RTCSRC_ULP_gc | CLK_RTCEN_bm;

      Diese Methode nimmt den 1kHz Takt vom internen ULP Oszi….eventuell musst du den noch starten etc.
      Genauere Infos findest du hier

      http://www.atmel.com/Images/doc8077.pdf

      auf Seite 89.
      Wie gesagt ist ungetestet, aber 1ms ist möglich wenn du ein bisschen am Prescaler rum schraubst :)
      Hoffe das hilft dir weiter :)

      Gruß
      Daniel

  4. Hallo Kampis,
    ich betreibe meinen xmega128a1 mit einem externen 8MHz Quarz. Jetzt will ich den internen 32.768 kHz Takt für den RTC verwenden jedoch funktioniert es nicht.
    Mein Unterprogramm sieht so aus.
    void init_rtc()
    {SC.CTRL |= OSC_RC32KEN_bm;
    while(!(OSC.STATUS & OSC_RC32KEN_bm));
    CCP = CCP_IOREG_gc;
    CLK.CTRL = CLK_SCLKSEL_RC32K_gc;
    CLK:RTCCTRL = CLK_RTCRC_TOSC_gc | CLK_RTCEN_bm;
    RTC.CTRL = RTC_PRESCALER_DIV1_gc;
    while(OSC.STATUS & RTC_SYNCBUSY_bm);
    RTC.INTCTRL = 0x03;
    }

    Interrupt routine:
    ISR(RTC_OVF_vect)
    {
    ….
    }

    ich spring aber nie in meine interrupt routine rein. Kannst du mir da evtl. weiter helfen?

    Danke

  5. Hallo Kampis,

    ich finde dein Tutorial echt Klasse.
    Bei meinem Projekt habe ich zwei externe Oszilatoren/Quarze .
    Ich will meinen Xmega mit einem externen Oszilator von 30Mhz betreiben will(am XTAL1 hängend) und gleichzeitig habe ich einen 32.768kHz-Quarz am TOSC hängen.

    void init_clock(void)
    {
    // initialize the external clock for cpu and usart
    OSC.XOSCCTRL = OSC_XOSCSEL_EXTCLK_gc; // Select external clock 30Mhz
    OSC.CTRL = OSC_XOSCEN_bm; // Enable external clock
    while(!(OSC.STATUS & OSC_XOSCRDY_bm)); // wait for external ready signal flag
    CCP = CCP_IOREG_gc; // protect I/O-registers and deactivate interrupts for 4 cpu-cycles
    CLK.CTRL = CLK_SCLKSEL_XOSC_gc; // Select external oscillator (or clock) –> in this case the 30 MHz ASFL1

    //intialize the realtime clock
    OSC.XOSCCTRL = OSC_X32KLPM_bm | OSC_XOSCSEL_32KHz_gc; //Select the external 32.768Mhz oszillator and set in PowerMode
    OSC.CTRL = OSC_XOSCEN_bm; //enable external clock
    while (OSC.STATUS & (OSC_XOSCRDY_bm));
    CLK.RTCCTRL = CLK_RTCSRC_TOSC32_gc| CLK_RTCEN_bm; //Select the 32.768kHz crystal oscillator on TOSC and enable

    CLK.LOCK = 0x01; //only change the clock by resetting
    }

    Nun stellt sich mir die Frage, ob sich die Zeilen
    OSC.XOSCCTRL = OSC_XOSCSEL_EXTCLK_gc;
    und
    OSC.XOSCCTRL = OSC_X32KLPM_bm | OSC_XOSCSEL_32KHz_gc;
    widersprechen.

    kannst du da einen Tipp geben, damit ich beide Quarze zum laufen bringe?

    Gruß fabi_h

    • Hallo Fabi,

      du musst erst (siehe unter „Clock“) deinen externen Oszillator aktivieren (CTRL-Register)und konfigurieren. Anschließend kannst du dann im RTCCTRL-Register das Bitmuster „101“ rein schreiben um den 32kHz Oszillator an TOSC zu aktivieren. Zudem musst du noch das Enable-Bit für die RTC setzen.
      Das was du da machst ist erst das Register mit einem Wert zu beschreiben und dann mit einem anderen.
      Wenn du nur ein weiteres Bit ändern willst, solltest du das so machen:

      Register = Wert;
      Register |= Neuer Wert;

      Damit veroderst du den aktuellen Registerinhalt mit einem neuen Wert (z.B. ein neues Bit, welches gesetzt werden soll).
      Probier es mal so und wenn es nicht klappt ruhig melden :)

      Gruß
      Daniel

      • Hallo Kampi,

        danke für deine Antwort!!
        Es hat ein bisschen gedauert. Aber jetzt bin ich trotzdem noch zu meinem Projekt gekommen. Parallel einen externen Systemtakt und einen externen RTC-Schwingquarz laufen zu lassen, scheint kein Problem darzustellen. Aber ich hab leider mit dem 30 MHz-Quarzoszillator ein Problem.. wahrscheinlich sind die zu hochgetaktet für ihn. Ich lasse ihn jetzt trotzdem „nur“ bei 16 MHz laufen.
        Dennoch hast du mir sehr weitergeholfen und finde dein Tutorial wirklich spitze!!

        Grüße Fabi

        • Hallo Fabi,

          freut mich das es nun funktioniert.
          Den XMega kann man auch nicht wirklich hoch takten….ich glaube bei etwa 45MHz ist Schluss.
          Die PLL ist auch mehr dafür da um aus einem niedrigen aber stabilen Takt einen hohen zu gewinnen, sodass man nicht den ungenauen 32MHz RC Oszillator nehmen muss :)

          Gruß
          Daniel

Schreibe einen Kommentar

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

Time limit is exhausted. Please reload CAPTCHA.