Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

freeRTOS tick (LFCLK?) goes nuts after bootloader DFU

Hi, 

We have developed a wearable device using the following config: nRF52832, SDK14.2, freertos based app, SD5.0.0 and secure_dfu_bootloader

Our device is headless hence we use 'buttonless dfu' method

Everything works well including app OTA.

Now we need apply a minor modification to the existing bootloader and OTA the modified bootloader.

Here is the sequence of operations:

  1. I've built the modified version of the secured bootloader

  2. I've generated a dfu package using the following command:
    nrfutil pkg generate --hw-version 52 --bootloader-version 1 --bootloader bootloader.hex --sd-req 0x9D --key-file private.key bl_dfu_package.zip

    Note that I had to promote --bootloader-version to 1 (it was 0 in the original bl), otherwise it didn't work

  3. I've put a working device into (buttonless) dfu mode and did OTA dfu of the above package (bl_dfu_package.zip)
  4. The dfu procedure completed successfully and the bootloader resets the device to reboot in the recently updated configuration
  5. The freertos based app starts running at increased speed. I estimate that the freertos scheduler clock runs approx. x30 times faster than it should (I guess at 32KHz tick interval instead of 1024 Hz)
  6. After forcing a soft reset using sd_nvic_SystemReset() or hard reset (reset button), everything boots up and runs at normal speed

What can be the reason that the first reset (after dfu completes) boots the system differently than the 2nd one?

Thanks

Parents
  • Hi.

    We are actually a little short on FreeRTOS and DFU expertise at the moment, due to summer vacation here in Norway. I'll try to track down the root cause of this, but some delay in response time will be expected. 

    Sorry for the inconvenience. 
    Best regards, 
    Joakim Jakobsen
     

  • Hi, 

    I've tracked down the root cause - It is indeed a problem with the rtos tick clock source (RTC1).

    I've added RTC1->PRESCALER value printout in one of the tasks startup code.

    On normal system start, this value ix 0x1F as expected (dividing 32768Hz LFCLK by 32 = 1024Hz)

    On system start after BL DFU, this value is 0 !! hence the x32 tick speed.

    The nRF52832 datasheet mentions that the prescaler has to be stopped before its value can be set, so I've added a call to stop the clock in the rtos tick initialization routine vPortSetupTimerInterrupt(), however it still does not solve the problem.

    void vPortSetupTimerInterrupt( void )
    {
        /* Request LF clock */
        nrf_drv_clock_lfclk_request(NULL);
    
        /* Configure SysTick to interrupt at the requested rate. */
    	nrf_rtc_task_trigger (portNRF_RTC_REG, NRF_RTC_TASK_STOP);	// << Added this line
        nrf_rtc_prescaler_set(portNRF_RTC_REG, portNRF_RTC_PRESCALER);
        nrf_rtc_int_enable   (portNRF_RTC_REG, RTC_INTENSET_TICK_Msk);
        nrf_rtc_task_trigger (portNRF_RTC_REG, NRF_RTC_TASK_CLEAR);
        nrf_rtc_task_trigger (portNRF_RTC_REG, NRF_RTC_TASK_START);
        nrf_rtc_event_enable(portNRF_RTC_REG, RTC_EVTEN_OVRFLW_Msk);
    
        NVIC_SetPriority(portNRF_RTC_IRQn, configKERNEL_INTERRUPT_PRIORITY);
        NVIC_EnableIRQ(portNRF_RTC_IRQn);
    }
    

    On what circumstances does this register (RTC1->PRESCALER) is zerod (other than hard reset)

    What can be the reason it is not being set as requested in vPortSetupTimerInterrupt() ?

    Thanks

Reply
  • Hi, 

    I've tracked down the root cause - It is indeed a problem with the rtos tick clock source (RTC1).

    I've added RTC1->PRESCALER value printout in one of the tasks startup code.

    On normal system start, this value ix 0x1F as expected (dividing 32768Hz LFCLK by 32 = 1024Hz)

    On system start after BL DFU, this value is 0 !! hence the x32 tick speed.

    The nRF52832 datasheet mentions that the prescaler has to be stopped before its value can be set, so I've added a call to stop the clock in the rtos tick initialization routine vPortSetupTimerInterrupt(), however it still does not solve the problem.

    void vPortSetupTimerInterrupt( void )
    {
        /* Request LF clock */
        nrf_drv_clock_lfclk_request(NULL);
    
        /* Configure SysTick to interrupt at the requested rate. */
    	nrf_rtc_task_trigger (portNRF_RTC_REG, NRF_RTC_TASK_STOP);	// << Added this line
        nrf_rtc_prescaler_set(portNRF_RTC_REG, portNRF_RTC_PRESCALER);
        nrf_rtc_int_enable   (portNRF_RTC_REG, RTC_INTENSET_TICK_Msk);
        nrf_rtc_task_trigger (portNRF_RTC_REG, NRF_RTC_TASK_CLEAR);
        nrf_rtc_task_trigger (portNRF_RTC_REG, NRF_RTC_TASK_START);
        nrf_rtc_event_enable(portNRF_RTC_REG, RTC_EVTEN_OVRFLW_Msk);
    
        NVIC_SetPriority(portNRF_RTC_IRQn, configKERNEL_INTERRUPT_PRIORITY);
        NVIC_EnableIRQ(portNRF_RTC_IRQn);
    }
    

    On what circumstances does this register (RTC1->PRESCALER) is zerod (other than hard reset)

    What can be the reason it is not being set as requested in vPortSetupTimerInterrupt() ?

    Thanks

Children
  • OK, I've nailed the problem - 

    On top the addition in my prev. post, there should be a short delay to compensate for the HFCLK-LFCLK jitter (see here).

    For the sake of fellow developers attached is the final modified code (+ #include "nrf_delay.h" at the beginning of the file):

    void vPortSetupTimerInterrupt( void )
    {
        /* Request LF clock */
        nrf_drv_clock_lfclk_request(NULL);
    
        /* Configure SysTick to interrupt at the requested rate. */
    	nrf_rtc_task_trigger (portNRF_RTC_REG, NRF_RTC_TASK_STOP);	// << Add these...
    	nrf_delay_ms(1);	                                        // << ...two lines
        nrf_rtc_prescaler_set(portNRF_RTC_REG, portNRF_RTC_PRESCALER);
        nrf_rtc_int_enable   (portNRF_RTC_REG, RTC_INTENSET_TICK_Msk);
        nrf_rtc_task_trigger (portNRF_RTC_REG, NRF_RTC_TASK_CLEAR);
        nrf_rtc_task_trigger (portNRF_RTC_REG, NRF_RTC_TASK_START);
        nrf_rtc_event_enable(portNRF_RTC_REG, RTC_EVTEN_OVRFLW_Msk);
    
        NVIC_SetPriority(portNRF_RTC_IRQn, configKERNEL_INTERRUPT_PRIORITY);
        NVIC_EnableIRQ(portNRF_RTC_IRQn);
    }

    Nordic fellows, 

    Consider adding this fix (after validation of course) to the next SDK version/patch

    Good luck

  • Thanks for sharing the root cause and the fix with the rest of the community. 

    I'll forward your findings and feedback internally. 

    Best regards, 
    Joakim

Related