# Updating device firmware using DFU in Zephyr Project on a FRDM-K64F board

**URL:** <https://hub.mender.io/t/updating-device-firmware-using-dfu-in-zephyr-project-on-a-frdm-k64f-board/1618>\
**Category:** Tutorials\
**Created:** [March 10, 2020, 8:01am UTC](https://hub.mender.io/t/updating-device-firmware-using-dfu-in-zephyr-project-on-a-frdm-k64f-board/1618 "2020-03-10T08:01:33Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![mirzak](https://yyz2.discourse-cdn.com/flex036/user_avatar/hub.mender.io/mirzak/32/2056_2.png) [@mirzak](https://hub.mender.io/u/mirzak)\
**Post date:** [March 10, 2020, 8:01am UTC](https://hub.mender.io/t/updating-device-firmware-using-dfu-in-zephyr-project-on-a-frdm-k64f-board/1618/1 "2020-03-10T08:01:33Z")

</div>

## Introduction

USB Device Firmware Upgrade (DFU) is an official USB device class specification of the USB Implementers Forum.

It specifies a vendor and device independent way of updating the firmware of a USB device. The idea is to have only one vendor-independent firmware update tool as part of the operating system, which can then (given a particular firmware image) be downloaded into the device.

In this tutorial we will cover how use the Device Firmware Update (DFU) USB class in [Zephyr Project](https://www.zephyrproject.org/) using a [FRDM-K64F](https://www.nxp.com/design/development-boards/freedom-development-boards/mcu-boards/freedom-development-platform-for-kinetis-k64-k63-and-k24-mcus:FRDM-K64F) board as target.

This tutorial is preparation work to use Mender to deploy an proxy deployment to a peripheral device, which will be the device that we prepare in this tutorial.

A lot of the steps outlined in this tutorial are already covered by the [Zephyr Project - Quick start](https://docs.zephyrproject.org/latest/getting_started/index.html) guide, the additions we make are steps to build MCUboot and the DFU application on the [FRDM-K64F](https://www.nxp.com/design/development-boards/freedom-development-boards/mcu-boards/freedom-development-platform-for-kinetis-k64-k63-and-k24-mcus:FRDM-K64F) and how to use `dfu-util` to flash an example application.

## Prerequisites for this tutorial

It is assumed that you are running a Debian based Linux distribution (native or in a VM) with the following packages installed:

```bash
sudo apt install --no-install-recommends git cmake ninja-build gperf \
  ccache dfu-util device-tree-compiler wget \
  python3-pip python3-setuptools python3-tk python3-wheel xz-utils file \
  make gcc gcc-multilib g++-multilib libsdl2-dev dfu-utils

```

Also since this tutorial is targeting the [FRDM-K64F](https://www.nxp.com/design/development-boards/freedom-development-boards/mcu-boards/freedom-development-platform-for-kinetis-k64-k63-and-k24-mcus:FRDM-K64F) board, it is a requirement to be able to test the provided instructions.

## Overview

The [Zephyr Project](https://www.zephyrproject.org/) already provides support for DFU together with [MCUboot](https://juullabs-oss.github.io/mcuboot/) as a first-stage bootloader.

> MCUboot is a secure bootloader for 32-bit MCUs. The goal of MCUboot is to define a common infrastructure for the bootloader, system flash layout on microcontroller systems, and to provide a secure bootloader that enables easy software upgrade.

Further they device flash layout in our setup can be described with the following simplified model:

 ![Zephyr Project - MCU boot](https://canada1.discourse-cdn.com/flex036/uploads/mender/original/1X/6acef303c6440eb66405ddb7af483fe7ca38c557.png)

Where,

- MCUboot acts as a first-stage bootloader
- The DFU application acts as a “recovery application”, which you can jump in to if you need to update the application (SLOT-1)
- The Scratch area is used by MCUboot to store information while an update is in progress.

MCUboot provides the key features needed to securely be able to update firmware of a device, while DFU acts as the interface to transfer and flash an image. Some of the key features of MCUboot are:

- Definition of an image format
- Support for integrity checking of firmware
- Support for image signing and verification
- “Boot Swap” logic to switch between image slots in a secure way

## Step 0 - Preparations

The Zephyr Project uses the `west` meta tool to handle source code, but it can also be used to flash device with built firmware among other things.

Install `west`:

```bash
pip3 install west

```

## Step 1 - Getting the source code

Change directory to `$HOME`

```bash
cd $HOME

```

Initialize the Zephyr Project workspace:

```bash
west init zephyrproject && cd zephyrproject && west update

```

Install the python requirements of the Zephyr Project:

```bash
pip3 install -r ~/zephyrproject/zephyr/scripts/requirements.txt

```

## Step 2 - Install Software Development Toolchain

Zephyr’s Software Development Kit (SDK) contains necessary Linux development tools to build Zephyr on all supported architectures. Additionally, it includes host tools such as custom QEMU binaries and a host compiler.

Change directory to `$HOME`

```bash
cd $HOME

```

Download the latest SDK as a self-extracting installation binary:

```bash
cd ~
wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.11.2/zephyr-sdk-0.11.2-setup.run

```

Run the installation binary, installing the SDK in your home folder `$HOME/zephyr-sdk-0.11.2`:

```bash
chmod +x zephyr-sdk-0.11.2-setup.run
./zephyr-sdk-0.11.2-setup.run -- -d ~/zephyr-sdk-0.11.2

```

Set environment variables to let the build system know where to find the toolchain:

```bash
export ZEPHYR_TOOLCHAIN_VARIANT=zephyr
export ZEPHYR_SDK_INSTALL_DIR=$HOME/zephyr-sdk-0.11.2

```

The SDK contains a udev rules file that provides information needed to identify boards and grant hardware access permission to flash tools. Install these udev rules with these commands:

```bash
sudo cp ${ZEPHYR_SDK_INSTALL_DIR}/sysroots/x86_64-pokysdk-linux/usr/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d
sudo udevadm control --reload

```

## Step 3 - Build and flash MCUboot

Change directory to `$HOME/zephyrproject`

```bash
cd $HOME/zephyrproject

```

Build MCUboot targeting `frdm_k64f`:

```bash
west build -s $HOME/zephyrproject/bootloader/mcuboot/boot/zephyr -d build-mcuboot -b frdm_k64f

```

**NOTE!** MCUboot is compiled with verified boot enabled, which means that sub-sequent files that are flashed on the device must be signed. The default key provided by MCUboot is used, this is not a secure key as it is publicly available in the MCUboot git repository and is only intended to be used for evaluation.

For the next step, the `frdm_k64f` board needs to be connected to the PC trough the `OpenSDAv2 USB` interface (J26 connector on the `frdm_k64f` board).

Flash MCUboot on the `frdm_k64f` board:

```bash
west flash -d build-mcuboot

```

## Step 4 - Build and flash DFU application

The following changes are optional, but these make sure that the DFU application automatically reboots once it has written a firmware image and without these changes one would need to manually reset the device for it to boot the flashed image.

```diff
diff --git a/samples/subsys/usb/dfu/prj.conf b/samples/subsys/usb/dfu/prj.conf
index ffc1e9080b..f6f47e51b0 100644
--- a/samples/subsys/usb/dfu/prj.conf
+++ b/samples/subsys/usb/dfu/prj.conf
@@ -11,3 +11,4 @@ CONFIG_LOG=y
 CONFIG_USB_DRIVER_LOG_LEVEL_ERR=y
 CONFIG_USB_DEVICE_LOG_LEVEL_ERR=y
 CONFIG_BOOTLOADER_MCUBOOT=y
+CONFIG_REBOOT=y
diff --git a/subsys/usb/class/usb_dfu.c b/subsys/usb/class/usb_dfu.c
index a31bdf58ed..630d18cc59 100644
--- a/subsys/usb/class/usb_dfu.c
+++ b/subsys/usb/class/usb_dfu.c
@@ -52,6 +52,8 @@
 #include <usb/class/usb_dfu.h>
 #include <usb_descriptor.h>

+#include <power/reboot.h>
+
 #define LOG_LEVEL CONFIG_USB_DEVICE_LOG_LEVEL
 #include <logging/log.h>
 LOG_MODULE_REGISTER(usb_dfu);
@@ -356,6 +358,7 @@ static void dfu_flash_write(u8_t *data, size_t len)
                        dfu_data.state = dfuERROR;
                        dfu_data.status = errWRITE;
                }
+ sys_reboot(SYS_REBOOT_WARM);
        } else {
                dfu_data.state = dfuDNLOAD_IDLE;
        }

```

Build DFU application:

```bash
west build -b frdm_k64f -d build-dfu zephyr/samples/subsys/usb/dfu

```

Create a signed DFU application binary:

```bash
$HOME/zephyrproject/bootloader/mcuboot/scripts/imgtool.py sign \
    --key $HOME/zephyrproject/bootloader/mcuboot/root-rsa-2048.pem \
    --header-size 0x200 \
    --align 8 \
    --version 1.2 \
    --slot-size 0x60000 \
    build-dfu/zephyr/zephyr.bin \
    signed-dfu-app.bin

```

Flash the signed DFU application binary to `SLOT-1`:

```bash
pyocd flash -e sector -a 0x20000 -t k64f $HOME/zephyrproject/signed-dfu-app.bin

```

If you are connected to the `frdm_k64f` serial debug port you should see something similar to the following:

> ```bash
> ***Booting Zephyr OS build v2.2.0-rc3-69-g5f0650b596c5***
> [00:00:00.005,000] <inf> mcuboot: Starting bootloader
> [00:00:00.011,000] <inf> mcuboot: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
> [00:00:00.021,000] <inf> mcuboot: Scratch: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
> [00:00:00.030,000] <inf> mcuboot: Boot source: primary slot
> [00:00:00.038,000] <inf> mcuboot: Swap type: none
> [00:00:00.106,000] <inf> mcuboot: Bootloader chainload address offset: 0x20000
> ***Booting Zephyr OS build v2.2.0-rc3-69-g5f0650b596c5*** slot
> [00:00:00.007,000] <inf> main: This device supports USB DFU class.
> 
> ```

This means that our device is now ready for transfer of firmware images using the DFU USB device class.

## Step 5 - Build and download a sample application using DFU

We will be using the `blinky` sample application as a reference to flash to our device using DFU. Prior to building the sample application we need to make sure that it is aware of MCUboot.

```bash
echo "CONFIG_BOOTLOADER_MCUBOOT=y" >> zephyr/samples/basic/blinky/prj.conf

```

MCUboot does not support executing position independent code which means that application is always booted from `SLOT-1` and the application binaries must be linked in such a way that the start address is equal the start address of `SLOT-1`. Will try to explain this further with a simple run trough of the flow when an DFU update is performed in our setup:

1. DFU application is running and waiting for commands from a host application
2. Host application initiates an `download` operation, meaning that a firmware file is downloaded to the `SLOT-2`
3. MCUboot is instructed that there is an test image (not permanent) in `SLOT-2` by the DFU application
4. Device resets/reboots
5. MCUboot swaps the images between `SLOT-1` & `SLOT-2` meaning that DFU application ends up on `SLOT-2` and our application ends up in `SLOT-1`
6. MCUboot executes the code in `SLOT-1` (our application)
7. Device resets/reboots
8. MCUboot swaps the images between `SLOT-1` & `SLOT-2` again (revert), meaning that the DFU application ends up in `SLOT-1` again and is started. This swap is done because in our reference setup we never make the application update permanent.

Build the `blinky` sample application:

```bash
west build -b frdm_k64f -d build-blinky zephyr/samples/basic/blinky/

```

Create a signed `blinky` application binary:

```bash
$HOME/zephyrproject/bootloader/mcuboot/scripts/imgtool.py sign \
    --key $HOME/zephyrproject/bootloader/mcuboot/root-rsa-2048.pem \
    --header-size 0x200 \
    --align 8 \
    --version 1.2 \
    --slot-size 0x60000 \
    build-blinky/zephyr/zephyr.bin \
    signed-blinky-green.bin

```

Download the `signed-blinky-green.bin` file to the device using DFU:

```bash
dfu-util --alt 1 --download signed-blinky-green.bin

```

**NOTE!** You need to manually restart the `frdm_k64f` device to trigger the image swap in MCUboot.

If you are connected to the serial debug port you should see something like this:

> ```bash
> ***Booting Zephyr OS build v2.2.0-rc3-69-g5f0650b596c5***
> [00:00:00.005,000] <inf> mcuboot: Starting bootloader
> [00:00:00.011,000] <inf> mcuboot: Primary image: magic=good, swap_type=0x4, copy_done=0x1, image_ok=0x1
> [00:00:00.020,000] <inf> mcuboot: Scratch: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
> [00:00:00.030,000] <inf> mcuboot: Boot source: none
> [00:00:00.035,000] <inf> mcuboot: Swap type: test
> [00:00:01.535,000] <inf> mcuboot: Bootloader chainload address offset: 0x20000
> [00:00:01.543,000] <inf> mcuboot: Jumping to the first image slot0 ***Booting Zephyr OS build v2.2.0-rc3-69-g5f0650b596c5***
> 
> ```

**NOTE!** In this particular setup the updates are not permanent, which means that if you reset the device again it will enter the DFU application allowing you upload a different application binary.

## Conclusion

In this tutorial we have gone trough how to setup secure and robust firmware updates on a MCU which allows to download images using the `dfu-utils`. This essentially allows us to update firmware of the MCU using any Linux capable device, e.g from an embedded Linux device.

Further recommended reading:

- [MCUboot documentation](https://juullabs-oss.github.io/mcuboot/design.html)
- [Zephyr Project documentation on device firmware upgrades](https://docs.zephyrproject.org/latest/guides/device_mgmt/dfu.html)

* * *

_If this tutorial was useful to you, please press like, or leave a thank you note to the contributor who put valuable time into this and made it available to you. It will be much appreciated!_

---

<div class="post-metadata">

**Author:** ![Utsav\_Shah](https://avatars.discourse-cdn.com/v4/letter/u/3ab097/32.png) [@Utsav\_Shah](https://hub.mender.io/u/Utsav_Shah)\
**Post date:** [November 29, 2023, 7:30am UTC](https://hub.mender.io/t/updating-device-firmware-using-dfu-in-zephyr-project-on-a-frdm-k64f-board/1618/2 "2023-11-29T07:30:21Z")

</div>

I have a question on the step number 4 where you mention to add certain flags which enables the device to automatically reboot. Being relatively new to this, I am not able to figure out where exactly do I need to add the config flags.Can you help me out with this?

Also once a firmware update is flashed and is running on the peripheral device, and let’s say I have another firmware to flash (basically an update). How do I make my device automatically come back into DFU mode and flash the (updated) firmware instead of the currently running firmware? As the device currently is running a firmware, I was wondering how to automatically trigger it to boot again in DFU mode. Hopefully this issue makes sense.

For reference, I want to try this out on an NRF5340 based system.

Any help on both the queries would be super helpful.
