nrf51822 DFU升级

基本原理

对于单片机做的产品,要实现在线升级,单片机内部一般是两段代码,一个是bootloader程序,一个是用户app程序,bootloader程序主要就是实现app升级的程序,它是单片机上电后首次运行的程序,app程序就是实现产品功能的程序。
对于nRF51822来说,稍微有点特殊,但是本质原理也是一样的,nRF51822芯片内部有段SoftDevice的程序,它是芯片上电后首次运行的程序,不过这段程序不负责程序升级,它是Nordic官方提供的蓝牙协议栈程序,当然它也具备一点bootloader的功能,也就是说,芯片上电后,它会判断芯片内部是否有bootloader代码(bootloader代码位置固定,所以它能判断出是否有合法的bootloader程序),若有bootloader程序则会跳转到bootloader程序执行,若没有bootloader程序而只检测到了用户的app程序,那么就直接跳转到app程序运行,当然这个bootloader程序是我们自己写的代码,只是它存储的位置和app程序是不一样的。
bootloader程序差不多也只做两件事情,1:控制程序的跳转,比如跳转到app程序;2:实现app程序升级;
当然bootloader是我们自己写的,你要实现更多的功能也是可以的,但是最基本的功能就是这两个,bootloader运行后,检测直接跳转到app的条件是否满足(app程序合法,相关标志位合法),若满足就直接跳转到app执行app程序,若不满足就继续执行bootloader,等待升级的相关操作命令;

Flash空间布局

dual bank

single bank
采用两种不同布局方式的差别:
(1)、single bank布局不支持softdevice及bootloader自身的升级,只支持该芯片上应用程序的升级。
(2)、采用single bank布局的方式中,一旦开始升级,芯片上原有的应用程序将不能被保存。而以dual bank布局的方式中,在开始接收新的二进制程序(image)时,原有的二进制程序(image)将会被保留,如果升级失败不会影响芯片上原有的程序。
目前的SDK DFU都是只支持dual bank升级,如果需要single bank需要使用6.0之前的版本sdk。
还有就是采用dual bank升级的代码大小不能超过总(内存-SoftDevice size - Bootloader size)/2.

DFU之应用程序

在NORDIC的SDK中,有丰富的文档和例子介绍nrf51822的OTA升级流程。
其中:
nRF51_SDK\examples\ble_peripheral\ble_app_hrs\pca10028\s110_with_dfu

nRF51_SDK\examples\dfu\bootloader\pca10028\dual_bank_ble_s110
就有完整的DFU例程。
一般写应用都是从以上上面的例程修改过来。我在这里就从零开始把DFU添加到一个我们本身没有DFU的应用上来。
DFU其实就是在原来的BLE应用上再添加一个服务,服务里包含了一个特征,往这个特征写入某个值(例程是0x01)就设置某些标志位,如果有记录了连接了主机的信息(主要是主机的mac地址),就把这些主机的mac地址放在某个内存,然后触发重启,就可以进入bootloader,bootloader就根据保存在某个内存地址上的标志位确定是否启动DFU,DFU会把保存的主机mac取出来,在广播时用定向广播,这样只有主机(这里是手机)能对这个nrf51822进行升级。
使用DFU升级的BLE程序都需要添加程序代码,增加DFU Service。具本分成以下几步:
(1) 将bootloader_util_arm.c,dfu_app_handler.c,ble_dfu.c三个文件添加到自己的工程中。这个三个文件的位置见SDK的说明。需要指出的是,除了这个三个文件,还应把这三个文件使用的头文件包括进工程,并将路径在Keil中配置好。
(2) 在服务初始化函数中初始华DFU服务。

#include "ble_dfu.h"
#include "dfu_app_handler.h"


    ble_dfu_init_t dfus_init;
   // Initialize the Device Firmware Update Service.
    memset(&dfus_init, 0, sizeof(dfus_init));
    dfus_init.evt_handler = dfu_app_on_dfu_evt;
    dfus_init.error_handler = NULL;
    dfus_init.revision = DFU_REVISION;
    err_code = ble_dfu_init(&m_dfus, &dfus_init);
    APP_ERROR_CHECK(err_code);

    dfu_app_reset_prepare_set(reset_prepare);

(3)在BLE 事件分发函数ble_dfu_on_ble_evt中使用:

ble_dfu_on_ble_evt(&m_dfus, p_ble_evt)
函数,将BLE事件分发给DFU service。
以上即可完成一个基本的支持DFU的应用。

猜你喜欢

转载自blog.csdn.net/dengcanjun6/article/details/54956798