RTC Timer re-initialization

Hi,

I have nRF52840 DK and am using nRF5_SDK_17.0.2_d674dde.

I am not using SoftDevice, and Zephyr RTOS.

I have a simple program and using RTC0 timer. My code snippet:

const uint32_t m_dwPreScales[10]={
4095,1365,819,585,455,  315,273,195,151,105};
const uint32_t m_dwRTCsCC[10]={
8, 24, 40, 56, 72,  104,120,168,216,312};

void rtc_initialize(void) {
    uint32_t err_code;
    k++;
    if (k>=9) k=0;
    //k=5;
    //=======================================================
    NRF_RTC0->TASKS_STOP= 1;
    NVIC_ClearPendingIRQ(RTC0_IRQn);
    NVIC_DisableIRQ(RTC0_IRQn);
    NRF_RTC0->EVTENCLR = RTC_INT_MASK;
    NRF_RTC0->INTENCLR = RTC_INT_MASK;
    //=======================================================
    volatile uint32_t prescaler= m_dwPreScales[k];
    volatile uint32_t duration_ticks= m_dwRTCsCC[k];
    NRF_RTC0->TASKS_CLEAR= 1;
    //NRF_RTC0->TASKS_TRIGOVRFLW= 1;
    NRF_RTC0->PRESCALER = prescaler;
    NRF_RTC0->CC[0]     = 3;
    NRF_RTC0->CC[1]     = duration_ticks;

    NRF_RTC0->INTENSET = RTC_CHANNEL_INT_MASK(0);
    NRF_RTC0->EVTENSET = RTC_CHANNEL_INT_MASK(0);
    NRF_RTC0->INTENSET = RTC_CHANNEL_INT_MASK(1);
    NRF_RTC0->EVTENSET = RTC_CHANNEL_INT_MASK(1);
    NRF_RTC0->EVTENSET = NRF_RTC_INT_TICK_MASK;
    NVIC_SetPriority(RTC0_IRQn, 2);  
    NVIC_EnableIRQ(RTC0_IRQn);
    NRF_RTC0->TASKS_START=1U;
    //======================================================
}
 
void RTC0_IRQHandler(void)
{
   if(NRF_RTC0->EVENTS_TICK){
       NRF_RTC0->EVENTS_TICK = 0;
   }
    
   if ((NRF_RTC0->EVENTS_COMPARE[0] != 0) )  
   {
      NRF_RTC0->EVENTS_COMPARE[0] = 0;  
      nrf_gpio_pin_toggle(LED1_PIN);
   }

   if ((NRF_RTC0->EVENTS_COMPARE[1] != 0))
   {
      NRF_RTC0->EVENTS_COMPARE[1] = 0;  
      nrf_gpio_pin_toggle(LED1_PIN);
      rtc_initialize();
      //NRF_RTC0->TASKS_START =1U;
   }
   if(NRF_RTC0->EVENTS_OVRFLW){
       NRF_RTC0->EVENTS_OVRFLW = 0;
   }  
   return ;
}

The code runs OK, the period is 1 second for any fixed k, which basically prescaler and CC[1]. Only CC[0] and CC[1] are enabled. For any fixed k with a pair of prescaler and CC1, with event period is 1 second.

But If I change k++, everytime re-initialization, the period becomes  1s, 2s, 3s,4s, 5s, ... (may not exactly).

Could you please help me take a code review for apparent mistakes?

Thank you,

David

  • Hi Torbjorn,

    I am good and you can close the case for me. Thank you for your help.

    But just as feedback, I have tested that CC[] can be dynamically reinitialized, except prescaler. Although the re-initialization  is in the ISR, but the interrupt and tasks are stopped before initialization. So it shouldn't matter. Also RTC is on LFCLK, but the registers for RTC is on another CLK as CPU? I validated prescaler by read-out into a variable. I am not sure why CC can be reinitialized while Prescaler not. As I said, I am good and I can fix the prescaler all the time, and just change CC values.

    Best Regards,

    David Zhou

  • Hi David

    The peripheral registers are running off of the 16MHz peripheral clock, so you should be able to access these much faster than the LFCLK, but the RTC module itself might not read the value until the next tick happens. 

    I notice from the PRESCALER section in the product specification that you can only write the PRESCALER value while the RTC is stopped, and quite possibly you need to wait for one LFCLK period after stopping the RTC in order to ensure it is fully stopped. 

    The CC registers does not have this limitation, and can be changed at any time. 

    While it is a bit more work to change the PRESCALER value, this is not something that is usually done dynamically. Most applications use a static PRESCALER value, and simply change the CC values instead when changing the wakeup interval. 

    Best regards
    Torbjørn

Related