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

RTC1 IRQ not firing until debugger connected.

We're using an nRF52832, SDK14.0.0, SoftDevice 132 v5.

Early in our firmware lifecycle, before SoftDevice is enabled, we configure our PMIC. This involves performing some TWI transactions and then setting a single-shot app_timer with an expiry of ~126msec.

Around 10% of the time, from a warm reset, the RTC1 IRQ is not firing, so the app_timer list is never walked, and our timer's callback is never called.

When operating nominally, the RTC1 IRQ is raised after almost exactly 126msec, and our callback is executed.

When we detect the failure scenario, we attach-and-halt in SEGGER's Ozone debugger. The value of r15 confirms that we're in WFE mode, and our call stack correctly shows us in our "sleep until an event" loop that's part of our PMIC configuration. At this point, if we single-step, we immediately end up in the RTC1_IRQHandler and the system proceeds as normal.

Our loop looks roughly like this:

bool check_pmic(pmic_t *pmic) {
  send_twi_request(pmic);

  app_timer_create(my_timer, pmic_app_timer_expired_callback, pmic);
  app_timer_start(my_timer, 126msec_in_tics);
  
  while (waiting_for_pmic(pmic)) {
    sleep_cpu();
    poll_pmic(pmic);
  }
}

void sleep_cpu(void) {
  uint32_t const fpscr = __get_FPSCR();                                       
  uint32_t const fpscr_off = fpscr & ~(uint32_t)VCE_CPU_FPSCR_EXCEPTION_BITS_MASK;                   

  __set_FPSCR(fpscr_off);                                                     
  __get_FPSCR();                                                              

  NVIC_ClearPendingIRQ(VCE_CPU_IRQ_FPU);                                      

  if (nrf_sdh_is_enabled()) {                                                 
    sd_app_evt_wait();                                                        
  } else {                                                                    
    __WFE();                                                                  
  }                                                                           
}

With the details of the pmic stuff left as pseudocode, but our cpu_sleep function copied verbatim (comments scrubbed).

One thing I noticed is that SoftDevice is disabled, so the code path is just __WFE. I see that sd_app_evt_wait() is just a __WFE anyway, and that no path does the SEV / WFE / WFE pattern.

Anyway, what would cause RTC1 IRQ to not raise until a debugger is attached and stepped? Similarly, using SEGGER's RTT protocol (which turns on SWO) to drain our firmware logs causes the RTC1 IRQ to raise.

Parents
  • Update, enabling SoftDevice before we start using app_timer seems to fix the issue. I got an answer recently about app_timer and SoftDevice here, so I guess the answer must be something about how we're sleeping the CPU?

    https://devzone.nordicsemi.com/f/nordic-q-a/45266/ok-to-use-app_timer-before-nrf_sdh_enable_request

  • Hi,

    charles said:
    Update, enabling SoftDevice before we start using app_timer seems to fix the issue. I got an answer recently about app_timer and SoftDevice here, so I guess the answer must be something about how we're sleeping the CPU?

    The Softdevice starts the low-frequency clock source (crystal or RC oscillator depending on configuration). As a test, could you try to start the LF clock manually at the beginning of main to see if it has the same effect as enabling the Softdevice early, or are you doing this already? 

    Code to start LF clock:

    NRF_CLOCK->LFCLKSRC = 1; // Set clock source to external 32KHz crystal. Change to 0 to use internal RC.
    NRF_CLOCK->TASKS_LFCLKSTART = 1;
    while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0); 

    charles said:
    When a Nordic rep looks at this, could you also explain in precise detail what sd_app_evt_wait does? Maybe post the code? (I wonder if we're sleeping incorrectly, this is the only time we sleep the chip before SoftDevice is enabled.

    Calling sd_app_evt_wait is similar to calling the __WFE instruction from the app. The main difference is that sd_app_evt_wait does not return on internal Sofdevice events, only application events. 

    Best regards,

    Vidar

Reply
  • Hi,

    charles said:
    Update, enabling SoftDevice before we start using app_timer seems to fix the issue. I got an answer recently about app_timer and SoftDevice here, so I guess the answer must be something about how we're sleeping the CPU?

    The Softdevice starts the low-frequency clock source (crystal or RC oscillator depending on configuration). As a test, could you try to start the LF clock manually at the beginning of main to see if it has the same effect as enabling the Softdevice early, or are you doing this already? 

    Code to start LF clock:

    NRF_CLOCK->LFCLKSRC = 1; // Set clock source to external 32KHz crystal. Change to 0 to use internal RC.
    NRF_CLOCK->TASKS_LFCLKSTART = 1;
    while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0); 

    charles said:
    When a Nordic rep looks at this, could you also explain in precise detail what sd_app_evt_wait does? Maybe post the code? (I wonder if we're sleeping incorrectly, this is the only time we sleep the chip before SoftDevice is enabled.

    Calling sd_app_evt_wait is similar to calling the __WFE instruction from the app. The main difference is that sd_app_evt_wait does not return on internal Sofdevice events, only application events. 

    Best regards,

    Vidar

Children
Related