Written by Mohammed Billoo, Embedded Linux Consultant, MAB Labs Embedded Solutions
Overview
An essential feature of any embedded system is the capability to update the embedded software. This is accomplished using a bootloader, another application running on the embedded system. However, a bootloader is quite different from a traditional application because it has specific responsibilities. These include:
- Configuring the processor and appropriate peripherals to be able to jump to the application and update the application
- Jumping to the application
- Interfacing with external entities to support application updates
In Zephyr RTOS, MCUboot serves as the bootloader. MCUmgr can be used as the host-side application to interface with the MCUboot.
As of the writing of this blog post, MCUboot requires an external stimulus, such as a GPIO pin being pressed, to prevent it from jumping to the application. Human intervention is needed to update the application software, which may not be possible on an embedded system. In this blog post, we will discuss the necessary modifications to MCUboot to support in-field updates without requiring an external stimulus. We will also discuss the corresponding implementation in the application to support the MCUboot changes. It is important to note that the implementation discussed in this blog post assumes that we’re using a Nordic nRF SoC.
MAB Labs recently supported a client with these changes, and we thought we’d share our findings with the rest of the community, hoping that it would also help others. We implemented and tested these changes on a Nordic nRF5340 SoC.
MCUboot Modifications
As of writing this blog post, MCUboot supports remaining in the bootloader only by an external stimulus, as shown below:
The above snippet is one of the first lines of code to be executed inside the “main” function, if the compile-time MCUBOOT_SERIAL configuration is enabled. If so, it detects the state of the specified GPIO pin, and if the state matches the specified state, the console will be initialized, and the embedded software will remain in bootloader mode. MCUboot will then be able to respond to commands from an external entity, such as MCUmgr.
We will borrow mechanisms from the Nordic nRF SDK to support automatic in-field updates. Nordic nRF SoCs have the GPREGRET register, which has been the canonical mechanism to support automatic updates (or what’s referred to as “buttonless DFU”).
We can leverage this register in MCUboot with the following change:
The above code snippet checks the value of the GPREGRET register. Suppose the least significant bit is set, a signal from the application that an in-field update is desired. In that case, MCUboot will prepare itself to interface with an external application to perform the update. It will also clear the least significant bit to prevent a boot loop from occurring. It is important to note that the MCUBOOT_SERIAL configuration option must be enabled if the UART interface is used to transfer the application image.
Application Modifications
The application software also needs to be modified to support the above changes to MCUboot, beyond just enabling the BOOTLOADER_MCUBOOT configuration option in the application’s “prj.conf” file. The requisite changes are shown below:
The above code sets the least significant bit of the GPREGRET register, sleeps for 1.5 seconds, and resets the SoC. After the SoC resets, MCUboot will first execute. MCUboot will check the value of the GPREGRET register, identify that the least significant bit is set, and will not jump to the application to support a firmware update.
Summary
This blog post showed how MCUboot could be modified to support in-field firmware updates without human intervention. We also saw the changes needed in the application to support the same feature. It is important to note that while the exact modifications described in this post are only relevant for Nordic nRF SoCs, a similar mechanism can be used for other SoCs and MCUs. In a future blog post, we will see how to commit these changes to our fork of the MCUboot repository. We will also see an example implementation of an application that triggers an in-field firmware update procedure, and demonstrate the complete process using MCUmgr.
More blogs by Mohammed Bill0o:
- nrf BLE Issues on Zephyr RTOS
-
Getting Started With Zephyr RTOS, the nRF Feather, and VS Code: Part 1
If you have any questions or comments, please reach out to the Zephyr community on the Zephyr Discord Channel.