Zephyr使用DFU

Creative Commons
本作品采用知识共享署名

本文说明zephyr如何进行dfu升级

zephyr以下面的形式完成dfu:
bootloader: mcuboot
image下载: mcumgr
image管理和烧写: zephyr dfu支援mcuboot image格式

原理简介

mcuboot分区

mcuboot有4个分区
boot_partition: 装载mcuboot
slot0_partition:装载由mcuboot引导运行的image
slot1_partition: 用于下载升级的image
scratch_partition: 用于交换slot0和slot1

正常引导运行

CPU上电后从boot_partition开始运行mcuboot,mcuboot对slot0进行检查,如果存在image且检查通过,则跳到slot0上执行zephyr image

下载image

slot0 image下载image

在slot0内的zephyr image内包含了mcumgr功能,通过mcumgr可以把升级image下载到slot1

mcuboot升级

编译是通过配置可以让mcuboot支援GPIO检查进入recovery模式,然后通过mcumgr下载升级image到slot1,目前zephyr上只配置了nrf52840_pca10059支援这种模式,我向mcuboot提交了一个pr支援zephyr所有board通过uart检查进入recovery mode,但一直没有被review,需要的小伙伴可以执行merge: https://github.com/JuulLabs-OSS/mcuboot/pull/456

image升级

下载了新的image到slot1后,做交换slot的flag设置,再次重启时mcuboot会先检查flag,发现需要交换slot,就将slot0和slot1的内容交换,已scratch_partition做为数据交换区,如果交换过程中出错,会将slot0和slot1做恢复。交换成功后mcuboot对slot0进行检查,检查通过调到slot0上开始执行新的image。

使用

Bootloader

按照Zephyr使用mcuboot编译烧写mcuboot

image准备

按照Zephyr使用mcuboot编译烧写一个image,并编译签名好另一个准备用于DFU的image,后面简称DFU-image。
image的配置文件需要有下面几个选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#image按MCUBOOT link
CONFIG_BOOTLOADER_MCUBOOT=y

#启用mcumgr
CONFIG_MCUMGR=y

#启动mcumgr image管理
CONFIG_MCUMGR_CMD_IMG_MGMT=y

#启动mcumgr的uart smp传输协议
CONFIG_MCUMGR_SMP_UART=y

#启动mcumgr的bt smp传输协议
CONFIG_MCUMGR_SMP_BT=y

#配置bt
CONFIG_BT_L2CAP_TX_MTU=260
CONFIG_BT_RX_BUF_LEN=260
CONFIG_BT_GATT_READ_MULTIPLE=n
CONFIG_NET_BUF_USER_DATA_SIZE=8

Host工具安装

在ubuntu 18.04下执行下面命令进行安装mcumgr命令行工具用于升级

1
go get github.com/apache/mynewt-mcumgr-cli/mcumgr

升级

准备好的DFU-image可通过蓝牙也可以通过串口进行下载

通过蓝牙下载

1
sudo /home/frank/go/bin/mcumgr -conntype ble --connstring ctlr_name=hci0,peer_name='Zephyr' image upload ~/work/project/nrf52_moderate/apps/moderate_mcuboot/build/zephyr.signed.bin

通过串口下载

1
mcumgr --conntype serial --connstring=/dev/ttyUSB0,baud=115200 image upload ~/work/project/nrf52_moderate/apps/moderate_mcuboot/build/zephyr.signed.bin

注意下载前需要确保没有其它串口工具占用/dev/ttyUSB0

下载速度

目前发现无论是串口还是蓝牙,下载速度均只有4KB/s

切换image

下载完后可以用下面命令查看image的情况

1
mcumgr --conntype serial --connstring=/dev/ttyUSB0,baud=115200 image list

如下

1
2
3
4
5
6
7
8
9
10
11
12
Images:
slot=0
version: 1.0.0
bootable: true
flags: active confirmed
hash: 0ca78338236de874e6606ba471b5b0865927fdc799073f1fbac2541b8ded3d4a
slot=1
version: 1.0.0
bootable: true
flags:
hash: 7decd49223b668ddabd20ad66dfd1fef4a03a003cac460c24f91e03cea2d1847
Split status: N/A (0)

用下面命令测试新的image

1
mcumgr --conntype serial --connstring=/dev/ttyUSB0,baud=115200 image test 7decd49223b668ddabd20ad66dfd1fef4a03a003cac460c24f91e03cea2d1847

可以看到slot的 flags变为pending

1
2
3
4
5
6
7
8
9
10
11
12
Images:
slot=0
version: 1.0.0
bootable: true
flags: active confirmed
hash: 0ca78338236de874e6606ba471b5b0865927fdc799073f1fbac2541b8ded3d4a
slot=1
version: 1.0.0
bootable: true
flags: pending
hash: 7decd49223b668ddabd20ad66dfd1fef4a03a003cac460c24f91e03cea2d1847
Split status: N/A (0)

重启后mcuboot将交换slot0和slot1执行,通过image list观察image可以看到slot0和1已经发生交换

1
2
3
4
5
6
7
8
9
10
11
Images:
slot=0
version: 1.0.0
bootable: true
flags: active
hash: 7decd49223b668ddabd20ad66dfd1fef4a03a003cac460c24f91e03cea2d1847
slot=1
version: 1.0.0
bootable: true
flags: confirmed
hash: 0ca78338236de874e6606ba471b5b0865927fdc799073f1fbac2541b8ded3d4a

此时如果重启又会恢复原来的slot.如果确认需要升级,用下面的命令确认交换,完成升级

1
mcumgr --conntype serial --connstring=/dev/ttyUSB0,baud=115200 image confirm

可以看到

1
2
3
4
5
6
7
8
9
10
11
12
Images:
slot=0
version: 1.0.0
bootable: true
flags: active confirmed
hash: 7decd49223b668ddabd20ad66dfd1fef4a03a003cac460c24f91e03cea2d1847
slot=1
version: 1.0.0
bootable: true
flags:
hash: 0ca78338236de874e6606ba471b5b0865927fdc799073f1fbac2541b8ded3d4a
Split status: N/A (0)

参考

https://docs.zephyrproject.org/latest/guides/device_mgmt/dfu.html
https://mcuboot.com/mcuboot/readme-zephyr.html
https://mcuboot.com/mcuboot/design.html