目录
CONTENT
1.概述2. NCS中的Bootloader 2.1 nRF5 SDK Bootloader 2.2 MCUboot 2.3 B0,亦称nRF Secure Immutable Bootloader(NSIB)3. DFU协议 3.1 概述 3.2 SMP DFU协议 3.2.1 SMP包头和命令 3.2.2 SMP包payload和CBOR编码 3.2.3 SMP包详细解析示例 3.2.4 SMP DFU流程 3.3 nrf dfu协议4. NCS DFU升级步骤说明 4.1 SMP DFU升级步骤说明 4.2 nrf_dfu升级步骤说明 4.3 存储器分区(多image情况)5. 移植SMP DFU功能到peripheral_uart(NUS)6. 手机端DFU参考代码 ●1、概述 ●DFU概念
DFU(Device Firmware Update),就是设备固件升级的意思。OTA概念
OTA(Over The Air)是实现DFU的一种方式而已,准确说,OTA的全称应该是OTA DFU,即通过空中无线方式实现设备固件升级。只不过大家为了方便起见,直接用OTA来指代固件空中升级(有时候大家也将OTA称为FOTA,即Firmware OTA,这种称呼意思更明了一些)。 只要是通过无线通信方式实现DFU的,都可以叫OTA,比如4G/WiFi/蓝牙/NFC/Zigbee/NB-IoT,他们都支持OTA。DFU除了可以通过无线方式(OTA)进行升级,也可以通过有线方式进行升级,比如通过UART,USB或者SPI通信接口来升级设备固件。 不管采用OTA方式还是有线通信方式,DFU包括后台式(background)和非后台式两种模式。 1、后台式DFU,又称静默式DFU(Silent DFU),在升级的时候,新固件在后台悄悄下载,即新固件下载属于应用程序功能的一部分,在新固件下载过程中,应用可以正常使用,也就是说整个下载过程对用户来说是无感的,下载完成后,系统再跳到BootLoader程序,由BootLoader完成新老固件拷贝操作,至此整个升级过程结束。比如智能手机升级Android或者iOS系统都是采用后台式DFU方式,新系统下载过程中,手机可以正常使用哦。 2、非后台式DFU,在升级的时候,系统需要先从应用程序跳到BootLoader程序,由BootLoader进行新固件下载工作,下载完成后BootLoader继续完成新老固件拷贝操作,至此升级结束。早先的功能机就是采用非后台式 DFU来升级操作系统的,即用户需要先长按某些按键进入bootloader模式,然后再进行升级,整个升级过程中手机正常功能都无法使用。 下面再讲双区(2 Slot)DFU和单区(1 Slot)DFU,双区或者单区DFU是新固件覆盖老固件的两种方式。 后台式DFU必须采用双区模式进行升级,即老系统(老固件)和新系统(新固件)各占一块Slot(存储区),假设老固件放在Slot0中,新固件放在Slot1中,升级的时候,应用程序先把新固件下载到Slot1中,只有当新固件下载完成并校验成功后,系统才会跳入BootLoader程序,然后擦除老固件所在的Slot0区,并把新固件拷贝到Slot0中,或者把Slot0和Slot1两者的image进行交换。 非后台式DFU可以采用双区也可以采用单区模式,与后台式DFU相似,双区模式下新老固件各占一块Slot(老固件为Slot0,新固件为Slot1),升级时,系统先跳入BootLoader程序,然后BootLoader程序把新固件下载到Slot1中,只有新固件下载完成并校验成功后,才会去擦除老固件所在的Slot0区,并把新固件拷贝到Slot0区。 单区模式的非后台式DFU只有一个Slot0,老固件和新固件分享这一个Slot0,升级的时候,进入bootloader程序DFU模式后立马擦除老固件,然后直接把新固件下载到同一个Slot中,下载完成后校验新固件的有效性,新固件有效升级完成,否则要求重来。 跟非后台式DFU双区模式相比,单区模式节省了一个Slot的Flash空间,在系统资源比较紧张的时候,单区模式是一个不错的选择。不管是双区模式还是单区模式,升级过程出现问题后,都可以进行二次升级,都不会出现“变砖”情况。 不过双区模式有一个好处,如果升级过程中出现问题或者新固件有问题,它还可以选择之前的老固件老系统继续执行而不受其影响。而单区模式碰到这种情况就只能一直待在bootloader中,然后等待二次或者多次升级尝试,此时设备的正常功能已无法使用,从用户使用这个角度来说,你的确可以说此时设备已经“变砖”了。 所以说,虽然双区模式牺牲了很多存储空间,但是换来了更好的升级体验。 可参考下面三个图来理解上述过程 如果你是第一次接触nRF Connect SDK(NCS),那么建议你先看一下这篇文章:开发你的第一个NCS/Zephyr应用程序,以建立NCS的一些基本知识,然后再往下看以下章节。 ●2、NCS中的 Bootloader ● 如果你的应用不需要DFU功能,那么Bootloader就可以不要;反之,如果你的应用需要DFU功能,Bootloader就一定需要。 Bootloader在其中起到的作用包括:一判断正常启动还是DFU升级流程,二启动并校验应用image,三升级的时候完成新image和老image的交换或者拷贝工作。Bootloader首先需要判断是进入正常应用程序启动流程还是DFU流程。
要启动应用image,Bootloader必须知道启动image的启动向量表在哪里。 要校验一个image,Bootloader必须知道这个image正确的校验值存在哪里。 要完成升级,Bootloader必须知道新image所在位置和老image所在位置,并执行一定的拷贝算法。 启动向量表可以放在image的最开始处,也可以放在其他地方,这就涉及到image的格式。 Image正确的校验值可以跟image合在一块存放,也可以单独放在一个flash page里面。如果image的校验值是跟image本身合在一块存放的,这里再次涉及到image的格式。 关于新image和老image存放位置,这就涉及到存储器分区问题。Bootloader的实现将直接决定image的格式,以及存储器的结构划分。 NCS支持MCUboot,B0和nRF5 Bootloader三种Bootloader,三个Bootloader选其一即可,一般推荐大家使用MCUboot。 由于很多读者对Nordic老的SDK,即nRF5 SDK比较熟悉,我们先以这个nRF5 Bootloader为例来讲解他们的Flash分区以及image格式,然后再讲MCUboot和B0,看看他们又是如何分区和定义image格式的。 注意:如果你只对其中某一个具体的Bootloader感兴趣,可以跳过其他章节,直接阅读相关章节,比如如果你只对MCUboot感兴趣,可以只看2.2节。2.1 nRF5 SDK Bootloader介绍
nRF5 Bootloader 是指:nRF5_SDK_17.1.0_ddde560examplesdfusecure_bootloader 这里面定义的Bootloader。 如果你的DFU想使用这个Bootloader,那么nRF5 SDK的存储区划分(双bank)是下面这样的: 在nRF Connect SDK(NCS)中,如果也使用nRF5 Bootloader,此时存储器的分区跟上面大同小异,我们用NCS中的语言重新组织如下: 当前固件(老固件)在Bank0里面执行,新固件接收后直接存放在Bank1,而且程序永远只执行Bank0里面的代码,Bank1的起始地址是动态的,其计算公式为:Bank0起始地址 + Bank0 image大小。 由于nRF5 Bootloader跳到Bank0的时候,直接跳到一个固定地址(0x1000),因此它不需要专门去找新image的启动向量,换句话说,如果使用nRF5 Bootloader的话,新image就是应用代码编译后的样子,不需要添加任何的头或者尾信息。 如果这样的话,image的SHA256或者签名校验怎么做? 在nRF5 Bootloader中,把正确的SHA256或者签名放在settings page里面,这样image就真得不需要任何头或者尾信息,当需要校验image的时候,从settings page中取出标准值,然后进行校验。 那这些标准的SHA256或者签名怎么从远程传过来呢? 答案是init包,所以nRF5 Bootloader升级的时候,需要把一个zip包传给目标设备,如下所示: 这个zip包除了新image本身,还包含一个dat文件,这个dat文件包含新image的大小,SHA256,签名等信息。至于升级拷贝,nRF5 Bootloader做法也很简单,先擦掉Bank0里面的内容,然后把Bank1里面的内容拷贝到Bank0,然后重新从Bank0启动,完成整个升级。 在拷贝之前,Bootloader会校验Bank1里面的image完整性,只有校验通过才会做下一步的拷贝工作,否则退出升级模式。 从上可以看出,虽然nRF5 Bootloader会校验image的完整性,但是如果出现发版错误(打个比方,Win11和Win7都是微软验签,因此完整性校验都可以通过,但是如果微软把Win11发到一台只能跑Win7的设备上,那么这台设备将无法运行),由于它没有新image确认操作,也不支持回滚操作,那么升级后系统有可能挂死在一个错误的版本里面。 说完了启动,校验和升级拷贝,最后说一下如何进入DFU模式。在nRF5 Bootloader里面,通过判断某些Flag(标志位)来决定要不要进入DFU模式,这些标志位有一个为真,进入DFU模式,否则正常启动app:2.2 MCUboot
MCUboot位于如下目录:bootloader/mcuboot/boot/zephyr 在NCS中做DFU的时候,一般都推荐使用MCUboot。 MCUboot功能强大,兼容的芯片平台多,而且是一个久经考验的第三方开源Bootloader。 MCUboot把存储区划分为Primary slot和Secondary slot,而且primary slot跟secondary slot两者大小是一样的,程序默认在Primary slot中执行。 有一点需要大家注意,NCS对MCUboot进行了定制,在NCS中,程序只能在Primary slot中执行,Secondary slot只是用来存储新image,而且Secondary slot可以放在内部Flash,也可以放在外部Flash,这样在NCS中,存储器分区有如下两种典型情况: 注:MCUboot放在0x000000地址。 如前所述,Bootloader有四大功能:启动image,校验image,拷贝image以及DFU模式判断。 那么MCUboot是如何完成这4项功能的:如果长度为0–23,则直接用short count的5 bits来表示,从第2个字节开始表示data payload
如果short count为24(0x18),则表示第2个字节代表长度,从第3个字节开始表示data payload
如果short count为25(0x19),则表示第2和第3个字节合起来表示长度,从第4个字节开始表示data payload
如果short count为26(0x1A),则表示第2,第3,第4和第5个字节合起来表示长度,从第6个字节开始表示data payload
如果short count为27(0x1B),则表示第2至第9个字节合起来表示长度,从第10个字节开始表示data payload
如果short count为31(0x1F),则表示长度为未定义,从第2个字节开始表示data payload,直到遇到停止符:0xFF
签名升级image。注:app_update.bin已经是签过名的image了
上传image,即把app_update.bin传送到目标设备
列出image以获得image的hash值
测试image,即写magic字段,以让MCUboot进入DFU模式
复位设备,以重新进入MCUboot,从而MCUboot进入DFU模式,并执行相应的swap操作,并完成两个slot image之间的交换或者拷贝动作
Confirm image,即新image启动成功后,对其image_ok字段进行置1操作
mcumgr conn add myCOM type="serial" connstring="dev=COM13,baud=115200,mtu=256" (Note: change the COM if needed)
mcumgr -c myCOM image upload app_update.bin
mcumgr -c myCOM image list
mcumgr -c myCOM image test
mcumgr -c myCOM reset
mcumgr -c myCOM image confirm
蓝牙DFU流程解读
当采用BLE作为传输层的时候,上面命令都被手机app打包成二进制数据包直接下发给设备端,但解析出来之后,你会发现蓝牙DFU流程跟上面说明的流程基本上一模一样。比如前面的00 00 00 02 00 01 00 00 bf ff,就是手机发给设备的第一条DFU命令或者说请求(request)。 我们再举一个例子:上传image命令(request),它的第一个数据包示例如下所示: 从包头02 00 00 eb 00 01 00 01可以看出,这个数据包将触发handler: img_mgmt_upload,我们再来看数据包payload的前面8个字节:bf 64 64 61 74 61 58 cc,bf表示后面是map数据,即key/value数据对,0x64,表示后面是text string数据,长度为4,从而得到64这个data item对应的payload为:64 61 74 61,即key=”data”; 从0x58开始,就表示value这个data item了,0x58表示这个item为字节串并且长度为下一个字节:0xcc,也就是说”data”这个key对应的value包含了0xcc个数据的字节流,这样第一个key/value对解析完毕。然后再解析63 6c 65 6e 1a 00 02 05 a8,0x63,表示此item为text string数据,长度为3,从而得到payload为6c 65 6e,即key = ”len”; 0x1a表示此item为正数,count为后面4个字节,也就是说”len”这个key对应的value为0x000205a8,至此第二个key/value对解析完毕。以此类推,我们后面又可以解析出”sha”和”off”两个key以及他们各自的value,最后碰到停止符:0xFF,整个map item结束。 前面说过,整个数据包的payload会通过参数传给img_mgmt_upload作为实参,img_mgmt_upload的函数声明为:3.3 nrf dfu协议
nrf dfu协议就是nRF5 SDK使用的DFU协议,相信很多读者都很熟悉它。 nrf dfu协议定义了两个角色:controller和target,controller发request,target回response,一来一往,完成DFU传输过程。 nrf dfu定义了如下request命令以及他们的response。 Request命令的格式是:Opcode + parameters Response的格式是:60 + Opcode + parameters 比如编码:01 02 00 10 00 00,通过上面解析可以知道它是一个创建数据对象命令NRF_DFU_OP_OBJECT_CREATE,而这条命令的响应是:60 01 01,可以看出也符合上面的定义。 nrf dfu用到了对象概念,什么叫对象(object)? 对象分两种:command object和data object,其中init包是command对象,而image chunk(image块)是data对象。 我们可以进一步提炼一下,nrf dfu协议主要涉及的命令是如下几个:原文标题:【Nordic博文分享系列】nRF Connect SDK(NCS)/Zephyr固件升级详解来啦!
文章出处:【微信公众号:Nordic半导体】欢迎添加关注!文章转载请注明出处。
全部0条评论
快来发表一下你的评论吧 !