RTT: Real Time Timer

In this example, we will generate an interrupt based on the real time timer. The real time timer runs at 1hz using the 32.768khz slow clock and has a 32bit counter that can count roll over events based on the programmable 16 bit prescaler. It can also generate an interrupt based on a comparing the equivalency of the value of ALMV in REG_RTT_AR. Since we can account for crystal error in the RTC settings, we can keep the RTT and RTC in sync by using the RTC as the 1hz clock source instead of just the RTT default of using the slow clock only.

Setup


#include "sam.h"
#include "basic_uart.h"

void clock_init(){
    REG_CKGR_MOR |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTEN;
    while (!(REG_PMC_SR & PMC_SR_MOSCXTS));
    REG_CKGR_MOR |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCSEL;
    REG_PMC_MCKR |= MC_MCKR_CSS_MAIN_CLK;
    while (!(REG_PMC_SR & PMC_SR_MCKRDY));
    REG_PMC_MCKR |= PMC_MCKR_PRES_CLK_1;
    while (!(REG_PMC_SR & PMC_SR_MCKRDY));
}

void slowClock_init(){
    //slow clock setup
    //switch from RC osc to external crystal, disable RC osc, disable PIO on xtal pins
    REG_SUPC_CR |= SUPC_CR_XTALSEL | SUPC_CR_KEY_PASSWD;
    //read status register.oscsel bit and wait for slow clock to be selected
    while (!(REG_SUPC_SR & SUPC_SR_OSCSEL));
	
    //set crystal correction
    REG_RTC_MR &= ~RTC_MR_HIGHPPM;
    //correction = (3906/20*ppm)-1 = 8.765
    REG_RTC_MR |= RTC_MR_CORRECTION(9);	
}

void rtt_init(){
    //enable RTT interrupts in NVIC
    NVIC_EnableIRQ(RTT_IRQn);
    //setup rtt to run at 1hz from RTC
    REG_RTT_MR|= RTT_MR_RTC1HZ;
    //setup interrupt every 10 seconds
    REG_RTT_AR = 4;
    //enable alarm interrupt
    REG_RTT_MR |= RTT_MR_ALMIEN;	
}

int main(void)
{
    SystemInit();
    clock_init();
    slowClock_init();
    UART_Init();
    rtt_init();
    
    while (1) 
    {
    }
}

void RTT_Handler( void) {
    //reading status register will clear interrupt flags
    uint32_t status = REG_RTT_SR;
    if ((status & RTT_SR_ALMS) >= 1){//ALMS generated an interrupt		
        /*
        Run the Code that you want to run every interrupt
        */
		
        //reset RTT counter
        REG_RTT_MR |= RTT_MR_RTTRST;
        //upon interrupt REG_RTT_AR.RTT_AR_ALMV gets set to the maximum value
        //we need to disable alarm to set a new value in ALMV
        REG_RTT_MR &= ~RTT_MR_ALMIEN;
        REG_RTT_AR = 4;
        //turn interrupt back on
        REG_RTT_MR |= RTT_MR_ALMIEN;
	}	
}