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

Bootloader WDT not Firing

Hi,

I am still investigating this but, I think it is best that we discuss it on this forum. 

I am using SDK 16.0.0, nRF52840, secure_bootloader_usb on a custom board. The problem appears to be the following:

My application is using the WDT to provide a means of system reset within 10 seconds if WDT is not refreshed. 

I am entering DFU by causing a writing to GPREGRET 0xB1 and causing a softreset with the purpose of downloading firmware via USB. 

At this point the bootloader takes control and should be able to identify that the WDT was running in the application and hence keep feeding it. 

Indeed, the bootloader checks for the enabled WDT and normally should enable RTC2 as a WDT refresh timer. 

What we are finding is that (at least in the release version of the bootloader) this is not happening. 

For some reason, the RTC2 interrupts are for Channel 2 (and Channel 1) compare are not enabled and the task of is also not enabled. The result is that the MCU is reset from the running WDT. 

Now comes the good part:

Trying to identify why this is happening we were setting breakpoints to various locations and checking what the firmware was doing. We found that in the file nrf_bootloader_dfu_timers and in the code shown below, a break point right at if(!m_timer_initialized) would do the trick.

/**@brief Function for initializing the timer if it is not already initialized.
 */
static void timer_init(void)
{
    static bool m_timer_initialized;

    if (!m_timer_initialized)
    {
        if (!nrf_clock_lf_is_running())
        {
            //nrf_clock_lf_src_set(NRF_CLOCK_LFCLK_Xtal_Full_Swing);      //Added VG 20200213
            //nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTART);
            //while(nrf_clock_lf_is_running() == false){}                 //Added VG 20200213 Wait till LFCLK Initializes

            lfclk_config();

        }
                        
        nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_TICK);
        nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_COMPARE_0);
        nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_COMPARE_1);
        NRFX_IRQ_PRIORITY_SET(RTC_IRQn, 5);
        NRFX_IRQ_ENABLE(RTC_IRQn);
        nrf_rtc_prescaler_set(RTC_STRUCT, RTC_PRESCALER);
        nrf_rtc_task_trigger(RTC_STRUCT, NRF_RTC_TASK_CLEAR);
        nrf_rtc_task_trigger(RTC_STRUCT, NRF_RTC_TASK_START);
        nrf_rtc_int_enable(RTC_STRUCT, RTC_INTENSET_OVRFLW_Msk);

        m_timer_initialized = true;
    }
}

When a break point is placed there, then after continuing code execution, the RTC2 timer starts normally and the interrupt CC2 is enabled. As a concsequence the WDT running is reset by RTC2 feed action. Breakpoints after this location in the code DO NOT have any effect. The RTC2 is not initialized correctly and does not feed the WDT. 

We cannot, at the moment, explain this behavior. Best guess is that it has do to with the way the code is written because the same routines are used to initialize the inactivity timer used by the bootloader. 

We will keep investigating but any help is greatly appreciated. 

Thanks.

  • Hello Einar,

    I tried what you suggested in the following:

    /**@brief Function for initializing the timer if it is not already initialized.
     */
    static void timer_init(void)
    {
        static bool m_timer_initialized;
            
        if (!m_timer_initialized)
        {
            /*if (!nrf_clock_lf_is_running())
            {           
                lfclk_config();               //VG 20200211 for init of LFCLK with external Oscillator
            }*/
                                   
            nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_TICK);
            nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_COMPARE_0);
            nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_COMPARE_1);
            NRFX_IRQ_PRIORITY_SET(RTC_IRQn, 5);
            NRFX_IRQ_ENABLE(RTC_IRQn);
            nrf_rtc_prescaler_set(RTC_STRUCT, RTC_PRESCALER);
            nrf_rtc_task_trigger(RTC_STRUCT, NRF_RTC_TASK_CLEAR);
            nrf_rtc_task_trigger(RTC_STRUCT, NRF_RTC_TASK_START);
            nrf_rtc_int_enable(RTC_STRUCT, RTC_INTENSET_OVRFLW_Msk);
                    
            m_timer_initialized = true;
        }
    }

    Indeed after reset, the LFCLKL shoul be running using the internal RC oscillator. So I tried not to initialize the LFCLK but let it run in RC mode. 

    The result is the same. The LFCLK should be running because I get a WDT reset after 10 seconds. The RTC2 IS NOT running no matter where I place the breakpoint. I can see the interrupts and CC registers initialized but the counter is not measuring hence the WDT causes a reset.

    Any ideas are welcome. What is Errata 101? I tried looking in nRF52840 documentation but could not find 101.

    Thanks.

  • Hi,

    I see. So the LF clock source has no impact on this issue. That is good news and expected really since it should not have any impact.

    I am puzzled about the fact that your tests show that using a breakpoint and continuing from there "fixes" the issue, but using a delay at the same location does not. If there is a timing issue, it would be the same. But in any case, breaching and continuing from breakpoint impacts the CPU, but not the RTC in any way, other than that potential interrupts are not cleared as soon as they would have been if the CPU were running. Could this be a clue?

    Can you stop the RTC before you start it, by implementing the suggested workaround for erratum 20?

    Erratum 101 was my bad. It is not relevant for the nRF52840 (but for the nRF52832).

  • Good morning Einar,

    Well, I think you got it. Although it is not clear to me why this works. I modified the timer_init code to the following:

    static void timer_init(void)
    {
        static bool m_timer_initialized;
            
        if (!m_timer_initialized)
        {
            /*if (!nrf_clock_lf_is_running())
            {           
                lfclk_config();               //VG 20200211 for init of LFCLK with external Oscillator
            }*/
    
            NRF_CLOCK->EVENTS_LFCLKSTARTED  = 0;              //20200511 Modified as per Nordic's suggestions. Solves the RTC2 Starting issue
            NRF_CLOCK->TASKS_LFCLKSTART     = 1;
            while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0) {}
            NRF_RTC0->TASKS_STOP = 0;
                                   
            nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_TICK);
            nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_COMPARE_0);
            nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_COMPARE_1);
            NRFX_IRQ_PRIORITY_SET(RTC_IRQn, 5);
            NRFX_IRQ_ENABLE(RTC_IRQn);
            nrf_rtc_prescaler_set(RTC_STRUCT, RTC_PRESCALER);
            nrf_rtc_task_trigger(RTC_STRUCT, NRF_RTC_TASK_CLEAR);
            nrf_rtc_task_trigger(RTC_STRUCT, NRF_RTC_TASK_START);
            nrf_rtc_int_enable(RTC_STRUCT, RTC_INTENSET_OVRFLW_Msk);
                    
            m_timer_initialized = true;
        }
    }

    Implementing Erratum 20. 

    This WORKS. RTC2 counter initializes normally and as a result the WDT which was operating in the application now is fed normally. The LFCLK source is the RC but that doesn't matter. I checked and in the application, I return LFCLK to XTAL and it works just fine. 

    Puzzled by this:

    The errata requests TASK STOP on RTC0 and this is what I added to the routine. How can a STOP TASK on RTC0 affect RTC2?

    Maybe this is because in my application all RTC were being used? RTC0 from the softdevice, RTC1 for application timers and RTC2 for a real time calendar?

    Anyway I am happy this is sorted and I can verify your answer above as a solution.

  • Hi,

    I am glad to hear you found an effective workaround. I am a bit surprised that changing the configuration of RTC0 has affected the issue for RTC2, but then again I do not understand the root cause of this issue.

Related