2021-04-23

本文重点在环境搭建开始,前面只是一些介绍,介绍了有关环境搭建需要注意的事项和升级过程中遇到的问题以及解决方法。串口升级和空中升级都有。

1.概述

所谓DFU(Device Firmware Update),就是设备固件升级的意思,而OTA(Over The Air)是实现DFU的一种方式而已,准确说,OTA的全称应该是OTA DFU,即通过空中无线方式实现设备固件升级。只不过大家为了方便起见,直接用OTA来指代固件空中升级(有时候大家也将OTA称为FOTA,即Firmware OTA,这种称呼意思更明了一些)。只要是通过无线通信方式实现DFU的,都可以叫OTA,比如2G/3G/4G/WiFi/蓝牙/NFC/Zigbee,他们都支持OTA。DFU除了可以通过无线方式(OTA)进行升级,也可以通过有线方式进行升级,比如通过UART,USB或者SPI通信接口来升级设备固件。

不管采用OTA方式还是有线通信方式,DFU包括后台式(background)和非后台式两种模式。后台式DFU,又称静默式DFU(Silent DFU),在升级的时候,新固件在后台悄悄下载,即新固件下载属于应用程序功能的一部分,在新固件下载过程中,应用可以正常使用,也就是说整个下载过程对用户来说是无感的,下载完成后,系统再跳到BootLoader模式,由BootLoader完成新固件覆盖老固件的操作,至此整个升级过程结束。比如智能手机升级Android或者iOS系统都是采用后台式DFU方式,新系统下载过程中,手机可以正常使用哦。非后台式DFU,在升级的时候,系统需要先从应用模式跳入到BootLoader模式,由BootLoader进行新固件下载工作,下载完成后BootLoader继续完成新固件覆盖老固件的操作,至此升级结束。早先的功能机就是采用非后台式 DFU来升级操作系统的,即用户需要先长按某些按键进入bootloader模式,然后再进行升级,整个升级过程中手机正常功能都无法使用。

下面再讲双区DFU(dual bank)和单区DFU(single bank),双区或者单区DFU是新固件和老固件覆盖的两种方式。后台式DFU必须采用双区模式进行升级,即老系统(老固件)和新系统(新固件)各占一块bank(存储区),假设老固件放在bank0中,新固件放在bank1中,升级的时候,应用程序先把新固件下载到bank1中,只有当新固件下载完成并校验成功后,系统才会跳入BootLoader模式,然后擦除老固件所在的bank0区,并把新固件拷贝到bank0中。非后台式DFU可以采用双区也可以采用单区模式,与后台式DFU相似,双区模式下新老固件各占一块bank(老固件为bank0,新固件为bank1),升级时,系统先跳入BootLoader模式,然后BootLoader程序把新固件下载到bank1中,只有新固件下载完成并校验成功后,才会去擦除老固件所在的bank0区,并把新固件拷贝到bank0区。单区模式的非后台式DFU只有一个bank0,老固件和新固件分享这一个bank0,升级的时候,进入bootloader模式后立马擦除老固件,然后直接把新固件下载到同一个bank中,下载完成后校验新固件的有效性,新固件有效升级完成,否则要求重来。跟非后台式DFU双区模式相比,单区模式节省了一个bank的Flash空间,在系统资源比较紧张的时候,单区模式是一个不错的选择。不管是双区模式还是单区模式,升级过程出现问题后,都可以进行二次升级,都不会出现“变砖”情况。不过双区模式有一个好处,如果升级过程中出现问题或者新固件有问题,它还可以选择之前的老固件老系统继续执行而不受其影响。而单区模式碰到这种情况就只能一直待在bootloader中,然后等待二次或者多次升级尝试,此时设备的正常功能已无法使用,从用户使用这个角度来说,你的确可以说此时设备已经“变砖”了。所以说,虽然双区模式牺牲了很多存储空间,但是换来了更好的升级体验。

可参考下面三个图来理解上述过程。

2. Nordic nRF5 SDK DFU工作原理

  1. 如文章“nRF5 SDK软件架构及softdevice工作原理”所述,Nordic nRF5 SDK软件架构跟其他家有点不一样,程序存储区最开始部分放得不是Bootloader,而是蓝牙协议栈Softdevice,应用程序则紧挨着Softdevice,Bootloader则被nRF5 SDK放在程序存储区的最上面,整个存储区结构图如下所示。如果用户还有Flash数据需要存放,那么这些数据紧挨着BootLoader下面

  2.  目前Nordic SDK默认只提供非后台式DFU开箱即用的例子(SDK16.0开始也支持后台式DFU框架),即系统必须先跳到BootLoader中,然后才能通过BLE/UART/USB去接收新的固件。如上所示,如果采用双区模式DFU,那么Bank0放的是应用程序,即老固件,Bank1放的是新固件。平时,Bank1为空或者忽略,系统只跑Bank0里面的应用程序;升级的时候,先跳到BootLoader,然后接收新固件并把它放在Bank1中,最后把Bank1里面的固件拷贝到Bank0中。如果采用单区模式,则没有Bank1这个区。平时,系统只跑Bank0里面的代码;升级的时候,跳到BootLoader,先擦除Bank0里面的老程序,并把新固件直接放在Bank0中。
  3. 根据升级时如何跳转到Bootloader,Nordic SDK又将DFU分为按键式DFU和非按键式(Buttonless)DFU,所谓按键式DFU,就是上电时长按某个按键以进入bootloader模式,而非按键式DFU,就是整个DFU过程中设备端无任何人工干预,通过BLE/UART/USB接口给应用程序发送一条指令,应用程序收到指令后再自动跳入bootloader模式。不管是按键式DFU还是非按键式DFU,两者只是进入BootLoader的方式不一样,其余基本一样,尤其是BootLoader工作过程基本上是一模一样的。后面只会阐述非按键式DFU的过程,按键式DFU以此类似,就不再赘述。
  4. 程序跳到BootLoader后,根据BootLoader需不需要对新固件进行验签,Nordic SDK又把DFU分为开放式DFU和安全式DFU(又称签名DFU)。开放式DFU,BootLoader不做任何验证,直接把新固件接收下来。安全式DFU,BootLoader存有一把公钥,BootLoader会先用这把公钥验证新固件的签名,只有验签通过,才允许后续的工作:比如把新固件接收下来;如果验签失败,BootLoader将拒绝升级,重新跳回应用程序。
  5. BootLoader可以通过不同的通信接口来接收新的固件,目前Nordic SDK支持BLE,UART和USB三种接口,所以大家可以在Nordic SDK中看到如下三种工程目录:
  6.  其中pca0056表示nRF52840对应的开发板编号,S140对应Softdevice的型号,然后ble有两个目录:无debug和有debug,uart和usb也包含同样的两个目录。有debug和无debug两者功能是一样的,两者的区别是:debug版本BootLoader支持日志打印(大家可以通过打印出的日志去理解BootLoader的工作过程),并可以忽略各种校验,debug版本占据的代码空间要大很多;无debug版本 BootLoader不支持日志打印功能并且版本和有效性校验是强制的。正式量产的时候推荐使用无debug版本以节省代码空间。这里要强调一下,不管是debug版本还是无debug版本,两者都可以用Keil进行单步和断点调试
  7. BLE,UART和USB只是通信方式不一样,他们遵守的DFU流程是一模一样的,这里会以BLE通信接口为例,详细阐述DFU过程,UART和USB与之类似,就不再赘述。
  8. 讲述DFU升级之前,先讲一下nRF52的启动流程,上电后,系统先执行softdevice,softdevice通过读取UICR一个寄存器的值,来判断目前系统是否有BootLoader,如果没有BootLoader,系统直接跳到application;如果有BootLoader,系统先跳到BootLoader,BootLoader再根据目前的情况来决定是进入升级模式还是跳往application,BootLoader主要判断如下几种情况:

按键是否按下

保持寄存器GPREGRET1是否为0xB1

上次DFU过程是否还在进行中

应用程序校验是否通过

如果按键没有按下,GPREGRET1不为0xB1,本次复位不是上次DFU的继续,并且应用程序校验通过,那么BootLoader就会直接跳到application,去执行application应用程序。那怎么去校验应用程序的有效性呢?为此BootLoader引入了一个放在Flash的结构体参数:m_dfu_settings_buffer(数据类型:nrf_dfu_settings_t),这个结构体参数虽然只有896字节,但由于Flash只能按页擦除,所以这个参数实际占用了一个Flash page,这个page称为settings page,settings page放在Flash的最后一个页面,settings page目前有2个版本:版本1(SDK15.2及以前版本)和版本2(SDK15.3及以后版本),版本2可以兼容版本1,前面所述的896字节是指settings page版本2的大小。Settings page包含的信息比较多,大家用得比较多的是:

  • 各种版本信息
  • DFU升级过程信息
  • Application image的CRC值和大小
  • 应用程序的bonding信息
  • Init command内容
  • application/softdevice的启动校验信息(版本2才有)

版本1的settings page只校验application image的CRC值,如果CRC匹配,则认为application有效。版本2的settings page不仅可以校验application image的CRC值,还可以校验application/softdevice的CRC值或者hash值或者签名,你可以选择你自己想要的校验方式,只有CRC值或者hash值或者签名校验通过(三选其一),应用程序才算有效,这时BootLoader才会跳到application去执行。为了保证settings page在发生意外时,比如写settings page过程中发生了复位或者掉电,系统也能正确恢复,SDK15及以后版本引入了一个backup page,backup page也占用一个Flash page,内容和settings page一模一样。

上面是没有触发升级的情况下nRF52的正常启动流程,那如果要执行DFU升级,流程又是怎么样的呢?下面详细讲一下无按键式BLE OTA的工作流程。

  • 1)      正常启动后,系统运行在应用程序中,此时手机通过app发送一条开始DFU的指令给设备,设备收到指令后,将GPREGRET1赋值0xB1,并触发软复位
  • 2)      复位后,系统再次进入BootLoader,因为GPREGRET1等于0xB1,BootLoader进入DFU模式,等待新固件接收
  • 3)      手机先将init packet发送给设备,设备先做前期检验prevalidation,主要是各种版本校验以及签名验签,校验通过后,更新settings  page并准备开始数据接收
  • 4)      接收新固件。每接收4kB数据,回复一次CRC校验值,直至整个新固件image接收完毕,如果新固件校验通过(版本1校验CRC值,版本2校验hash值),就会去invalidate(无效化) bank0里面的老固件,更新settings page,并再次触发软复位
  • 5)      BootLoader启动后发现有新固件需要activate(激活),此时会去擦掉bank0里面的固件,并把bank1里面的固件拷贝到bank0,然后更新settings page,并再次触发软复位。注:上面讲的是dual bank的流程,single bank与之相似,只不过在第3)步的时候就会去擦除老固件
  • 6)      BootLoader再次启动后,检查新image的有效性,校验通过后,跳到新的application去执行代码

从上面流程可以看出,DFU过程中,系统需要跑两段完全独立的代码:Application和BootLoader,Application和BootLoader都支持蓝牙功能,也就是说,两者都有自己的蓝牙广播和蓝牙连接。这里面有一个问题:当系统从Application跳到BootLoader后,手机怎么辨别两者为同一个设备?很多人会说,可以让BootLoader和Application两者的广播名字一样,根据广播名字的一致性,来判断二者来自同一个设备。这种方法存在两个问题:一大部分手机都支持GATT cache(缓存)功能,当application跟手机相连后,手机会把application的GATT数据缓存下来以加快下次连接的速度(这个现象在苹果手机最明显),之后如果系统跳到BootLoader,然后再跟手机相连,如果两者的蓝牙设备地址一样,手机会认为是同一个设备,从而跳过服务发现的过程而直接使用之前缓存下来的GATT数据,这样会导致BootLoader的服务无法被手机发现,从而出现升级失败。二如果多个设备同时在升级,而我们仅仅依靠广播名字来决定两者属不属于同一个设备,这会导致设备A application有可能跟设备B的BootLoader进行错配。为了解决这个问题,Nordic提出了两套方案。方案一,假设application的蓝牙设备地址为x,跳到BootLoader后蓝牙设备地址会变成x+1,这样手机就可以通过这种地址+1的方式来辨别两者属不属于同一个设备,由于application和BootLoader使用不同的蓝牙设备地址,前面的GATT缓存问题也就不存在。关于方案一,有一个问题需要特别注意:如果你想修改例子默认的蓝牙设备地址(比如使用IEEE的public蓝牙MAC地址),此时一定要记得同时更改application和BootLoader的蓝牙设备地址,使他们满足+1的条件,否则Nordic手机DFU库无法辨别两者是否属于同一个设备,以致于无法完成OTA过程。方案二,application和BootLoader的蓝牙设备地址一模一样,但设备跟手机执行配对和bonding操作,设备跟手机bonding后,就可以支持service changed indicate操作,这样跳到BootLoader后可以让手机主动再执行一次服务发现过程,从而解决GATT缓存问题。

很多人对签名验签不是很理解,这里详细说一下它的工作原理。首先,你需要一对公私钥,其中私钥用来生成新固件的签名,公钥用来验证签名的有效性,大家可以用nrfutil来生成自己需要的公私钥对,公私钥制作成功后,私钥一定要妥善保管(一般放在云端),千万不能丢,否则你自己也无法升级自己的设备;也不能被第三方知道,否则升级的安全性就不能保证了。公钥可以变成一个.c文件,并覆盖DFU工程下的同名文件:dfu_public_key.c 。其次,BootLoader要支持签名验签密码算法,这个DFU代码已经有了,并且有四种后端可选:micro-ecc,cc310_bl,Oberon和mbedtls,四选其一即可(这4种后端,只有cc310是硬件实现,其余都是软件实现),nRF52840推荐选择cc310作为算法后端,其他nRF52芯片推荐选择micro-ecc作为算法后端。micro-ecc效率高,占用的代码空间最小,但它的版权是CPOL,只要你能接受CPOL,那么推荐使用micro-ecc;反之,如果接受不了CPOL版权,而且硬件又不支持cc310,那么推荐使用Oberon,不过Oberon占用的代码空间比micro-ecc要大一些,这个大家注意一下。再次,手机端要生成新固件的签名,并把新固件的签名传给设备端。大家还是可以用nrfutil去生成新固件的签名。最后,BootLoader接收到新固件hash值和签名,并使用自己的公钥对该签名进行验签。这里说一下,由于nrfutil是PC端应用程序,所以它可以集成各种加密算法库,并完成上面提及的公私钥对,hash和签名的生成工作。

3. DFU升级步骤详解

3.1 安全式蓝牙空中升级步骤

  1. Nordic SDK已经提供了DFU例子,下面我们一步一步给大家讲解如何通过Nordic SDK来实现无按键式蓝牙空中升级。欲实现空中升级,设备需要同时下载softdevice,应用程序,BootLoader程序,以及BootLoader settings page。其中BootLoader代码位于目录:SDK根目录\examples\dfu\secure_bootloader,然后在该目录下选择你对应的板子和工程。Application对应的目录:SDK根目录\examples\ble_peripheral\ble_app_buttonless_dfu,而softdevice所在目录:SDK根目录\components\softdevice。
  2. 下面我们以nRF52832/PCA10040和S132/SDK16为例阐述无按键式蓝牙空中升级实现步骤,其他芯片/softdevice/SDK原理与之类似,这里就不再赘述。
  3. 环境的搭建需要的软件列表:
  • nRF5x_Command_Line_Tools软件
  1. Gcc-arm-none软件
  2. Mingw平台
  3. Python软件(版本需要在2.6-3.9.0之间)
  4. Pc-nrfutil软件
  5. micro-ecc-master库的下载
  6. 以上软件的下载地址可以自行搜索或者参考以下播客:

4. 环境搭建开始:

  1. 安装nRF5x_Command_Line_Tools环境。安装过程略
  2. 安装Gcc-arm-none软件,使用默认安装路径,并且需要记录一下安装位置,后面环境搭建会使用到。
  3. 安装Mingw,安装过程略,可以下载别人安装好的,只要位置放到能找到的地方就可以。然后需要添加环境变量。

添加环境变量的步骤如下: 

1). 右键选择点击“此电脑”,选择属性;

 

2). 点击“高级系统设置”

3). 选择菜单栏的“高级”,然后点击“环境变量”。

4). 找到“path”,选择,然后点击“编辑”

5).点击“新建”,按照相同输入绝对地址,点击保存就可以了。

 

6).测试是否环境变量设置成功,点击“开始”,输入cmd,回车,在弹窗中输入gcc -v 回车,v小写,如果设置成功就会出现gcc的版本号。

 

4.安装python,默认位置即可,需要记录一下安装的位置,需要添加环境变量,需要注意,python的版本不能高于3.9.0,否则无法在pc-nrfutil中使用时,会失败。可以在cmd打开的窗口中输入:python -V回车,V大写。

 

5. 安装pc-nrfuti,一般下载的都是压缩包,解压进入文件夹,shift+右键,进入dos窗口。

 

 

6. 在窗口中输入python setup.py install 回车。需要在有网络的情况下是使用,需要等待几分钟。

7. 由于之前安装了nRF5x_Command_Line_Tools所以需要添加nrfutill.exe的环境变量。(位置在python文件夹下)可以直接搜nrfutill。保证位置正确就行。

  可以在dos窗口,输入nrfutil version,如果正确则会显示版本信息。

 

8. nrfutil运行需要几个特殊的DLL库,而这几个库有些Windows机器是没有的,如此,可往:https://www.microsoft.com/en-us/download/details.aspx?id=40784下载

9.私钥和公钥的生成和一些库的生成:

1) 通过nrfutil生成公私钥对。新建一个key文件夹,在key文件夹内打开dos窗口,进行如下操作。

私钥生成命令:nrfutil keys generate private.keyprivate.key就是私钥)

公钥生成命令:nrfutil keys display --key pk --format code private.key --out_file dfu_public_key.c (dfu_public_key.c就是公钥)

2)大家务必要保存好私钥private.key,以后每次升级新固件时,都会通过这个私钥对它进行签名,一旦priv.pem丢失或者被暴露,DFU将无法进行或者变得不安全

 需要把公钥替换掉bootloader工程内的examples\dfu\dfu_public_key.c 。

3)把下载的micro-ecc-master压缩包解压到external\micro-ecc,改名为micro-ecc,然后在external\micro-ecc\nrf52nf_keil\armgcc文件下,打开dos窗口,直接输入make ,就会生成对应的lib库,替换掉对应的bootloader工程里面的micro_ecc_lib_nrf52.lib文件。

 

10.各种hex文件的生成:

1)booloader工程(examples\dfu\secure_bootloader\pca10040_s132_ble\arm5_no_packs)编译生成nrf52832_xxaa_s132.hex文件,复制到到key文件夹内,改名为boot.hex。

2)应用工程(examples\ble_peripheral\ble_app_buttonless_dfu\pca10040\s132\arm5_no_pack)编译生成的nrf52832_xxaa.hex文件,复制到key文件内,改名为app,zip。

3)softdevice的,hex文件在components\softdevice\s132\hex\s132_nrf52_7.0.1_softdevice.hex,复制到key文件内,改名为s132.hex。(根据自己工程的不同,这个版本也不通)

4)Setting.hex文件的生成,在key文件夹内打开dos窗口,输入以下指令:

nrfutil settings generate --family NRF52 --application app.hex --application-version 1 --bootloader-version 1 --b1-settings-version 1 setting.hex

可以自行根据要求修改版本号。

5)合并前面的四个.hex文件。

mergehex --merge app.hex boot.hex s132.hex --output out3to1.hex

mergehex --merge out3to1.hex setting.hex --output application.hex

6)生成升级的压缩包app.zip

nrfutil pkg generate --applicatio app.hex --application-version 1 --hw-version 52 --sd-req 0xCB --key-file private.key app.zip

这个--sd-req 0xCB 中的0xCB是对应的softdevice的版本号,如果不知道可以在dos窗口输入

nrfutil pkg generate --help 会出现一些版本号,如果没有找到,也可以使用studio软件,打开prongmmer

界面,红色框就是对应的版本号。

11.烧录和升级:

1)直接在studio 软件内的program Application 中找到合并生成的 application.hex 文件,烧录既可使用。

2)控制进入DFU模式后,把app.zip压缩包下载到手机上,使用nrf connect app连接DFUTarg,的设备,然后点击头上的“DFU”,选择压缩包就可以进行传输。


12.烧录过程中会出现的问题和解决方法:

1)连接传输未开始就断开连接,查看手机app日志出现:

REMOTE DFU INVALID OBJECT 就表示,你压缩包用的签名私钥和bootloader的公钥对应的私钥不是同一个。

如果是传输进行到一定程度,就断开了,出现如下错误:

2)REMOTE DFU INVALID PARAM 就表示,你bootloader 需要修改如下的数

   把最大值进行修改,改的大一点,具体可以自行测试。

3)如果为了防止升级的数据包过大,从而升级失败,可以修改下面的程序,把bank1的地址设置到bank0。

可以在这边修改,添加判断之类的。(仅供参考,需要实际测试)

 

 

 

4.串口升级

1.环境搭建和空中升级一样,如果是在空中升级之后,进行串口升级操作环境可以进行如下修改:

以记事本的格式打开pc-nrfutil-master\nordicsemi\dfu\dfu_transport_serial.py文件,

 

2.修改波特率和流控为自己bootloader内设置的一样。然后在dos窗口输入以下指令:

Python setup.py build

Python setup.py install

 

3. 使用examples\dfu\secure_bootloader\pca10040_uart\arm5_no_packs的bootloader工程 ,同样需要把dfu_public_key.c文件替换和lib库替换,如果已经替换可以不用,然后生成.hex文件前需要进行如下操作:

3.1修改串口端口号:

位置在这

修改串口的端口号,要保持对应。

 

3.2 修改流控为0:

或者

2.3修改波特率为9600(实测115200也可以):

或者

3.4 编译生成的nrf52832_xxaa_s132.hex,复制到key文件夹中,可以修改名字为boot.hex(需要把之前的空中升级文件放到另一个地方)。

3.5 应用程序可以自己找,都可以用,只要可以控制程序进入DFU模式就行。

 

4.生成其他hex文件、合并,烧录和空中升级一样,压缩包生成指令也一样。

串口升级的时候,板子进入DFU模式,保证串口和pc端连接,然后确定端口号是COM多少。在key文件夹内,进入dos窗口,输入以下指令:

nrfutil dfu serial -pkg app.zip -p COM1 -fc 0 -b 115200

实测115200和9600都可以,如果不开流控115200传输失败就修改为9600.

 

5.串口升级遇到的问题和解决方法:

本文参考播客:

https://www.cnblogs.com/iini/p/9314246.html

https://www.cnblogs.com/silencehuan/p/11011716.html

https://blog.csdn.net/YYGY731793898/article/details/108981974

如有疑问可以加群一起讨论:687360507

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值