FRDM-KL05Z RTC inaccurate

17 Jan 2016

The real time clock on the FRDM-KL05Z runs fast (200 ppm on my board) due to incorrect initialization of the RTC_CR register. The FRDM-KL05Z Rev B board does not have any load capacitors on the 32.768kHz crystal so the load is set using the OSC0_CR and RTC_CR registers. The OSC0_CR register is correctly set in SystemInit() for CLOCK_SETUP = 1, but the RTC_CR register, which overrides OSC0_CR, is not set correctly in rtc_init(). The crystal will oscillate at the correct frequency only until the first call to set_time() which calls rtc_init(). The fix is to add the following lines right after the first call to set_time():

   RTC->CR &= ~(RTC_CR_SC16P_MASK | RTC_CR_SC4P_MASK);
   RTC->CR |= RTC_CR_SC8P_MASK | RTC_CR_SC2P_MASK;

I chose 10 pF loading to allow for trace capacitance on the board.

Tom

17 Jan 2016

The RTC->CR override in rtc_api.c is not needed if the clock set up is 32Khz external crystal source on any of the KLxx targets. As we only have one crystal clock oscillator this should be set correctly in the system file, OSC0->CR during start up. This also adds unnecessary _NOP delay as the oscillator is already running.

I suggest that part should be removed, code between line 44 - 48 in the rtc_api.c file.

Tom could you try that to see if it works correctly?

edit...

I have checked, removing that code does work. RTC starts and runs with POR and keeps time on nRST.

Also tried the RTC Time compensation function that seems to work, you may want to try it, just replace the rtc_init with below. It does not work in the user code area, bricks the program from the start.

rtc_api.c snip


void rtc_init(void) {
    init();

    // Configure the TSR. default value: 1
    RTC->TSR = 1;
    
    // Configure Time Compensation Register to calibrate RTC accuracy
    
    // Dissable LRL lock
    RTC->LR &= ~RTC_LR_LRL_MASK;    
    // RTC->TCR: RTC_TCR_CIR_MASK,RTC_TCR_CIR(x)=0,RTC_TCR_TCR(x)=0 default no correction 
    RTC->TCR = RTC_TCR_CIR(0) | RTC_TCR_TCR(0);
    /* 
        RTC_TCR_CIR(x) sets the compensation interval in seconds from 1 to 256.
        0x05 will apply the compensation once every 4 seconds.
         
        RTC_TCR_TCR(x) sets the Register Overflow
        0x80 Time Prescaler Register overflows every 32896 clock cycles. (+128)
        ... ... RTC runs slower
        0xFF Time Prescaler Register overflows every 32769 clock cycles.
        0x00 Time Prescaler Register overflows every 32768 clock cycles, Default.
        0x01 Time Prescaler Register overflows every 32767 clock cycles.
        ... ... RTC runs faster
        0x7F Time Prescaler Register overflows every 32641 clock cycles. (-128)
    */
    // Enable TCL lock
    RTC->LR |= RTC_LR_TCL_MASK;
    // Enable LRL lock
    RTC->LR |= RTC_LR_LRL_MASK;
    
    // enable counter
    RTC->SR |= RTC_SR_TCE_MASK;
}

I have sent a PR so this may be added to the official Mbed library.

01 Mar 2016

Paul,

Can you link to the PR here so we can track it?

-Austin

01 Mar 2016