以ble_app_uart例子为基础,在其上添加dfu服务。

Sdk中的bootloader提供了两个方式来进入升级模式,一种是按键,另一种是手机点击升级。

在bootloader代码相关代码如下

如果是手机app通过点击图标直接升级,那么在app跳转到bootloader进行升级前就会设置  NRF_POWER->GPREGRET 这个寄存器的值。所以bootloader代码中开始就是判断这个寄存器中的值来判断是不是手机触发的进入DFU模式。

下面的代码会判断是否有 设备上的按键按下,如果在上电过程中按下按键也会进入DFU模式。

PS:无论是通过手机上的 DFU图标进入升级模式,还是通过设备上的按键进入升级模式都是需要 bootloader的, 两种方式只是进入升级模式 的方式不同而已。

首先打开ble_app_uart工程在keil中添加如下所需模块

然后添加一些DFU相关的处理代码

Main.c中添加

#ifdef BLE_DFU_APP_SUPPORT

#include "ble_dfu.h"

#include "dfu_app_handler.h"

#endif

修改IS_SRVC_CHANGED_CHARACT_PRESENT 宏为1

Main.c中添加如下宏

Main.c中添加如下静态变量

#ifdef BLE_DFU_APP_SUPPORT

static ble_dfu_t                         m_dfus;

#endif

Main.c中添加如下3个函数

#ifdef BLE_DFU_APP_SUPPORT
/**@brief Function for stopping advertising.
 */
static void advertising_stop(void)
{
    uint32_t err_code;

    err_code = sd_ble_gap_adv_stop();
    APP_ERROR_CHECK(err_code);

    err_code = bsp_indication_set(BSP_INDICATE_IDLE);
    APP_ERROR_CHECK(err_code);
}

/**@brief Function for loading application-specific context after establishing a secure connection.
 *
 * @details This function will load the application context and check if the ATT table is marked as
 * changed. If the ATT table is marked as changed, a Service Changed Indication
 * is sent to the peer if the Service Changed CCCD is set to indicate.
 *
 * @param[in] p_handle The Device Manager handle that identifies the connection for which the context
 * should be loaded.
 */
static void app_context_load(dm_handle_t const * p_handle)
{
    uint32_t err_code;
    static uint32_t context_data;
    dm_application_context_t context;

    context.len = sizeof(context_data);
    context.p_data = (uint8_t *)&context_data;

    err_code = dm_application_context_get(p_handle, &context);
    if (err_code == NRF_SUCCESS)
    {
        // Send Service Changed Indication if ATT table has changed.
        )
        {
            err_code = sd_ble_gatts_service_changed(m_conn_handle, APP_SERVICE_HANDLE_START, BLE_HANDLE_MAX);
            if ((err_code != NRF_SUCCESS) &&
                (err_code != BLE_ERROR_INVALID_CONN_HANDLE) &&
                (err_code != NRF_ERROR_INVALID_STATE) &&
                (err_code != BLE_ERROR_NO_TX_BUFFERS) &&
                (err_code != NRF_ERROR_BUSY) &&
                (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING))
            {
                APP_ERROR_HANDLER(err_code);
            }
        }

        err_code = dm_application_context_delete(p_handle);
        APP_ERROR_CHECK(err_code);
    }
    else if (err_code == DM_NO_APP_CONTEXT)
    {
        // No context available. Ignore.
    }
    else
    {
        APP_ERROR_HANDLER(err_code);
    }
}

/** @snippet [DFU BLE Reset prepare] */
/**@brief Function for preparing for system reset.
 *
 * @details This function implements @ref dfu_app_reset_prepare_t. It will be called by
 * @ref dfu_app_handler.c before entering the bootloader/DFU.
 * This allows the current running application to shut down gracefully.
 */
static void reset_prepare(void)
{
    uint32_t err_code;

    if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
    {
        // Disconnect from peer.
        err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
        APP_ERROR_CHECK(err_code);
        err_code = bsp_indication_set(BSP_INDICATE_IDLE);
        APP_ERROR_CHECK(err_code);
    }
    else
    {
        // If not connected, the device will be advertising. Hence stop the advertising.
        advertising_stop();
    }

    err_code = ble_conn_params_stop();
    APP_ERROR_CHECK(err_code);

    nrf_delay_ms();
}
/** @snippet [DFU BLE Reset prepare] */
#endif // BLE_DFU_APP_SUPPORT

以上代码都用  BLE_DFU_APP_SUPPORT 这个宏来包含了,所以添加这些代码后需要在工程设置中添加一下这个宏的定义。

PS:官方的 hrs例子中 存在带dfu的工程,打开那个工程直接全局搜这个宏就能找到上面这个和 dfu相关的代码了。这里的代码就是从那里拷贝过来的。

Main.c中的services_init函数的最后添加 创建dfu 服务的代码

static void services_init(void)

{

………………………

……………………….

#ifdef BLE_DFU_APP_SUPPORT

/** @snippet [DFU BLE Service initialization] */

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.evt_handler   = dfu_app_on_dfu_evt;

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);

dfu_app_dm_appl_instance_set(m_app_handle);

#endif // BLE_DFU_APP_SUPPORT

}

事件派发函数中 添加 dfu的事件处理函数以及 device_manage模块的事件处理函数

Main.c中再添加如下函数和代码

这时候编译下载程序后使用nordic 官方软件 nrf master control panel软件 连接设备后可以看到右上角有一个DFU的小图标。点击那个就可以升级了。

PS:别忘了需要烧写bootloader

那么点击这个dfu图标后是如何跳转bootloader进入升级模式的呢。

前面我们在service_init 中添加了dfu服务的创建。

函数中设置了一个回调函数 dfu_app_on_dfu_evt

当点击 DFU 图标后就会发送一条启动指令,dfu_app_on_dfu_evt函数中会处理这条指令

Bootloader_start函数就是做一些设置然后跳转到bootloader中去

上面的 sd_power_gpregret_set函数就是设置一个标记,表明从是从app 中启动进入bootloader的。

和前面说的bootloader代码中开头的判断所对应

Sdk中的bootloader例子是基于32Kram的51422,如果使用16kram的51822需要修改如下地址

另外,一旦烧录bootloader后设备上电启动顺序不再是 协议栈->app

而是 协议栈->bootloader->app

在bootloader中会对app是否有效做判断,sdk中的实现是只有通过DFU模式升级的app才会被认为有效的,应为DFU模式升级后会设置一些相关标志。 DFU判断app是不是有效就是判断这些标志, 所以如果你用烧录软件烧写app,因为没有设置一些标志,所以bootloader会认为 app无效,从而不会启动app。

不过可以通过修改一下变量来实现,即使通过烧录软件烧录app,bootloader也可以正常启动app。

打开bootlaoder工程中的bootloader_settings.c文件,修改如下变量就可以了。

如果应用程序中使用了看门狗那么dfu中也需要喂狗,51822的看门狗打开后就会一直运行。

看门狗最好设置成 睡眠时看门狗也停止,这样方便处理,只要在 唤醒后喂狗就行了,睡眠多久无所谓,因为睡眠时看门狗不会计数

直接将下面两个值设置为0。

bootloader代码中添加喂狗代码

nrf51822-添加DFU服务的更多相关文章

  1. 手动配置三台虚拟机pacemaker+corosync并添加httpd服务

    创建三台虚拟机,实验环境:centos7.1,选择基础设施服务安装. 每台虚拟机两块网卡,第一块为pxe,第二块连通外网,手动为两块网卡配置IP.网关,使它们都能ping通外网并可以互相通过hostn ...

  2. 如何启动免安装版Tomcat并将Tomcat添加到服务中

    1.安装jdk,并配置环境变量 (1)在Path中添加 F:\Program Files\Java\jdk1.8.0_25\bin (2)添加一个JAVA_HOME变量,变量值为F:\Program ...

  3. 如何手动添加Windows服务和如何把一个服务删除

    windows 手动添加服务方法一:修改注册表 在注册表编辑器,展开分支"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services" ...

  4. 添加无线服务wzcsvc服务,Eventlog服务

    <添加eventlog服务.reg> Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentCont ...

  5. Centos7 install Openstack - (第四节)添加计算服务(Nova)

    Centos7 install Openstack - (第四节)添加计算服务(Nova) 我的blog地址:http://www.cnblogs.com/caoguo 该文根据openstack官方 ...

  6. Centos7 install Openstack - (第三节)添加镜像服务(Glance)

    Centos7 install Openstack - (第三节)添加镜像服务(Glance) 我的blog地址:http://www.cnblogs.com/caoguo 该文根据openstack ...

  7. 关于WCF的引用,添加服务和添加web服务的区别

    原文:关于WCF的引用,添加服务和添加web服务的区别 本章内容主要是根据我做的实验来阐述这2种添加服务针对WCF的不同之处,我们按照示例一步一步来看. 如下是工程的结构: 该WCF服务是通过控制台程 ...

  8. 将Tomcat添加进服务启动

    tomcat有解压版和安装版2种版本,安装版已经做好了将tomcat添加进服务的操作,而解压版需要我们自己来实现,应用场景主要是在服务器端需要在服务器启动时就启动tomcat. 1.首先需要配置好jd ...

  9. 将项目添加到服务上时报web modules的错误

    将项目添加到服务上时报web modules的错误如下图: 这是tomcat的版本和web modules的版本不支持造成的,如果在如下地方修改不了: 这时候就要在项目的根目录修改如下图: 用工具打开 ...

随机推荐

  1. cmd.ExecuteNonQuery();和cmd.ExecuteScalar();

    C#...cmd.ExecuteNonQuery();是返回执行命令后影响的参数 返回符合你条件的所有语句,如果你要数据库里某张表的数据,说执行这个命令后他返回的是就是这张表的全部数据cmd.Exec ...

  2. sql 遍历结果print和表格形式

    select * from tb_province --省 pID pName1 北京市2 天津市3 上海市4 重庆市5 河北省6 山西省....... select * from tb_city - ...

  3. XML的验证模式

    XML文件的验证模式保证了XML文件的正确性,而比较常用的验证模式有两种:DTD和XSD. DTD与XSD区别 DTD(Document Type Definition)即文档类型定义,是一种XML约 ...

  4. HDU3037 Saving Beans(Lucas定理+乘法逆元)

    题目大概问小于等于m个的物品放到n个地方有几种方法. 即解这个n元一次方程的非负整数解的个数$x_1+x_2+x_3+\dots+x_n=y$,其中0<=y<=m. 这个方程的非负整数解个 ...

  5. Square Coins[HDU1398]

    Square Coins Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...

  6. BZOJ3784 : 树上的路径

    树的点分治,在分治的时候将所有点到根的距离依次放入一个数组q中. 对于一棵子树里的点,合法的路径一定是q[L]..q[R]的某个数加上自己到重心的距离. 定义五元组(v,l,m,r,w),表示当前路径 ...

  7. Robotium Table控件的处理

    HTML代码: <html> <head> <title>Table</title> </head> <body> <ta ...

  8. lintcode :Coins in Line II 硬币排成线 II

    题目 硬币排成线 II 有 n 个不同价值的硬币排成一条线.两个参赛者轮流从左边依次拿走 1 或 2 个硬币,直到没有硬币为止.计算两个人分别拿到的硬币总价值,价值高的人获胜. 请判定 第一个玩家 是 ...

  9. [转]Multiple outputs from T4 made easy

    本文转自:http://damieng.com/blog/2009/01/22/multiple-outputs-from-t4-made-easy One of the things I wante ...

  10. NBOJv2 1004 蛤玮打扫教室(线段树区间更新区间最值查询)

    Problem 1004: 蛤玮打扫教室 Time Limits:  1000 MS   Memory Limits:  65536 KB 64-bit interger IO format:  %l ...