To avoid using UNIX time stamp, I modified the above code. And wondering how to configure the RTC's clock for 12 hours with AM/PM, I went a little further. Looked at github library RTCZero, but it seems like they only implement the library for 24 hour clock.
Here's Part 1 of 2
// Set-up RTC and timer TC4 to generate a timestamp down to microsecond accuracy
// Modified for 12/24 hour clocks
union { // Timestamp union/structure
struct {
uint32_t second : 6;
uint32_t minute : 6;
uint32_t hour : 4;
uint32_t _AMPM : 1;
uint32_t day : 5;
uint32_t month : 4;
uint32_t year : 6;
} bit;
uint32_t reg;
} timeStamp;
// Initialize Real Time Counter Clock/Calendar
const byte seconds = 0;
const byte minutes = 59;
const byte hours = 11; // 1-12 (12 hour clock)
const byte _ampm = 0; // 0 = AM, 1 = PM
const byte day = 20;
const byte month = 12;
const byte year = 2020;
unsigned long ms;
void setup(){
// Initialise native serial port, event system and LED output //////////////////////
ms = millis();
SerialUSB.begin(115200); // Initialise the native serial port
while (!SerialUSB); // Wait for the console to open
SerialUSB.println("STARTUP");
PM->APBCMASK.reg |= PM_APBCMASK_EVSYS; // Switch on the event system peripheral
PORT->Group[g_APinDescription[LED_BUILTIN].ulPort].DIRSET.reg = 1 << g_APinDescription[LED_BUILTIN].ulPin; // Set digital pin LED_BUILTIN to an OUTPUT
// RTC Generic Clock (GCLK) Configuration //////////////////////////////////////////
GCLK->GENDIV.reg = GCLK_GENDIV_DIV(4) | // Select clock divisor to divide by 32 (2 ^ (4 + 1))
GCLK_GENDIV_ID(4); // Select GLCK4
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
GCLK->GENCTRL.reg = //GCLK_GENCTRL_RUNSTDBY | // Enable run standby mode
GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW
GCLK_GENCTRL_GENEN | // Enable GCLK
GCLK_GENCTRL_DIVSEL | // Set GLCK divisor as 2 to the power of (divisor) value
GCLK_GENCTRL_SRC_XOSC32K | // Select GCLK source as external 32.768kHz crystal (XOSC32K)
GCLK_GENCTRL_ID(4); // Select GCLK4
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Enable GCLK
GCLK_CLKCTRL_ID_RTC | // Connect to the RTC at 1.024kHz (32.768kHz/32)
GCLK_CLKCTRL_GEN_GCLK4; // Select GCLK4
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
// Timer TC4 Generic Clock (GCLK) Configuration //////////////////////////////////////////
GCLK->GENDIV.reg = GCLK_GENDIV_DIV(3) | // Select clock divisor to divide by 3 48MHz/3=16MHz
GCLK_GENDIV_ID(5); // Select GLCK5
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
GCLK->GENCTRL.reg = //GCLK_GENCTRL_RUNSTDBY | // Enable run standby mode
GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW
GCLK_GENCTRL_GENEN | // Enable GCLK
GCLK_GENCTRL_SRC_DFLL48M | // Select GCLK source as the 48MHz DFLL (DFLL48M)
GCLK_GENCTRL_ID(5); // Select GCLK5
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Enable GCLK
GCLK_CLKCTRL_ID_TC4_TC5 | // Connect to timers TC4 an TC5
GCLK_CLKCTRL_GEN_GCLK5; // Select GCLK5
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
// Timer TC4 configuration ////////////////////////////////////////////////////
TC4->COUNT32.CTRLA.reg = TC_CTRLA_PRESCALER_DIV16 | // Set the timer prescaler to divide by 16: 16MHz/16=1MHz
TC_CTRLA_PRESCSYNC_PRESC | // Reload timer on next prescaler clock
TC_CTRLA_MODE_COUNT32; // Set the TC4 timer to 32-bit mode in conjuction with timer TC5
// RTC configuration //////////////////////////////////////////////////////////
RTC->MODE2.CTRL.bit.SWRST = 1; // Software reset the RTC
while (RTC->MODE2.STATUS.bit.SYNCBUSY); // Wait for synchronization ...
// Why this DISABLED check after RTC RESET???
while(RTC->MODE2.CTRL.bit.ENABLE); // Wait for the RTC to become disabled
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
NVIC_SetPriority(RTC_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for the RTC
NVIC_EnableIRQ(RTC_IRQn); // Connect Event System to Nested Vector Interrupt Controller (NVIC)
RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_ALARM0; // Set RTC ALARM0 interrupt
//RTC->MODE2.CLOCK.reg = 0x516AE000; // Initialise the RTC: May 21st 2020, 14:00 hours, ref year: 2000
//*
RTC->MODE2.CTRL.bit.CLKREP = 1; // 0 for 24hr, 1 for 12hr (AM/PM) clock
RTC->MODE2.CLOCK.bit.DAY = day;
RTC->MODE2.CLOCK.bit.MONTH = month;
RTC->MODE2.CLOCK.bit.YEAR = year - 2000; // reference year 2000 is a leap year
RTC->MODE2.CLOCK.bit.SECOND = seconds;
RTC->MODE2.CLOCK.bit.MINUTE = minutes;
RTC->MODE2.CLOCK.bit.HOUR = ( _ampm << 4 ) + hours;
//*/
while (RTC->MODE2.STATUS.bit.SYNCBUSY); // Wait for synchronization
Code part 2 of 2 below.