Nearly every embedded system needs the ability to have its firmware updated in the field to add new features or fix bugs. However, firmware field updates can be challenging as a developer must either program their own bootloader or procure a bootloader from a third-party component supplier.
There is an easier route. This article will show how to use the device firmware updates (DFU) feature that is built into many microcontrollers, but yet is often overlooked.
Firmware update options
Developing a bootloader from scratch is not a trivial endeavor. Developers need to parse out their flash space so that multiple applications can co-exist. They then need to develop some way to transfer their compiled binary onto the microcontroller without the use of a programming tool. This requires them to either develop their communication protocol or increase their system complexity by adding external memory to store new images. They can also increase the amount of internal memory they have on their microcontroller.
Also, the software itself can become complex, since the bootloader will need to set the system state and determine whether it is safe to jump to the application code or not.
Using a custom bootloader can provide developers with much needed flexibility for their applications, but there is a firmware update standard that can work in many applications that require no work from a developer: the USB standard’s built-in device firmware update (DFU) class. This can be used to update a microcontroller’s application code in the field through its USB port, which can dramatically decrease the firmware update process and development cycle.
DFU has become so pervasive that some microcontroller vendors such as STMicroelectronics even include the software necessary to perform the updates hardcoded into their ROM. Those that don’t, often provide example code on how to support DFU.
Selecting a DFU-capable microcontroller
The easiest way to support DFU is to select a microcontroller that already has DFU included in its ROM, such as STMicroelectronics’ STM32 microcontrollers. Of these, the devices that would be the most interesting for a developer to experiment with are the ones on the STM32 IoT Discovery Node and the STM32F429 Discovery Kit.
Figure 1: The STMicroelectronics STM32 IoT Discovery Node is based on an ARM® Cortex®-M4 core running a STM32L475 MCU that includes DFU mode capabilities for firmware updates. This particular device is designed for use as an IoT node. (Image source: STMicroelectronics)
The STM32 IoT Discovery Node is a low-cost development board designed for use as an IoT sensor node. The board includes several different interfaces for connecting the board such as Wi-Fi and Bluetooth. What’s interesting is that the onboard STM32L475 provides developers with the ability to test and use DFU capabilities on a device designed to connect to the internet.
For developers who just want to test DFU on a normal device that would be stand-alone, the STM32F429 Discovery Kit is a well-known, low-cost development kit for the STM32F4 series of microcontrollers. Let’s discuss how a developer would go about testing DFU on these microcontrollers.
Figure 2: The STMicroelectronics STM32F429 Discovery Kit is based on an ARM® Cortex®-M4 core. This low-cost development board’s MCU also includes DFU-mode capabilities for firmware updates. (Image source: STMicroelectronics)
A simple DFU example
DFU is accessed differently on each microcontroller. As a simple example, look at how a developer would update their firmware on a device that is running an STM32L475 MCU.
As mentioned earlier, the STM32 microcontrollers include a DFU bootloader built into their ROM. To access that bootloader, a developer needs to pull one of the BOOT pins to ground while the MCU is starting up. The BOOT pins control the mode that the MCU boots up in, such as booting from flash, RAM, or in our preferred case, the DFU USB mode.
Preparing an application to be downloaded using DFU does not require any additional work from the developer. GNU compiler collection (GCC), along with many other toolchains, support generating a DFU file when an application is compiled. The only trick here for the developer is to determine where that file is stored: just like with any typical application, the debug or objects folder is where the .dfu file can be found.
The DFU file is very similar to other application record formats such as binary, s-record and hex files. The file format contains address and data information that is relayed over USB, processed and then written to the location specified within flash. The process is so seamless that a developer rarely, if ever, needs to even examine the protocol that is being used. This is all abstracted behind the scenes, which helps make the firmware update process and the development effort less complex.
There are several different tools that a developer can use to transfer their application to their microcontroller using DFU. A general command line tool that can be used is dfu-util. It is available on both Linux and Windows® as an open-source software package. If a developer is working with the STM toolchain, they can take advantage of the STMicroelectronics application DfuSe (Figure 3).
Figure 3: The STMicroelectronics DfuSe tool can be used to program a DFU file that is generated by a compiler such as GCC and loaded onto a DFU capable microcontroller. (Image source: Beningo Embedded Group)
DfuSe is a Windows GUI utility that will detect any STM32 device that has been powered up in DFU mode and connected via USB to the computer. Developers can retrieve information such as the programmed vendor and product IDs. If the flash space has not been properly secured, they can even copy the MCU’s memory contents and store them on the computer using the Upload Action box.
When using DfuSe, a developer will typically only use the Upgrade or Verify Action sections. In this area, a developer can select their DFU application file and then select the upgrade button. DfuSe will then automatically coordinate the firmware update process until the entire file has been successfully loaded onto the MCU. A developer can then choose to verify that the image was received successfully. Once verified, the BOOT pins can be set back to their default configuration, such as boot to flash, and then the ‘Leave DFU’ mode is selected to load and execute the updated firmware.
Using DFU on devices without DFU support
Just because a microcontroller doesn’t include a DFU bootloader within ROM doesn’t mean that a developer can’t still utilize DFU capabilities. DFU is a USB class and is supported in many USB stacks. This means that a developer can just as easily add DFU capability to their application frameworks and still perform a DFU update.
For example, Microchip Technology's AT32UC3A3, does not have a built-in DFU mode (Figure 4). A developer can follow a simple application note which describes how DFU works, and how a developer should configure their microcontroller to support DFU properly.
Figure 4: The AT32UC3A3 UC3-A3 XPLD AVR®32 MCU 32-Bit AVR Embedded Evaluation Board does not include DFU on-chip but can have framework USB code added that enables the DFU firmware update feature. (Image source: Microchip Technology)
Tips and tricks for performing firmware updates
Updating firmware in the field doesn’t necessarily have to come only from a DFU capable microcontroller. A developer may decide that an alternative approach to updating the firmware is necessary or more practical. In these circumstances, there are several tips that a developer should keep in mind concerning their firmware update process. These include:
- Use a checksum or hash to verify the application that will be written to microcontroller memory.
- Select a microcontroller with enough memory to store a backup copy of the firmware so that if something goes wrong, the firmware version can be rolled back.
- Verify that if the microcontroller has a built-in flashloader, that the end user cannot accidentally trigger it.
- Make sure that any software bootloaders have been compiled and optimized for size.
- Lock the flash peripheral so that the application cannot be read out of memory and reverse engineered.
- Always make sure that the stack pointer, vector table and program counter registers are set to the appropriate application value.
- Consider using alternative update methods such as drag-n-drop updates using USB MSD as demonstrated on the KL46Z Freedom Board (Figure 5).
Figure 5: NXP Semiconductor’s KL46Z Freedom Board is a low-cost development board that by default does not support DFU. Developers can use alternative update methods such as USB MSD where a new firmware image is dragged and dropped into internal memory. (Image source: NXP Semiconductor)
Nearly every embedded system requires a method to update application code in the field to avoid recalls. Creating a bootloader from scratch or modifying an existing one can introduce complexity and integration issues into a development cycle.Instead, developers can make use of the well-proven DFU capability that is built into the USB standard to very quickly and efficiently perform field upgrades with little to no effort. In order for this to go smoothly, developers need to carefully review their microcontrollers and determine whether DFU is built-in to their microcontroller or whether they need to include a software stack that enables DFU capabilities.