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 Reply
  • 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 :/

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

  • In my main application I actually enable a 1-millisecond timer also to keep track of time and I enable it before the BLE stack initialization, and I've never ever seen problems with that. Why does the application work with a way more demanding timer and the bootloader doesn't?

Related