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.

Parents
  • Hi,

    This is odd. There should not be any other code in the bootloader that touches RTC2. Can you share any changes you have done to the bootloader?

  • Hello Einar,

    Thanks for comming back so quickly. It is odd and what is frustrating is why a breakpoint allows the RTC2 to be triggered. 

    Indeed I did some changes to the bootloader but I cannot see how these may affect it. Let me explain:

    In the file nrf_bootloader_dfu_timers I needed to change the way the LFCLK is initialized because I am using an external oscillator and not a crystal. The routine timer_init has been modified to:

    /**@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();            
            }
                                   
            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;
        }
    }

    where the routine lfclk_config is the following:

    static void lfclk_config(void)
    {      
        bool lfclk_running=	nrfx_clock_lfclk_is_running();
         	                  
             NRF_CLOCK->LFCLKSRC = LFCLKSRC_XTERNAL_OSCILLATOR;  
            
             if(lfclk_running == false){
               	nrfx_clock_lfclk_start();
             }
          
          while(nrfx_clock_lfclk_is_running() == false){
          }
    }

    Another minor modification is in the nrf_bootloader.c file where I introduced a port initialization in the nrf_dfu_init_user routine as shown below:

    /**@brief Weak implementation of nrf_dfu_init
     *
     * @note    This function must be overridden in application if
     *          user-specific initialization is needed.
     */
    __WEAK uint32_t nrf_dfu_init_user(void)
    {
        NRF_LOG_DEBUG("in weak nrf_dfu_init_user");
    
        ports_init();                                     
    
        return NRF_SUCCESS;
    }

    ports_init only intializes input and output ports for our custom board

    Also in the file nrf_dfu_req_handler.c I added a bit of code for toggling an LED inside the dfu_req_handler as shown below:

    static void nrf_dfu_req_handler_req(void * p_evt, uint16_t event_length)
    {
        nrf_dfu_request_t * p_req = (nrf_dfu_request_t *)(p_evt);
        nrf_dfu_req_handler_req_process(p_req);
        nrf_gpio_pin_toggle(LED_RED);                                                 
    }

    This toggles an LED. 

    Finally in main.c I only added toggling of LEDs where needed as shown below:

    static void dfu_observer(nrf_dfu_evt_type_t evt_type)
    {
        switch (evt_type)
        {
            case NRF_DFU_EVT_DFU_FAILED:
            case NRF_DFU_EVT_DFU_ABORTED:
            case NRF_DFU_EVT_DFU_INITIALIZED:
    
                //bsp_board_init(BSP_INIT_LEDS);
                //bsp_board_led_on(BSP_BOARD_LED_0);
                //bsp_board_led_on(BSP_BOARD_LED_1);
                //bsp_board_led_off(BSP_BOARD_LED_2);
                nrf_gpio_pin_clear(LED_GRN);
                nrf_gpio_pin_clear(LED_RED);
                break;
            case NRF_DFU_EVT_TRANSPORT_ACTIVATED:
                //bsp_board_led_off(BSP_BOARD_LED_1);
                //bsp_board_led_on(BSP_BOARD_LED_2);            
                nrf_gpio_pin_set(LED_RED);            
                break;
            case NRF_DFU_EVT_DFU_STARTED:            
                break;
    
            default:
                break;
        }
    }

    I cannot see how, these modifications could affect the triggering of RTC2. 

    Meanwhile I tried using RTC1 or RTC0 but the result is the same. I also tried to introduce nrfx driver for the RTC and trigger it with the nrfx driver rather than the RTC HAL and this did not have any effect. 

    Let me know of your opinion. 

  • 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.

Reply Children
No Data
Related