This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

How to make RTC0 worked in repeated mode?

Hello Nordic support,

I was referring to the RTC example in nrf52 SDK where an interrupt is triggered on Compare Counter event. In the example, the interrupt is triggered just once , i.e 3 s after boot. I would like to modify the example to trigger interrupt every 3 seconds.

To achieve this, I call the function nrf_drv_rtc_cc_set() in rtc_handler as follows:

static void rtc_handler(nrf_drv_rtc_int_type_t int_type)
{
    if (int_type == NRF_DRV_RTC_INT_COMPARE0)
    {
        nrf_gpio_pin_toggle(COMPARE_EVENT_OUTPUT);
        nrf_drv_rtc_cc_set(&rtc,0,COMPARE_COUNTERTIME * 8,true);
    }
}

However, this does not have any effect and the interrupt is triggered only once after boot.

Can you please let me know how to achieve the RTC trigger an interrupt at regular interval?

Thanks,

Anusha

Parents
  • The counter clear operation on the nRF52832 RTC doesn't generate a separate interrupt; and there are 2 other options. If this is the only interrupt used on the timer, you can trigger an overflow, which after 16 RTC ticks will behave as a counter clear and generate an interrupt if enabled.

    // Cane use timer overflow trigger as pseudo clear, overflows 16 ticks later
      pRTC->TASKS_TRIGOVRFLW;     // Set COUNTER to 0xFFFFF0

    If you have more than 1 interrupt in the RTC, then that not may be usable, in which case you can move the CC register forward on each interrupt to the next required value. There are two ways of doing this, read the current counter and add the offset to that or (preferably) add the offset directly to the CC register. The latter option has proved somewhat troublesome on occasion, but worth a try. The former risks losing accuracy as so many cycles are required to read the counter value. The sample code uses direct low-level registers to make clear what is going on; you can translate that the Nordic drivers if preferred.

    //  Frequency fRTC [kHz] = 32.768 / (PRESCALER + 1 )
    //  24-bit counter so overflows from 0xFFFFFF to 0x000000, prescaler is 12-bit range 0-4095
    #define RTC_CRYSTAL_FREQUENCY   32768ul // Hz
    #define TIMER_PRESCALER             0   // (32768Hz/(PRESCALER+1)) -> 32.768KHz or 30.517us tick when prescaler is 0
    #define MSECS_PER_TICK             10   // Slower ticks means less power but also less accuracy, so choose a balance
    #define TIMER_TICK  ((RTC_CRYSTAL_FREQUENCY*MSECS_PER_TICK)/1000) // Assumes 30.517 us basic crystal tick but adjusts automatically
    
    void RTC0_IRQHandler(void)
    {
       NRF_RTC_Type * pRTC = NRF_RTC0;
       // COUNTER and COMPARE[n] registers are all 24-bit. It seems an intermediate sampled
       // value must be used as pRTC->CC[1] += N; does not work for some reason, maybe requires
       // so many cycles to read back
       uint32_t CountValue = pRTC->COUNTER;
    #if 0
       // TICK is interrupt every Prescaler overflow (if enabled)
       if (pRTC->EVENTS_TICK == 1)
       {
          // 32.768kHz for 8-bit overflow with divisor set to 0 (ie /1) is 30.52 uSeconds
          pRTC->EVENTS_TICK = 0;
       }
       // OVRFLW is interrupt every RTC Counter overflow (if enabled)
       if (pRTC->EVENTS_OVRFLW == 1)
       {
          // 32.768kHz for 24-bit overflow with divisor set to 0 (ie /1) is 512 seconds
          pRTC->EVENTS_OVRFLW = 0;
       }
       // Unused, 1,2,3
       if (pRTC->EVENTS_COMPARE[1] == 1)
       {
          pRTC->EVENTS_COMPARE[1] = 0;
       }
    #endif
       if (pRTC->EVENTS_COMPARE[0] == 1)
       {
          pRTC->EVENTS_COMPARE[0] = 0;
          // Data Synchronization Barrier: completes when all explicit memory accesses before
          // last instruction completes to avoid spurious interrupt
          __DSB();
          // TIMER_TICK compare value, will generate next EVENTS_COMPARE[1]
          pRTC->CC[1] = CountValue + TIMER_TICK;
          // Update generic System Timer or whatever here
          // blahblah
       }
    }

    The preferred approach:

    //  Frequency fRTC [kHz] = 32.768 / (PRESCALER + 1 )
    //  24-bit counter so overflows from 0xFFFFFF to 0x000000, prescaler is 12-bit range 0-4095
    #define RTC_CRYSTAL_FREQUENCY   32768ul // Hz
    #define TIMER_PRESCALER             0   // (32768Hz/(PRESCALER+1)) -> 32.768KHz or 30.517us tick when prescaler is 0
    #define MSECS_PER_TICK             10   // Slower ticks means less power but also less accuracy, so choose a balance
    #define TIMER_TICK  ((RTC_CRYSTAL_FREQUENCY*MSECS_PER_TICK)/1000) // Assumes 30.517 us basic crystal tick but adjusts automatically
    
    void RTC0_IRQHandler(void)
    {
       NRF_RTC_Type * pRTC = NRF_RTC0;
       // COUNTER and COMPARE[n] registers are all 24-bit
       if (pRTC->EVENTS_COMPARE[0] == 1)
       {
          pRTC->EVENTS_COMPARE[0] = 0;
          // Data Synchronization Barrier: completes when all explicit memory accesses before
          // last instruction completes to avoid spurious interrupt
          __DSB();
           // TIMER_TICK compare value, will generate next EVENTS_COMPARE[1]
          pRTC->CC[1] += TIMER_TICK;
          // Update generic System Timer or whatever here
          // blahblah
       }
    }

Reply
  • The counter clear operation on the nRF52832 RTC doesn't generate a separate interrupt; and there are 2 other options. If this is the only interrupt used on the timer, you can trigger an overflow, which after 16 RTC ticks will behave as a counter clear and generate an interrupt if enabled.

    // Cane use timer overflow trigger as pseudo clear, overflows 16 ticks later
      pRTC->TASKS_TRIGOVRFLW;     // Set COUNTER to 0xFFFFF0

    If you have more than 1 interrupt in the RTC, then that not may be usable, in which case you can move the CC register forward on each interrupt to the next required value. There are two ways of doing this, read the current counter and add the offset to that or (preferably) add the offset directly to the CC register. The latter option has proved somewhat troublesome on occasion, but worth a try. The former risks losing accuracy as so many cycles are required to read the counter value. The sample code uses direct low-level registers to make clear what is going on; you can translate that the Nordic drivers if preferred.

    //  Frequency fRTC [kHz] = 32.768 / (PRESCALER + 1 )
    //  24-bit counter so overflows from 0xFFFFFF to 0x000000, prescaler is 12-bit range 0-4095
    #define RTC_CRYSTAL_FREQUENCY   32768ul // Hz
    #define TIMER_PRESCALER             0   // (32768Hz/(PRESCALER+1)) -> 32.768KHz or 30.517us tick when prescaler is 0
    #define MSECS_PER_TICK             10   // Slower ticks means less power but also less accuracy, so choose a balance
    #define TIMER_TICK  ((RTC_CRYSTAL_FREQUENCY*MSECS_PER_TICK)/1000) // Assumes 30.517 us basic crystal tick but adjusts automatically
    
    void RTC0_IRQHandler(void)
    {
       NRF_RTC_Type * pRTC = NRF_RTC0;
       // COUNTER and COMPARE[n] registers are all 24-bit. It seems an intermediate sampled
       // value must be used as pRTC->CC[1] += N; does not work for some reason, maybe requires
       // so many cycles to read back
       uint32_t CountValue = pRTC->COUNTER;
    #if 0
       // TICK is interrupt every Prescaler overflow (if enabled)
       if (pRTC->EVENTS_TICK == 1)
       {
          // 32.768kHz for 8-bit overflow with divisor set to 0 (ie /1) is 30.52 uSeconds
          pRTC->EVENTS_TICK = 0;
       }
       // OVRFLW is interrupt every RTC Counter overflow (if enabled)
       if (pRTC->EVENTS_OVRFLW == 1)
       {
          // 32.768kHz for 24-bit overflow with divisor set to 0 (ie /1) is 512 seconds
          pRTC->EVENTS_OVRFLW = 0;
       }
       // Unused, 1,2,3
       if (pRTC->EVENTS_COMPARE[1] == 1)
       {
          pRTC->EVENTS_COMPARE[1] = 0;
       }
    #endif
       if (pRTC->EVENTS_COMPARE[0] == 1)
       {
          pRTC->EVENTS_COMPARE[0] = 0;
          // Data Synchronization Barrier: completes when all explicit memory accesses before
          // last instruction completes to avoid spurious interrupt
          __DSB();
          // TIMER_TICK compare value, will generate next EVENTS_COMPARE[1]
          pRTC->CC[1] = CountValue + TIMER_TICK;
          // Update generic System Timer or whatever here
          // blahblah
       }
    }

    The preferred approach:

    //  Frequency fRTC [kHz] = 32.768 / (PRESCALER + 1 )
    //  24-bit counter so overflows from 0xFFFFFF to 0x000000, prescaler is 12-bit range 0-4095
    #define RTC_CRYSTAL_FREQUENCY   32768ul // Hz
    #define TIMER_PRESCALER             0   // (32768Hz/(PRESCALER+1)) -> 32.768KHz or 30.517us tick when prescaler is 0
    #define MSECS_PER_TICK             10   // Slower ticks means less power but also less accuracy, so choose a balance
    #define TIMER_TICK  ((RTC_CRYSTAL_FREQUENCY*MSECS_PER_TICK)/1000) // Assumes 30.517 us basic crystal tick but adjusts automatically
    
    void RTC0_IRQHandler(void)
    {
       NRF_RTC_Type * pRTC = NRF_RTC0;
       // COUNTER and COMPARE[n] registers are all 24-bit
       if (pRTC->EVENTS_COMPARE[0] == 1)
       {
          pRTC->EVENTS_COMPARE[0] = 0;
          // Data Synchronization Barrier: completes when all explicit memory accesses before
          // last instruction completes to avoid spurious interrupt
          __DSB();
           // TIMER_TICK compare value, will generate next EVENTS_COMPARE[1]
          pRTC->CC[1] += TIMER_TICK;
          // Update generic System Timer or whatever here
          // blahblah
       }
    }

Children
Related