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

Timer V2 in bootloader SDK15

Hello,

I'm working in a bootloader based on the one included with SDK15. I want to add a timer that fires every 50 ms to keep track of time. The purpose of this timer is to generate unblocking delays for some tasks that have to do with interfacing another bootloader in a STM32. However, when I add this timer, the bootloader keeps working but the other timers don't work anymore.

I have added another timer to blink an LED while a DFU is in process.

This is the code I added to nrf_bootloader_dfu_timers.c.

Initialization of timers:

/**@brief Initialization of app_timer. Function ensures that initialization happens only once.
 */
static void timer_init(void)
{
    if (!m_app_timer_initialized)
    {
        if (!nrf_clock_lf_is_running())
        {
            nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTART);

            // Wait for the clock to be ready.
            while (!nrf_clock_lf_is_running()) {;}
        }

        uint32_t err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);

        // Start a single shot timer that will reset the DFU on timeout.
        err_code = app_timer_create(&m_dfu_inactivity_timer,
                                    APP_TIMER_MODE_SINGLE_SHOT,
                                    timeout_handler);
        ASSERT(err_code == NRF_SUCCESS);

        err_code = app_timer_create(&m_wdt_feed_timer,
                                    APP_TIMER_MODE_REPEATED,
                                    timeout_handler);
        ASSERT(err_code == NRF_SUCCESS);

        err_code = app_timer_create(&m_led_blink_timer,
									APP_TIMER_MODE_REPEATED,
									timeout_handler);
		ASSERT(err_code == NRF_SUCCESS);

		err_code = app_timer_create(&m_boot_clock_timer,
									APP_TIMER_MODE_REPEATED,
									timeout_handler);
		ASSERT(err_code == NRF_SUCCESS);

        m_app_timer_initialized = true;
    }
}

Timer start:

void nrf_bootloader_dfu_inactivity_timer_restart(uint32_t timeout_ms, nrf_bootloader_dfu_timeout_callback_t callback)
{
    timer_start(m_dfu_inactivity_timer, timeout_ms, callback);
}


void nrf_bootloader_wdt_feed_timer_start(uint32_t timeout_ms, nrf_bootloader_dfu_timeout_callback_t callback)
{
    timer_start(m_wdt_feed_timer, timeout_ms, callback);
}


void nrf_bootloader_led_blink_timer_start(uint32_t timeout_ms, nrf_bootloader_dfu_timeout_callback_t callback)
{
    timer_start(m_led_blink_timer, timeout_ms, callback);
}


void nrf_bootloader_boot_clock_timer_start(uint32_t timeout_ms, nrf_bootloader_dfu_timeout_callback_t callback)
{
    timer_start(m_boot_clock_timer, timeout_ms, callback);
}

I have noticed that the whole thing works depending on the firing frequency of the timers. Maybe it has something to do with the timer FIFO getting full? I don't get any errors, the bootloader still advertises and performs DFUs normally. It's just the timers that aren't working.

For example this doesn't work when the timeout of the LED blink timer is 800 ms and the clock timer is 50 ms. It does however work with 800 ms and 200 ms. If I want to blink the LED faster it also doesn't work (i.e. 200 ms and 200 ms). Where could this be failing?

Thanks for your help!

Parents
  • Hi Andy, 

     

    We tried here and was seeing the same issue. We will have further investigation and let you know what we find. 

     

     

  • Thanks Hung, I will wait for your verdict :)

  • Hi Andy, 

     

    We haven't found the root cause yet. However, I found that if I start the timers  after the MBR initialize the softdevice then it works fine. My suggestion for now is to start your app timer (nrf_bootloader_led_blink_timer_start)  after the call nrf_dfu_init() inside nrf_bootloader_init(). 

    Strange enough, if I use larger timeout timer, it works regardless where the timer is started. I guess it has something to do with the timing of the RTC due to the initialize of the softdevice. I will report this to R&D and get back to you when we have an update. 

    For now, please try the workaround and let me know the result. 

     

  • Hi Hung, your workaround did indeed fix the issue. I don't really understand why though. I am initializing all my stuff in nrf_dfu_user_init(), which is executed just before nrf_dfu_init(). I moved it after and it looks like it works now.

  • After testing some more I found out that this workaround breaks my bootloader in certain conditions, since I use the NVMC to write some code to flash on the very first boot. I was doing this before initializing the Softdevice so there was never a problem, now that I moved that initialization I would have to either use sd functions to write to UICR, or to split my initialization routine in two, to initialize stuff before and after the SD initialization.

    I'll split it for now, but this is not ideal :/

  • Problem is caused by the fact that enabling softdevice is messing with interrupt vector table. There are couple of vector tables in the system:

    - in mbr, root vector table at 0x0

    - in softdevice

    - in bootloader

    - in application (if present)

    When softdevice is enabled in the bootloader switch occurs. MBR starts to forward interrupts to Softdevice instead of bootloader. Then bootloader provides own vector table address to softdevice (sd_softdevice_vector_table_base_set(BOOTLOADER_START_ADDR)) to let know softdevice where to forward application interrupts (one not handled by softdevice).

    Unfortunately, this operation is not atomic. First nrf_dfu_mbr_init_sd() is called and then table is set. If any interrupt occurs in that spot softdevice will get it and will crash because it has no vector table to forward that interrupt to.

    I know that it's a bit tricky but you should ensure that no interrupt happends until softdevice is fully enabled.

Reply
  • Problem is caused by the fact that enabling softdevice is messing with interrupt vector table. There are couple of vector tables in the system:

    - in mbr, root vector table at 0x0

    - in softdevice

    - in bootloader

    - in application (if present)

    When softdevice is enabled in the bootloader switch occurs. MBR starts to forward interrupts to Softdevice instead of bootloader. Then bootloader provides own vector table address to softdevice (sd_softdevice_vector_table_base_set(BOOTLOADER_START_ADDR)) to let know softdevice where to forward application interrupts (one not handled by softdevice).

    Unfortunately, this operation is not atomic. First nrf_dfu_mbr_init_sd() is called and then table is set. If any interrupt occurs in that spot softdevice will get it and will crash because it has no vector table to forward that interrupt to.

    I know that it's a bit tricky but you should ensure that no interrupt happends until softdevice is fully enabled.

Children
Related