nrf52810 DFU OTA学习记录
-
nrf528xx是Nordic的一个低功耗蓝牙(ble)芯片系列,在比它早期的芯片都是用Cortex-M0的内核,而这个系列用的是Cortex-M4,性能(尤其是浮点运算)提升了一大截。该芯片支持Bluetooth5,并且有mesh的SDK,资料丰富,感觉拿来学习ble非常棒。
DFU OTA,Device Firmware Upgrade Over The Air,即无线固件升级,下面基于官方例程来在自己的app上实现DFU,其中升级包采用ECDSA算法签名,以保证文件源正确。
下面是学习过程的一些记录:一. 环境搭建、跑SKD12例程
- 总结了一下,整套流程是这样走的,加上安全认证有些复杂,关键的问题是要实现bootloader
D:\xiaoan\MC3A\DFU\过程\1531818394085.png)
-
直接编译bootloader会出现两个错误:
1) 缺少公钥
2)缺少uecc.h(缺少ecc库)
-
安装mingw,Minimalist GNU For Windows 是一个编译套件,包括了C/C++ gcc编译工具
1)下载:https://sourceforge.net/projects/mingw/files/
2)下载好后到 【C:\MinGW\bin 】目录下将【mingw32-make.exe】 重命名为【make.exe】
3)在【系统环境变量】 Path中添加:【C:\MinGW\bin】
4)测试:命令行下输入 【make -v】则会出现版本信息,如下:
-
安装GCC compiler toolchain for ARM,用来为Cortex-M and Cortex-R family 编译程序的交叉编译工具链,结合mingw使用,为了编译micro-ecc
1)下载:【https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads】
2)安装:没什么说的,打开直接装就行
3)用编辑器打开【\nRF5_SDK_12.3.0_d7731ad\components\toolchain\gcc\Makefile.windows】修改GNU_INSTALL_ROOT为刚才安装的路径,我这里是【C:/Program Files (x86)/GNU Tools Arm Embedded/7 2018-q2-update】,后面我们编译mico-ecc时候用的是
-
编译micro-ecc
1)下载:【https://github.com/kmackay/micro-ecc】
2)放到bootloader工程的指定路径:将【micro-ecc.zip】中的【micro-ecc-master】解压到【\nRF5_SDK_12.3.0_d7731ad\external\micro-ecc】目录下并修改文件夹名称为【micro-ecc】
3)在【\nRF5_SDK_12.3.0_d7731ad\external\micro-ecc\nrf52_keil\armgcc】目录下打开命令行,输入【make】,进行编译,生成【micro_ecc_lib_nrf52.lib】
-
此时如果在keil中再编译bootloader,则会看到之前报的缺少uecc.h的error没了,下面解决另一个error
-
如果没有python环境,则先装好python(一定用2.x,我这里是3.6.3,后面会遇到问题),安装好后在命令行里运行【python --version】会打印版本信息
-
安装nrfutil.exe,这是nrf为dfu专门做的工具包,用来生成公钥/密钥和打包在线升级app
1)在命令行里输入【pip install nrfutil】就行了,安装好后输入【nrfutil version】 ,会打印版本信息
2)下面要产生密钥,命令行输入【nrfutil.exe keys generate path\private.key】 这里的path随便找个位置,等下密钥会生成在这里。如果用3.x,会出现报错信息
4)命令行输入 【nrfutil keys display --key pk --format code path\private.key --out_file path\public_key.c】生成公钥,将.c文件改名为【dfu_public_key.c】并替换掉【\examples\dfu\bootloader_secure】下的原文件
-
重新编译bootloader,终于通过了...
-
下一步要使用nrfutil.exe工具生成用于更新的zip文件,该文件要包括app和密钥,把application.hex和private.key放在同一个目录下,在次目录中打开命令行,运行:
【nrfutil pkg generate --hw-version 52 --application-version 1 --application application.hex --sd-req0x8C --key-file private.key cc_Dfu12.2.zip】
-
先烧softdevice,,再烧bootloader,可以扫描到蓝牙【DfuTarg】最后把zip通过手机app更新,重启跑进新的app。
二. SDK15 S132 boot例程移植到 S112,跑在NRF52810上
- S112是基于S132进行优化过的版本,nrf52832Flash大小512k,RAM64k,S132协议栈占用152kB,而S112只占了100kB,nrf52810的Flash大小是192k,RAM大小24k;我们的app有50k+,所以只能用S112
- 协议栈更新详细说明在【\components\softdevice\s112\doc\s112_nrf52_6.0.0_migration-document.pdf】里全都有,我们也是根据这个来移植boot
- 打开【\examples\dfu\secure_bootloader\pca10040_ble\arm5_no_packs】boot例程
- 首先修改工程头文件路径,改成112的
- 全局宏定义NRF52832_XXAA 改为NRF52810_XXAA,器件类型也修改为NRF52810_XXAA
-
打开nrf.h,默认NRF52是定义成NRF52832_XXAA了,这样就同时定义了32和10,会有问题。把定义修改如下:
-
编译,因为S112和S132不完全兼容,会出现一些宏定义/结构体之类的问题,一个一个解决,可以参考s112_nrf52_6.0.0_migration-document.pdf
-
FLASH结构设计如下:
这样预留给APP 60kB空间,其中最后4k用于存放用户配置、语音文件等。
所以我们FLASH配置如下:
项目 起始地址 大小 SD112 0x00000 0x19000 USER_APP 0x19000 0xE000 USER_DATA 0x27000 0x1000 BOOT_LOADER 0x28000 0x8000 实际上,这些东西还能再细分的,具体可以参考【S112_SDS_v2.0.pdf】中sector12:
RAM的话,sd和app的堆栈区是共享的,可以参考【S112_SDS_v2.0.pdf】中sector14,但是我没找到S112的SoftDevice RAM consumption具体是多少。实际测最少需要9k,BOOTLOADER实际上也算是一个APP,我们APP和BOOTLOADER的RAM配置都给sd留9k,其余自己用。
APP keil配置例如下:
三. 由APP返回boot
-
参考【\examples\ble_peripheral\ble_app_buttonless_dfu】例程序,只需要移植 ble_dfu_buttonless_bootloader_start_finalize(void) 和 nrf_dfu_svci_vector_table_set(void) 函数即可,可以从APP进入BOOT。
-
原理可以查看文档【S112_SDS_v2.0.pdf】中sector12.2 :
也就是说,如果有BOOTLOADER存在的话, UICR.NRFFW[0]中存放的就是BOOT的向量表(否则是0xFFFFFFFF),通过sd_softdevice_vector_table_base_set(uint32_t address)函数可以设置从哪个地址启动。
- 整个系统流程:
首先得知道,MBR = Master Boot Record,硬件中断只会到达这里,经过MBR的中断源,一部分在softdevice处理,一部分在app处理,这取决于sd占用了哪些资源,剩余的都到app中触发了。
所以问题的关键在怎么切换MBR—app/boot的部分,我只知道用sd_softdevice_vector_table_base_set就行了,但是这个函数没有提供源码,没找到具体是怎么实现的 然后有个很有意思的东西,没弄明白,留在最后