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

NRF_CLOCK->LFCLKSTAT register contents are not properly evaluated after a system reset if RTC compare event 1 or 2 are used

I stumbled upon an issue where the LFCLKSTAT register in the NRF_CLOCK peripheral can not be properly evaluated after a softreset if the application that was running before the soft reset was executed uses either the COMPARE1 or COMPARE2 interrupt of an RTC peripheral.

I tried to condense the code leading to this issue to a concise excample.

The LFCLK startup code is shown below. I evaluate the LFCLKSTAT register first, because in a real-life application, the bootloader may have already started the LFCLK.

  if (((NRF_CLOCK->LFCLKSTAT & CLOCK_LFCLKSTAT_STATE_Msk) >> CLOCK_LFCLKSTAT_STATE_Pos) == 0)
  {
    // This block is never reached if RTC compare event 1 or 2 were used.
  
    // select LFCLK
    switch (m_lfclk_config.source)
    {
      case NRF_CLOCK_LF_SRC_RC:
        NRF_CLOCK->LFCLKSRC = CLOCK_LFCLKSRC_SRC_RC;
        break; // NRF_CLOCK_LF_SRC_RC
      
      case NRF_CLOCK_LF_SRC_XTAL:
        NRF_CLOCK->LFCLKSRC = CLOCK_LFCLKSRC_SRC_Xtal;
        break; // NRF_CLOCK_LF_SRC_XTAL
      
      case NRF_CLOCK_LF_SRC_SYNTH:
        NRF_CLOCK->LFCLKSRC = CLOCK_LFCLKSRC_SRC_Synth;
        break; // NRF_CLOCK_LF_SRC_SYNTH
    }
  
    NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
    // Enable interrupt, so we can call __WFE later.
    NRF_CLOCK->INTENSET = CLOCK_INTENSET_LFCLKSTARTED_Msk;

#if defined(NRF52832_XXAA) || defined(NRF52832_XXAB)
    nrfx_clock_anomaly_132();
#endif // defined(NRF52832_XXAA) || defined(NRF52832_XXAB)
    
    NRF_CLOCK->TASKS_LFCLKSTART = 1;
    while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0)
    {
      __WFE();
    }
    NRF_CLOCK->INTENCLR = CLOCK_INTENSET_LFCLKSTARTED_Msk;
    NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
  }

The code inside the above if-block does not get executed after a soft reset if RTC compare event 1 or 2 were used.

The main-function, which calls the above clock initialisation and initializes the RTC is shown below:

int main(void)
{ 
  nrf_gpio_cfg_output(28);
  nrf_gpio_cfg_output(4);
  
  // allow wakeup from sleep on pending interrupt
  SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
  
  nrf_gpio_pin_set(4);
  init_lfclk_f();
  nrf_gpio_pin_clear(4);
  
  // setup and start RTC0
  NRF_RTC0->PRESCALER = (RTC_PRESCALER - 1);
  NRF_RTC0->CC[1] = (NRF_RTC0->COUNTER + RTC_INTERVAL) & RTC_CNT_MAX;
  NRF_RTC0->INTENSET = RTC_INTENSET_COMPARE1_Msk;
  NRF_RTC0->EVTENSET = RTC_EVTEN_COMPARE1_Msk;
  NVIC_SetPriority(RTC0_IRQn, APP_IRQ_PRIORITY_LOW);
  NVIC_EnableIRQ(RTC0_IRQn);
  NRF_RTC0->TASKS_START = 1;
  
  // enable interrupts
  __ASM("CPSIE i");
  
  nrf_gpio_pin_set(28);
  
  while(1)
  {     
    // enter application wait
    __WFE();
  }
  return (0);
}

And the RTC0_IRQHandler...

void RTC0_IRQHandler(void)
{
  uint_fast32_t next_tick;
  static uint8_t num_invoked = 0;
    
  // COMPARE1 event ?
  if (NRF_RTC0->EVENTS_COMPARE[1] != 0)
  {
    // clear event
    NRF_RTC0->EVENTS_COMPARE[1] = 0;
    // force write operation to be done by reading the value back in Cortex M4F devices
    // URL: http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.nrf52.v1.0.0/migration/preface.html
    (void)NRF_RTC0->EVENTS_COMPARE[1];

    // calculate next tick
    next_tick = (NRF_RTC0->CC[1] + RTC_INTERVAL) & RTC_CNT_MAX;

    // set next tick
    NRF_RTC0->CC[1] = next_tick;
    
    if (++num_invoked == 3)
    {
      nrf_gpio_pin_clear(28);
      NVIC_SystemReset();
    }
  }
}

If using the COMPARE0 event instead of COMPARE1 or COMPARE2, the LFCLKSTAT register can be evaluated just fine after a reset. Also, when setting a debugger breakpoint *before* the clock initialisation, the register seems to be evaluated just fine. But an artificial delay in software does not seem to do the trick.

I've also attached the complete example in a zip file:

/cfs-file/__key/support-attachments/beef5d1b77644c448dabff31668f3a47-cc406bf8178b42319c481185b5dab4c1/rtc_2D00_lfclk_2D00_problem.zip

I think, this is actually related to this unresolved issue I had a few months back: https://devzone.nordicsemi.com/f/nordic-q-a/27195/lfclk-related-issues-in-sdk14-dfu

Parents
  • Hi,

     

    I can confirm the same behavior at my end as well, running on a nRF52832 rev 2 (E00) device. Saving the LFCLKSTAT content to a global shows that it is set to 0x10001, but if you read the LFCLKSTAT register some time afterwards, it is 0x00000.

    By adding the errata #132 delay (nrfx_clock_anomaly_132()) before reading the NRF_CLOCK->LFCLKSTAT register, this seems to fix the issue.

    I will report this internally. Thank you very much for reporting this to us, and thank you for providing code that reproduces the issue as well.

     

    Kind regards,

    Håkon

     

  • Hi Håkon,

    Thanks for the quick response. I actually thought, that I did test it with the errata #132 delay invoked before reading the NRF_CLOCK->LFCLKSTAT register, but it seems that I really didn't. For me, this is a viable workaround for now. Nonetheless, I would be happy if you could share any insights from your internal analysis.

    Regards,

    -mike

Reply Children
No Data
Related