Hallo zusammen,
da mich des öfteren Forenmitglieder fragen, wie man bei dem Xmega den RTC mit einem externen Uhrenquarz nutzt, stelle ich hierzu einmal ein Beispiel in das Forum.
Zielsystem ist der Xmega128A1 auf dem Mikrocontrollermodul XMEGA-A1-USB.
An dem Oszillatoreingang TOSC1/2 ist ein 32,768kHz Uhrenquarz angeschlossen. Die an PQ3 angeschlossenen LED soll einmal die Sekunde getoggled werden. Der Systemtakt ist nicht wichtig, ich nutze im Beispiel den internen RC-Oszillator mit 2MHz.
Im Beispiel gehe ich folgendermaßen vor:
A. Zuerst wird der 32kHz Oszillator im low power mode konfiguriert und aktiviert, die Taktquelle des RTC wird auf den Oszillator eingestellt (1024Hz).
B. Danach wird der RTC konfiguriert.
C. Nun wird der Overflow Interrupt des RTC freigegeben, der einmal in der Sekunde auftritt.
In der Interrupt-Serviceroutine setze ich das Bit IF_RTC_OVERFLOW in der Variable IntFlags, welches in der Hauptschleife des Hauptprogramms ausgewertet wird. Hier toggle ich dann die LED an PQ3.
Das Beispielprogramm habe ich noch einmal angehängt.
Dirk
CodeBox C
da mich des öfteren Forenmitglieder fragen, wie man bei dem Xmega den RTC mit einem externen Uhrenquarz nutzt, stelle ich hierzu einmal ein Beispiel in das Forum.
Zielsystem ist der Xmega128A1 auf dem Mikrocontrollermodul XMEGA-A1-USB.
An dem Oszillatoreingang TOSC1/2 ist ein 32,768kHz Uhrenquarz angeschlossen. Die an PQ3 angeschlossenen LED soll einmal die Sekunde getoggled werden. Der Systemtakt ist nicht wichtig, ich nutze im Beispiel den internen RC-Oszillator mit 2MHz.
Im Beispiel gehe ich folgendermaßen vor:
A. Zuerst wird der 32kHz Oszillator im low power mode konfiguriert und aktiviert, die Taktquelle des RTC wird auf den Oszillator eingestellt (1024Hz).
B. Danach wird der RTC konfiguriert.
C. Nun wird der Overflow Interrupt des RTC freigegeben, der einmal in der Sekunde auftritt.
In der Interrupt-Serviceroutine setze ich das Bit IF_RTC_OVERFLOW in der Variable IntFlags, welches in der Hauptschleife des Hauptprogramms ausgewertet wird. Hier toggle ich dann die LED an PQ3.
Das Beispielprogramm habe ich noch einmal angehängt.
Dirk
CodeBox C
#include <stdlib.h>
#include <stddef.h>
#include "avr_compiler.h"
volatile uint8_t IntFlags;
#define IF_RTC_OVERFLOW 0
ISR(RTC_OVF_vect)
{
IntFlags |= 1<<IF_RTC_OVERFLOW; // Message an das Hauptprogramm
}
int main (void)
{
IntFlags = 0;
// Systemclock: 2MHz (internal RC Oscillator)
PORTQ.DIRSET = 1<<PIN3; // LED an PQ3
PORTQ.OUTCLR = 1<<PIN3; // LED an
// **************************************************************
// A. Zuerst konfigurieren wir Oscillator und Clock-Distribution
// **************************************************************
/*****************************************************************
* OSC
* XOSCCTRL - XOSC Control Register
*
* Bit 5 = X32KLPM: Crystal Oscillator 32.768 kHz Low Power Mode
*
* Bit 3:0 = XOSCSEL[3:0]: Crystal Oscillator Selection
* = 0010 = OSC_XOSCSEL_32KHz_gc (GROUP: 32kHz, SOURCE: 32.768 kHz TOSC)
*
*****************************************************************/
OSC.XOSCCTRL = OSC_X32KLPM_bm | OSC_XOSCSEL_32KHz_gc;
/*****************************************************************
* OSC
* CTRL - Oscillator Control Register
*
* Bit 3 = XOSCEN: External Oscillator Enable
*
*****************************************************************/
OSC.CTRL = OSC_XOSCEN_bm;
// Warten bis External Clock Source stabil und bereit ist
while ((OSC.STATUS & (OSC_XOSCRDY_bm)) != OSC_XOSCRDY_bm) ;
/*****************************************************************
* CLK
* RTCCTRL - RTC Control Register
*
* Bit 2:0 = RTCSRC[2:0]: RTC Clock ource
* = 001 = CLK_RTCSRC_TOSC_gc
* (1.024 kHz from 32.768 kHz Crystal Oscillator on TOSC)
*
* Bit 0 = RTCEN: RTC Enable
*****************************************************************/
CLK.RTCCTRL = ( CLK.RTCCTRL & ~CLK_RTCSRC_gm ) |
CLK_RTCSRC_TOSC_gc | CLK_RTCEN_bm;
// Nun läuft der 32kHz Oszillator im low power mode und das RTC Modul
// erhält einen Clock von 1024Hz
// **************************************************************
// B. Jetzt konfigurieren wir den RTC
// **************************************************************
// Der RTC Counter soll nach exakt 1s überlaufen
RTC.PER = 1023;
RTC.CNT = 0;
RTC.COMP = 0xFFFF;
RTC.CTRL = RTC_PRESCALER_DIV1_gc; // Prescaler 1
// Der RTC Counter erhält nun seinen Takt (1024Hz)
// Da der RTC Counter asynchron zum System seinen Takt erhält, müssen
// wir warten, bis die Register des RTC synchronisiert sind
do {
} while(( RTC.STATUS & RTC_SYNCBUSY_bm ) == RTC_SYNCBUSY_bm);
// **************************************************************
// C. Nun aktivieren wir den Overflow-Interrupt des RTC
// **************************************************************
// Low Level Overflow Interurpt aktivieren
RTC.INTCTRL = ( RTC.INTCTRL & ~( RTC_COMPINTLVL_gm | RTC_OVFINTLVL_gm ) ) |
RTC_OVFINTLVL_LO_gc;
// Low Level Interrupts freigeben
PMIC.CTRL |= PMIC_LOLVLEN_bm;
sei(); // Interrupts global freigeben
// Main Loop
while (1)
{
// Haben wir eine Message von unserer RTC Counter Overflow ISR?
if ((IntFlags & (1<<IF_RTC_OVERFLOW)) == (1<<IF_RTC_OVERFLOW))
{
cli();
IntFlags &= ~(1<<IF_RTC_OVERFLOW); // Ja, Message erhalten, Flag wieder löschen
sei();
PORTQ.OUTTGL = 1<<PIN3; // LED toggle (Periodendauer 1 Sekunde)
}
};
return 0x00;
}