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

Force MBR to jump to bootloader on GPIO input?

Hi Nordic,

We're developing a product based on the nRF52810 and got the following question:

We were wondering if we can recover a board in the worst-case scenario where a valid OTA is applied, but due to a bug not caught in QA, it somehow renders the device unusable.

Take the following case for example:  

A persistent setting is read from flash on startup, and on certain values of the setting the board will crash right after boot.

It got through QA because it only happens in the unlikely case that this particular value is written to the flash at some point, or as a result of power loss while writting to the flash. The next time it boots it will instantly crash without a chance to telling the MBR to go into DFU mode again.

We would love to implement a safety mechanism to escape this situation and unbrick affected devices, where the user can press the RESET button (we're using the RESET pin) and possibly by releasing it and pressing again in a short timeframe the board would go into bootloader mode again for the chance to install a fixed version of the firmware.

To be totally safe, this would be ideally done in the MBR as follows.

On the MBR entry point, the reason of reset is checked.

if it's a hard reset then

Reconfigure the RESET button as a regular GPIO and start a 500 ms timer

if the GPIO is set low and the high before the timer expires then

reconfigure the GPIO as RESET again and jump to the bootloader ignoring the DFU settings in flash

else

proceed to the user firmware

else 

proceed like normal (check if there is a DFU command pending, ....)

I'm aware that the MBR source code is proprietary and not intended to be updated or modified. So I'm asking for alternative ideas to implement such a security mechanism.

Probably it's easier to build that into the asm startup code of the app firmware to be run right before main() and never touch it in any subsequent firmware update once it's working. The potential bricking code would always be after main()...

Is there already some support for this in the SDK/hardware?, can you recommend a better way of achieving this?

Thanks in advance!
Mike

  • Reconfigure the RESET button as a regular GPIO and start a 500 ms timer

    Not safely possible. UICR erase is a very dangerous operation, and would be the only way to reconfigure the pin.

    Note that the normal boot process is MBR->bootloader->app, so your pin check can simply be done in the bootloader itself.

    In many cases you also have a way to cut power (removing the power source in order to trigger POR), so you don't really need the reset pin function in the final design and could configure the GPIO as a "bootloader" button.

  • Would also not recommend changing the rest pin like Turo J stated.

    Might want to have a look at the General purpose retention registers (GPREGRET and GPREGRET2). These register retain there value after a rest.

    infocenter.nordicsemi.com/index.jsp

    There are some reserved values for the bootloader.
    https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v15.3.0/group__nrf__bootloader__info.html

    More info on the bootloader
    https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/getting-started-with-nordics-secure-dfu-bootloader

    In essence write GPREGRET = 0xB1 and some value to GPREGRET2 when you hit the error and when the user presses reset the device will enter bootloader.

  • As Turbo J says:

    Turbo J said:
    Note that the normal boot process is MBR->bootloader->app, so your pin check can simply be done in the bootloader itself.

     Infact the bootloader can also be configured to check a certain GPIO pin on startup and stay in DFU mode if this pin is low. See dfu_enter_check() in dfu_bootloader.c, which is called in nrf_bootloader_init().

    static bool dfu_enter_check(void)
    {
        if (!app_is_valid(crc_on_valid_app_required()))
        {
            NRF_LOG_DEBUG("DFU mode because app is not valid.");
            return true;
        }
    
        if (NRF_BL_DFU_ENTER_METHOD_BUTTON &&
           (nrf_gpio_pin_read(NRF_BL_DFU_ENTER_METHOD_BUTTON_PIN) == 0))
        {
            NRF_LOG_DEBUG("DFU mode requested via button.");
            return true;
        }
    
        if (NRF_BL_DFU_ENTER_METHOD_PINRESET &&
           (NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk))
        {
            NRF_LOG_DEBUG("DFU mode requested via pin-reset.");
            return true;
        }
    
        if (NRF_BL_DFU_ENTER_METHOD_GPREGRET &&
           (nrf_power_gpregret_get() & BOOTLOADER_DFU_START))
        {
            NRF_LOG_DEBUG("DFU mode requested via GPREGRET.");
            return true;
        }
    
        if (NRF_BL_DFU_ENTER_METHOD_BUTTONLESS &&
           (s_dfu_settings.enter_buttonless_dfu == 1))
        {
            NRF_LOG_DEBUG("DFU mode requested via bootloader settings.");
            return true;
        }
    
        return false;
    }

    Best regards

    Bjørn 

  • Hi,

    Thank you both for your advice and suggestions

    UICR erase is a very dangerous operation

    I wasn't aware of that. Discarded then.

    Note that the normal boot process is MBR->bootloader->app, so your pin check can simply be done in the bootloader itself.

    Nice!, having that functionality built into the bootloader is better and more convenient.

    In essence write GPREGRET = 0xB1 and some value to GPREGRET2 when you hit the error and when the user presses reset the device will enter bootloader.

    Well, if by "when you hit the error" you mean in the app fault handler, as you pointed out the result would be that the device would boot into bootloader mode when pressing RESET if there was a crash (in the case of getting stuck in an infinite loop, perhaps I can configure the watchdog to trigger an exception as well (not sure)). In this case, I don't really like the idea of forcefully going into DFU on any crash, since a crash doesn't mean that the device is bricked.

    That's why I'm after a solution that lets the user voluntarily reboot into DFU without app firmware assistance.

    Our device has only one pushbutton designated as RESET. Ideally, the same button would hard reset the device (short press), or reset into DFU (long press, double press...)


    On the other hand, having crash handlers able to reset the device on crash and a watchdog, then probably the hard RESET function is not that important and I can use the push button as a regular GPIO to check at the entry point of the bootloader, and if pressed during normal firmware operation perform a soft reset.

    Does this sound reasonable?. How do other nRF-based consumer products handle it?

    Thanks again!

    Mike

  • Mike Melbot said:
    Our device has only one pushbutton designated as RESET. Ideally, the same button would hard reset the device (short press), or reset into DFU (long press, double press...)

     If this one button is tied to the RESET pin and this is enabled in UICR, then you will not be able to distinguish short presses and long presses as a single press will reset the device.

    Mike Melbot said:
    On the other hand, having crash handlers able to reset the device on crash and a watchdog, then probably the hard RESET function is not that important and I can use the push button as a regular GPIO to check at the entry point of the bootloader, and if pressed during normal firmware operation perform a soft reset.

     This sound like the better idea.

    Best regads

    Bjørn

Related