前言

SDK版本15.3

评估板:pca10040

在 uart 的例程中添加 DFU 功能,使用 s132 的协议栈,因为官方的 BootLoader 工程用的是s132的协议栈。

一、准备工作

在开始实验之前必须先准备以下软件:

  • gcc-arm-none-eabi-7-2018-q2-update-win32.exe

由于使用加密的dfu需要用到micro-ecc库进行签名验证,需要micro_ecc_lib_nrf52.lib,而官方的sdk中并没有加入micro_ecc_lib_nrf52.lib,所以需要我们自己编译

直接在官网下载或者用我下载好的,

官网下载地址:https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads

我下载好的:https://download.csdn.net/download/m_pfly_fish/12152291

15.3的sdk用的是7-2018-q2-update版本的gcc,安装这个版本可以跳过编译micro-ecc库时对Makefile.windows文件的修改。用其他版本的gcc时,需要根据版本修改该文件中的gcc路径和版本信息

  • make-3.81.exe

官网下载地址:http://gnuwin32.sourceforge.net/packages/make.htm

我下好的:https://download.csdn.net/download/m_pfly_fish/12153126

Windows系统的gnu编译器,执行make用

  • micro-ecc-master.zip

官网下载地址:https://github.com/kmackay/micro-ecc

Nordic的DFU中采用了micro-ecc实现ECDSA算法,编译micro_ecc_lib_nrf52.lib时所用到的源码

  • python-2.7.12.amd64.msi

官网下载地址:https://www.python.org/downloads/

我下好的:https://download.csdn.net/download/m_pfly_fish/12153141

nrfutil需要用到python-2.7的环境

  • nRFgo Studio

从官网下就行

我下好的:https://download.csdn.net/download/m_pfly_fish/12051047

主要提供nrfjprog.exe和mergehex.exe。这两个软件在nRFgo Studio的安装目录下找到 C:\Program Files (x86)\Nordic Semiconductor\nrf5x\bin 安装之后用cmd输入nrfjprog和mergehex,查看是否安装可用。

  • oreutils-5.3.0.exe

官网下载地址:http://gnuwin32.sourceforge.net/packages/coreutils.htm

我下好的:https://download.csdn.net/download/m_pfly_fish/12153167

二、软件安装

2.1 双击安装 make-3.81.exe

一直next,注意安装目录使用默认的c盘

2.2 双击安装 coreutils-5.3.0.exe

一直next,注意安装目录使用默认的c盘

2.3 双击安装 gcc-arm-none-eabi-7-2018-q2-update-win32.exe

一直next,注意安装目录使用默认的c盘

安装完成后需要将路径C:\Program Files (x86)\GNU Tools ARM Embedded\7 2018-q2-update\bin;和C:\Program Files (x86)\GnuWin32\bin添加到环境变量Path中

我因为之前还安装了 4.9 2015q3 的 gcc 所以Path中多一个4.9版本的路径

2.4 安装 python-2.7.12.amd64.msi

一直next,注意安装目录使用默认的c盘

安装完毕后,同样需要把python的路径加到环境变量中

添加完成后需要安装 nrfutil

打开 cmd 命令行窗口,跳转至 C:\Python27 目录下,输入python -m pip install nrfutil等待安装完成

三、修改编译BootLoader工程

直接编译sdk中的secure_bootloader工程时会出现以下报错,找不到 uECC.h,micro_ecc_lib_nrf52.lib 和 pk

error:  #5: cannot open source input file "uECC.h": No such file or directory

error: L6002U: Could not open file ..\..\..\..\..\external\micro-ecc\nrf52hf_keil\armgcc\micro_ecc_lib_nrf52.lib: No such file or directory

Error: L6218E: Undefined symbol pk (referred from nrf_dfu_validation.o).

3.1 先解决 缺少 uECC.h 的问题

将下载的 micro-ecc-master.zip 解压后修改文件夹名为 micro-ecc,然后拷贝至 nRF5_SDK_15.3.0_59ac345\external\micro-ecc 目录下

在该文件夹中可以找到 uECC.h

3.2 解决缺少 micro_ecc_lib_nrf52.lib 的问题

如果你使用的是15.3的sdk,并且安装了 gcc-arm-none-eabi-7-2018-q2-update-win32.exe 版本的gcc,那么直接双击运行build_all.bat 脚本就可以自动编译出 micro_ecc_lib_nrf52.lib ,在 nRF5_SDK_15.3.0_59ac345\external\micro-ecc\nrf52hf_keil\armgcc 目录中可以找到  micro_ecc_lib_nrf52.lib

假如使用的不是15.3版本的sdk或者使用的不是 gcc-arm-none-eabi-7-2018-q2-update-win32.exe版本的gcc,那么需要修改 nRF5_SDK_15.3.0_59ac345\components\toolchain\gcc 目录下 Makefile.windows 文件

GNU_INSTALL_ROOT := C:/Program Files (x86)/GNU Tools ARM Embedded/7 2018-q2-update/bin/

GNU_VERSION := 7.3.1

GNU_PREFIX := arm-none-eabi

将gcc编译器路径更换为实际路径和实际版本

我使用 4.9 2015q3版本的 gcc 时,将修改 Makefile.windows 文件修改为:

GNU_INSTALL_ROOT := C:/Program Files (x86)/GNU Tools ARM Embedded/4.9 2015q3/bin/

GNU_VERSION := 6.3.0

GNU_PREFIX := arm-none-eabi

3.3 解决缺少 pk 的问题

打开cmd命令行,输入一下指令

nrfutil.exe keys generate private.pem

nrfutil.exe keys display --key pk --format code private.pem --out_file public_key.c

这样生成的秘钥就保存在 public_key.c中,打开public_key.c。把数组pk复制到报错的位置。

3.4 修改BootLoader工程代码

解决完报错后,BootLoader工程还不能正常工作,需要根据情况修改代码

  • 如果LED灯IO口跟secure_bootloader工程默认引脚不同或原来LED引脚用作其他功能,需要将dfu_observer()函数中LED灯相关代码屏蔽,否则会一直运行在bootloader,不跳转到application

3.5 配置sdk_config文件

将进入DFU方式改为无按键的BLE连接发送命令方式

四、修改Application工程

4.1 配置sdk_config文件

  • 使能 dfu service

  • 修改 VS UUID COUNT 值,因为dfu service使用了 128bit 的自定义的 base uuid,所以这里需要在原先的 count 值上+1

4.2 修改ram空间

因为添加了一个自定义的 base uuid,所以需要修改 ram 空间,每增加一个uuid,IRAM1的起始地址就要增加0x10,size 同时减少0x10。

4.3 添加Include目录

  • …/…/…/…/…/…/components/libraries/bootloader
  • …/…/…/…/…/…/components/libraries/bootloader/ble_dfu
  • …/…/…/…/…/…/components/libraries/bootloader/dfu
  • …/…/…/…/…/…/components/libraries/svc

4.4 添加源文件

在工程中增加一个文件夹nRF_DFU,并添加以下文件:

  • \components\ble\ble_services\ble_dfu\ble_dfu.c
  • \components\ble\ble_services\ble_dfu\ble_dfu_bonded.c
  • \components\ble\ble_services\ble_dfu\ble_dfu_unbonded.c

在工程中增加一个文件夹nRF_SVC,并添加以下文件:

  • \components\libraries\bootloader\dfu\nrf_dfu_svci.c

4.5添加宏

添加下列项:

  • NRF_DFU_TRANSPORT_BLE=1
  • BL_SETTINGS_ACCESS_ONLY
  • NRF_DFU_SVCI_ENABLED

4.6 修改 main.c

添加头文件

#include "nrf_dfu_ble_svci_bond_sharing.h"
#include "nrf_svci_async_function.h"
#include "nrf_svci_async_handler.h"
#include "ble_dfu.h"
#include "nrf_power.h"
#include "nrf_bootloader_info.h"

添加代码

/**@brief Handler for shutdown preparation.** @details During shutdown procedures, this function will be called at a 1 second interval*          untill the function returns true. When the function returns true, it means that the*          app is ready to reset to DFU mode.** @param[in]   event   Power manager event.** @retval  True if shutdown is allowed by this power manager handler, otherwise false.*/
static bool app_shutdown_handler(nrf_pwr_mgmt_evt_t event)
{switch (event){case NRF_PWR_MGMT_EVT_PREPARE_DFU:NRF_LOG_INFO("Power management wants to reset to DFU mode.");// YOUR_JOB: Get ready to reset into DFU mode//// If you aren't finished with any ongoing tasks, return "false" to// signal to the system that reset is impossible at this stage.//// Here is an example using a variable to delay resetting the device.//// if (!m_ready_for_reset)// {//      return false;// }// else//{////    // Device ready to enter//    uint32_t err_code;//    err_code = sd_softdevice_disable();//    APP_ERROR_CHECK(err_code);//    err_code = app_timer_stop_all();//    APP_ERROR_CHECK(err_code);//}break;default:// YOUR_JOB: Implement any of the other events available from the power management module://      -NRF_PWR_MGMT_EVT_PREPARE_SYSOFF//      -NRF_PWR_MGMT_EVT_PREPARE_WAKEUP//      -NRF_PWR_MGMT_EVT_PREPARE_RESETreturn true;}NRF_LOG_INFO("Power management allowed to reset to DFU mode.");return true;
}//lint -esym(528, m_app_shutdown_handler)
/**@brief Register application shutdown handler with priority 0.*/
NRF_PWR_MGMT_HANDLER_REGISTER(app_shutdown_handler, 0);static void buttonless_dfu_sdh_state_observer(nrf_sdh_state_evt_t state, void * p_context)
{if (state == NRF_SDH_EVT_STATE_DISABLED){// Softdevice was disabled before going into reset. Inform bootloader to skip CRC on next boot.nrf_power_gpregret2_set(BOOTLOADER_DFU_SKIP_CRC);//Go to system off.nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF);}
}/* nrf_sdh state observer. */
NRF_SDH_STATE_OBSERVER(m_buttonless_dfu_state_obs, 0) =
{.handler = buttonless_dfu_sdh_state_observer,
};static void advertising_config_get(ble_adv_modes_config_t * p_config)
{memset(p_config, 0, sizeof(ble_adv_modes_config_t));p_config->ble_adv_fast_enabled  = true;p_config->ble_adv_fast_interval = APP_ADV_INTERVAL;p_config->ble_adv_fast_timeout  = APP_ADV_DURATION;
}static void disconnect(uint16_t conn_handle, void * p_context)
{UNUSED_PARAMETER(p_context);ret_code_t err_code = sd_ble_gap_disconnect(conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);if (err_code != NRF_SUCCESS){NRF_LOG_WARNING("Failed to disconnect connection. Connection handle: %d Error: %d", conn_handle, err_code);}else{NRF_LOG_DEBUG("Disconnected connection handle %d", conn_handle);}
}// YOUR_JOB: Update this code if you want to do anything given a DFU event (optional).
/**@brief Function for handling dfu events from the Buttonless Secure DFU service** @param[in]   event   Event from the Buttonless Secure DFU service.*/
static void ble_dfu_evt_handler(ble_dfu_buttonless_evt_type_t event)
{switch (event){case BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE:{NRF_LOG_INFO("Device is preparing to enter bootloader mode.");// Prevent device from advertising on disconnect.ble_adv_modes_config_t config;advertising_config_get(&config);config.ble_adv_on_disconnect_disabled = true;ble_advertising_modes_config_set(&m_advertising, &config);// Disconnect all other bonded devices that currently are connected.// This is required to receive a service changed indication// on bootup after a successful (or aborted) Device Firmware Update.uint32_t conn_count = ble_conn_state_for_each_connected(disconnect, NULL);NRF_LOG_INFO("Disconnected %d links.", conn_count);break;}case BLE_DFU_EVT_BOOTLOADER_ENTER:// YOUR_JOB: Write app-specific unwritten data to FLASH, control finalization of this//           by delaying reset by reporting false in app_shutdown_handlerNRF_LOG_INFO("Device will enter bootloader mode.");break;case BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED:NRF_LOG_ERROR("Request to enter bootloader mode failed asynchroneously.");// YOUR_JOB: Take corrective measures to resolve the issue//           like calling APP_ERROR_CHECK to reset the device.break;case BLE_DFU_EVT_RESPONSE_SEND_ERROR:NRF_LOG_ERROR("Request to send a response to client failed.");// YOUR_JOB: Take corrective measures to resolve the issue//           like calling APP_ERROR_CHECK to reset the device.APP_ERROR_CHECK(false);break;default:NRF_LOG_ERROR("Unknown event from ble_dfu_buttonless.");break;}
}

在 int main(void) 中添加以下代码

    ret_code_t err_code; // Initialize the async SVCI interface to bootloader before any interrupts are enabled.err_code = ble_dfu_buttonless_async_svci_init();APP_ERROR_CHECK(err_code);

在static void services_init(void)中添加以下代码

    ble_dfu_buttonless_init_t dfus_init = {0};dfus_init.evt_handler = ble_dfu_evt_handler;err_code = ble_dfu_buttonless_init(&dfus_init);APP_ERROR_CHECK(err_code);

五、生成烧录固件

直接烧录softdevice、bootloader和application,会发现application并未运行,芯片一直跑在Bootloader中。

芯片启动后先进入Bootloader,检测Bootloader Settings中的数据,如果这些数据指示Flash中有一个有效的Application,则跳转进入Application。Bootloader Settings是Flash中的一段区域,它包含了Application的大小、CRC等数据,执行DFU时也会在这里存储状态信息。

正常执行DFU时,Bootloader自动生成和维护Bootloader Settings信息。而烧录过程不同,需要手动写入。可以根据application.hex生成一个bl_settings.hex,以产生这些数据,然后烧录这个hex,而我们一般将需要烧录的bl_settings.hex、softdevice、bootloader 和 application 文件合并成一个文件,方便量产烧录

5.1 生成bl_settings.hex

打开cmd命令窗口 输入 nrfutil.exe settings generate --family NRF52 --application nrf52832_xxaa_app.hex --application-version 0 --bootloader-version 0 --bl-settings-version 2 bootloader_settings.hex

application-version、bootloader-version、bl-settings-version 分别是 application 版本号、 bootloader 版本号和 bl-settings版本号,可以自定。

5.2 合并 bl_settings.hex、softdevice、bootloader 和 application 文件

合并 BootLoader 文件和 softdevice 文件:mergehex.exe --merge nrf52832_xxaa_s132_bootloader.hex s132_nrf52_6.1.1_softdevice.hex --output production_final1.hex

合并 application 文件:mergehex.exe --merge production_final1.hex nrf52832_xxaa_app.hex --output production_final2.hex

合并 bl_settings.hex 文件:mergehex.exe --merge production_final2.hex bootloader_settings.hex --output production_final.hex

production_final 文件就是最终烧录固件,通过以下指令可以直接烧录固件至开发板中:

  • nrfjprog -f NRF52 --eraseall
  • nrfjprog -f NRF52 --program "production_final.hex" --verify
  • nrfjprog -f NRF52 --reset

六、打包ota固件

打包OTA所需的zip文件。这里只介绍升级 application 的方法

打开cmd命令窗口 输入 nrfutil pkg generate --hw-version 52 --sd-req 0xB7 --application-version 1 --application nrf52832_xxaa_app.hex --key-file private.pem nrf52832_xxaa_app.zip

其中

--sd-req 0xB7,0xB7 是协议栈版本,查看方式可以用nrf go连接板子后查看

--application-version 1 是 application 版本,自定

--key-file private.pem 是之前编译 bootloader 工程时生成的私钥文件

生成的压缩包就是 ota 文件。

七、OTA操作流程

以下用图片来演示操作 ota 流程

发送df命令,控制设备进入BootLoader

BootLoader模式下的设备名可以在BootLoader工程中进行更改

点击右上dfu按钮进行开始ota

ota完成后,设备会自动重启,跳转至 application

参考

https://blog.csdn.net/qq_36347513/article/details/103744653

https://blog.csdn.net/jdsnpgxj/article/details/80772727

(有空再把dfu的原理总结出来)

NRF52832学习笔记(2)—— 添加DFU功能(基于SDK15.3)相关推荐

  1. nrf52832 学习笔记(七)蓝牙协议层级理解

    nrf52832 学习笔记(七)蓝牙协议层级理解 本文主要由一下几篇文档摘录汇总而成 ,如有错误欢迎斧正 da14531 蓝牙协议文档 深入浅出低功耗蓝牙(BLE)协议栈 低功耗蓝牙ATT/GATT/ ...

  2. nrf52832 学习笔记(二)SDK框架分析

    nrf52832 学习笔记(二)SDK框架分析 个人对SDK框架的一些理解,如有错误欢迎斧正. flash 分区 在不包含DFU的情况下,nrf52832 flash划分为: MBR 0x000000 ...

  3. nrf52832 学习笔记(三)蓝牙从机广播

    nrf52832 学习笔记(三)蓝牙从机广播 蓝牙从机要想被主机连接,首先需要发送广播信息,周围主机通过扫描广播信号,根据从机的广播信息,判断是否连接. 蓝牙协议栈初始化 不管是主机还是从机,要想使用 ...

  4. nrf52832 学习笔记(六)配对和绑定

    nrf52832 学习笔记(六)配对和绑定 配对绑定推荐博客低功耗蓝牙配对绑定解读和实践 蓝牙在配对之前都是明文通信的,也就是说主从机之间传输的数据包可以被第三方抓取分析逆向,而且如果没有配对,谁都可 ...

  5. NRF52832学习笔记(40)——RFID RC522使用

    一.简介 MF RC522 是应用于 13.56MHz 非接触式通信中高集成度读写卡系列芯片中的一员.是 NXP 公司针对"三表"应用推出的一款低电压.低成本.体积小的非接触式读写 ...

  6. NRF52832学习笔记(18)——RFID SI522使用

    一.简介 ACD(低功耗寻卡)只是一种模式,和 PCD(普通寻卡)是一样的,在使用到 ACD 模式时,其实就是普通的读写模式和低功耗模式的切换,可以理解为"ACD 函数"中嵌套了一 ...

  7. OpenCV学习笔记(二十六)——小试SVM算法ml OpenCV学习笔记(二十七)——基于级联分类器的目标检测objdect OpenCV学习笔记(二十八)——光流法对运动目标跟踪Video Ope

    OpenCV学习笔记(二十六)--小试SVM算法ml 总感觉自己停留在码农的初级阶段,要想更上一层,就得静下心来,好好研究一下算法的东西.OpenCV作为一个计算机视觉的开源库,肯定不会只停留在数字图 ...

  8. JavaWeb-综合案例(用户信息)-学习笔记02【登录功能】

    Java后端 学习路线 笔记汇总表[黑马程序员] JavaWeb-综合案例(用户信息)-学习笔记01[列表查询] JavaWeb-综合案例(用户信息)-学习笔记02[登录功能] JavaWeb-综合案 ...

  9. nrf52832 学习笔记(五)蓝牙主从机连接和连接参数更新

    nrf52832 学习笔记(五)蓝牙主从机连接和连接参数更新 主机连接 nrf52832 SDK中主机连接从机需要使用 sd_ble_gap_connect(ble_gap_addr_t const ...

最新文章

  1. Error: Module build failed: TypeError: this.getResolve is not a function at Object.loader
  2. re.search中与正则表达式*结合使用的注意事项
  3. 错误代码中文查询GetLastError返回代码的含义
  4. python list去重函数_python 列表函数
  5. ntp同步 mysql_解析Mysql 主从同步延迟原理及解决方案
  6. 本部裁员、分部招人,科技公司的岗位都奔向了外地?
  7. @Value取值为NULL的解决方案
  8. 同步异步和阻塞3-同步阻塞
  9. thinkphp 文件下载实例 实现以及注意事项
  10. 一二线城市有哪些值得加入的互联网公司?
  11. 设计模式——Facade(外观)模式
  12. PL3369C原边12W电源芯片
  13. TI DSP 6657 SRIO 简介
  14. 【python】二进制与十进制的转换
  15. 2018 CTCS第五届“智能出行”中国企业差旅合规高峰论坛即将开幕
  16. 魔法少女小Scarlet
  17. 桥牌坐庄训练bm2000 level3闯关记录——A9
  18. Zabbix Meetup上海站回顾+ppt下载
  19. Deepin下codeblocks安装汉化以及环境配置
  20. C#连接Access2013

热门文章

  1. 信息系统项目管理系列之十:项目人力资源管理
  2. el-select右侧图标换成自定义的箭头,且箭头向上
  3. Qt5 学习之路及嵌入式开发教程11:Qt5标准输入对话框类及QSlider控件
  4. springboot整合jsp模板
  5. 远程桌面从服务器拷文件出错
  6. 键盘win键无法使用,win+r不生效、win键没反应、Windows键失灵万能解决方案
  7. OpenGL之常用方法整理
  8. Hinton曾授课,斯坦福首个Transformers专题讲座视频放出,NLP、CV和RL无所不包
  9. spring boot: Whitelabel Error Page(小白的终极解决方案)
  10. Android使用VideoView播放网络视频