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

sd_nvic_System_Reset() causes my application to hang until WDT timeout

I'm working on a project based on nRF52840 and nRF5 SDK16. I'm using BLE with softdevice S140 7.0.1 and USB CDC ACM for communication with a USB host. Ultimately the problem I'm trying to solve is jumping to the bootloader so I can use nrfutil to send a firmware update over USB. After I flash the bootloader and softdevice before there is an application present, I can send the application via USB without issues. However, if my application is running and I'm trying to jump to (and stay in) the bootloader, I run into problems.

To tell my application to jump to the bootloader, I send a custom command over USB. My application then writes the BOOTLOADER_DFU_START magic number to the GPREGRET register and then calls sd_nvic_SystemReset(). The bootloader is then supposed to see the magic number in GPREGRET and stay in the bootloader to receive the new application firmware.

However what happens instead is calling sd_nvic_SystemReset() actually locks up my application until my watchdog timer times out and resets the system. (My watchdog is relatively short so it took me a while to realize this was happening). The problem with this is it looks like GPREGRET does not persist through a watchdog reset, so my bootloader will not see the magic number in GPREGRET and will instead jump right back to the application.

So what might be causing my application to hang when sd_nvic_SystemReset() is called?

One other bit of weirdness I've run into recently that I can't help but wonder if it's related is the LFCLK settings. I'm currently running on the nRF52840 DK with plans to move to custom hardware once I get this working. The nRF52840 DK has a 32kHz crystal so I naturally assumed I'd use that for the LFCLK source. But through trial and error, the only way I could get both USB and the softdevice to initialize without parameter errors was by setting the LFCLK source to the internal RC oscillator. I'd love to solve this problem too, but I'm not too concerned about it unless it's related to the bigger issue above preventing me from staying in my bootloader.

Thanks.

Parents
  • Hi Sydney,
    Could you double check that the code actually hang at sd_nvic_SystemReset() ? It should reset immediately after the call. 
    I suspect that it actually jumped to the bootloader, however, if the bootloader doesn't handle the WDT properly (or too late to handle it), the WDT will reset and then you end up the GPREGRET be cleared. 

    We have a bug inside the bootloader that may cause it not to handle the WDT properly. In nrf_bootloader_dfu_timers.c :

    static void timer_init(void)
    {
        static bool m_timer_initialized;
    
        if (!m_timer_initialized)
        {
            if (!nrf_clock_lf_is_running())
            {
                nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTART);
            }

    The line  if (!nrf_clock_lf_is_running()) should be removed. The reason for that is that if the WDT is running the LF clock is active but it only provides the clock to the WDT , not to the RTC. So we need to trigger the LFCLKSTART anyway if we want to use RTC (then RTC will be used to feed the WDT). 

    If the patch doesn't work for you, I would suggest to try testing if you can trigger a sd_nvic_SystemReset() immediately from your application (for example remove the bootloader, run only the application and try to trigger a reset , check if it reboot immediately or not (you can toggle a GPIO at the beginning of your application/bootloader)).
    Also please try testing with longer WDT, and check if it's handled properly inside the Bootloader. 


Reply
  • Hi Sydney,
    Could you double check that the code actually hang at sd_nvic_SystemReset() ? It should reset immediately after the call. 
    I suspect that it actually jumped to the bootloader, however, if the bootloader doesn't handle the WDT properly (or too late to handle it), the WDT will reset and then you end up the GPREGRET be cleared. 

    We have a bug inside the bootloader that may cause it not to handle the WDT properly. In nrf_bootloader_dfu_timers.c :

    static void timer_init(void)
    {
        static bool m_timer_initialized;
    
        if (!m_timer_initialized)
        {
            if (!nrf_clock_lf_is_running())
            {
                nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTART);
            }

    The line  if (!nrf_clock_lf_is_running()) should be removed. The reason for that is that if the WDT is running the LF clock is active but it only provides the clock to the WDT , not to the RTC. So we need to trigger the LFCLKSTART anyway if we want to use RTC (then RTC will be used to feed the WDT). 

    If the patch doesn't work for you, I would suggest to try testing if you can trigger a sd_nvic_SystemReset() immediately from your application (for example remove the bootloader, run only the application and try to trigger a reset , check if it reboot immediately or not (you can toggle a GPIO at the beginning of your application/bootloader)).
    Also please try testing with longer WDT, and check if it's handled properly inside the Bootloader. 


Children
Related