Hi Phil-D,
The trick to getting the RTC interrupt to fire every second (1Hz) in clock/calendar mode (Mode 2), is to increment the ALARM0 compare register (SECOND bitfield) each time the RTC_Hander() interrupt service routine is called:
RTC->MODE2.Mode2Alarm[0].ALARM.bit.SECOND = (RTC->MODE2.Mode2Alarm[0].ALARM.bit.SECOND + 1) % 60; // Increment the ALARM0 compare register
In this way, the ALARM0 compare register is set one second ahead of the clock/canlendar counter and the RTC interrupt is therefore called every second, each time the counter increments. The modulo 60 resets the compare register back to 0 after 60 seconds have elapsed.
Here's the code:
// Set-up RTC interrupt to fire every second (1Hz) in clock/calendar mode (Mode 2)
void setup(){
SerialUSB.begin(115200);
while (!SerialUSB);
PORT->Group[PORTA].DIRSET.reg = PORT_PA17; // Set digital pin D13 to an OUTPUT
// Configure clock source and clock generators (gclk.h)------------------------
GCLK->GENDIV.reg = GCLK_GENDIV_ID(4) | // Select GLCK4
GCLK_GENDIV_DIV(4); // Select clock divisor to divide by 32 (2 ^ (4 + 1))
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(4) | // Select GCLK4
GCLK_GENCTRL_SRC_XOSC32K | // Select GCLK source as the external 32.768kHz crystal
GCLK_GENCTRL_IDC | // Improve duty cycle for odd div factors
GCLK_GENCTRL_RUNSTDBY | // Enable run standby mode
GCLK_GENCTRL_DIVSEL | // Set GLCK divisor as 2 to the power of (divisor) value
GCLK_GENCTRL_GENEN; // Enable GCLK4
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_GEN_GCLK4 | // Select GCLK4
GCLK_CLKCTRL_ID_RTC | // Connect to the RTC
GCLK_CLKCTRL_CLKEN; // Enable GCLK4
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
// RTC configuration (rtc.h)--------------------------------------------------
RTC->MODE2.CTRL.reg |= RTC_MODE2_CTRL_PRESCALER_DIV1024 | // Set prescaler to 1024
RTC_MODE2_CTRL_MODE_CLOCK; // Set RTC to mode 2, clock/calendar mode
RTC->MODE2.Mode2Alarm[0].ALARM.bit.SECOND = RTC_MODE2_ALARM_SECOND(0); // Set the ALARM0 compare register
while (RTC->MODE2.STATUS.bit.SYNCBUSY) // Wait for synchronization
RTC->MODE2.Mode2Alarm[0].MASK.bit.SEL = RTC_MODE2_MASK_SEL_SS; // Set the RTC clock/calender interrupt mask to match seconds only
while (RTC->MODE2.STATUS.bit.SYNCBUSY) // Wait for synchronization
// Configure RTC interrupts ------------------------------------------
NVIC_SetPriority(RTC_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for RTC
NVIC_EnableIRQ(RTC_IRQn); // Connect RTC to Nested Vector Interrupt Controller (NVIC)
RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_ALARM0; // Set Mode 2 alarm interrupt
// Enable RTC--------------------------------------------------------------
RTC->MODE2.CLOCK.reg = 0x0000000; // Set the RTC counter to zero
while (RTC->MODE2.STATUS.bit.SYNCBUSY); // Wait for synchronization
RTC->MODE2.CTRL.reg |= RTC_MODE2_CTRL_ENABLE; // Turn on the RTC
while (RTC->MODE2.STATUS.bit.SYNCBUSY); // Wait for synchronization
SerialUSB.println(F("Setup complete..."));
}
void loop(){}
void RTC_Handler(void)
{
if (RTC->MODE2.INTFLAG.bit.ALARM0 && RTC->MODE2.INTENSET.bit.ALARM0) // Check for ALARM0 interrupt
{
SerialUSB.print(F("RTC Handler "));
SerialUSB.println(RTC->MODE2.Mode2Alarm[0].ALARM.bit.SECOND);
PORT->Group[PORTA].OUTTGL.reg = PORT_PA17; // Toggle digital pin D13
RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_ALARM0; // Reset interrupt flag
RTC->MODE2.Mode2Alarm[0].ALARM.bit.SECOND = (RTC->MODE2.Mode2Alarm[0].ALARM.bit.SECOND + 1) % 60; // Increment the ALARM0 compare register
while (RTC->MODE2.STATUS.bit.SYNCBUSY); // Wait for synchronization
}
}
The code toggles the Zero's LED on digtial pin 13, so it'll go on for 1 second, off for 1 second and so on... The ALARM0 compare register value is also output on the console.