DFU移植方式详解
为方便用户将GR5xx提供的DFU方案应用到自定义的工程中,本章以ble_app_template_dfu示例工程为例(工程位于SDK_Folder\projects\ble\ble_peripheral\ble_app_template_dfu),介绍为该工程移植DFU功能的操作。移植过程主要包括以下步骤:
- 添加DFU组件和OTA Profile。
- DFU初始化。
- 添加DFU调度器。
- DFU服务初始化及数据接收处理。
- 修改固件地址和名称。
具体操作步骤如下:
-
添加DFU组件和OTA Profile。
在gr_libraries和gr_profiles工程文件夹下分别添加dfu_port.c(位于SDK_Folder\components\libraries\dfu_port)和otas.c文件(SDK_Folder\components\profiles\otas),如下图所示。
图 48 Keil工程列表 - DFU初始化,代码位于user_periph_setup.c文件的app_periph_init()函数中,如下所示:
#include “dfu_port.h” void app_periph_init(void) { …… dfu_uart_init(); dfu_port_init(uart_send_data, DFU_FW_SAVE_ADDR, &dfu_pro_call); …… }
- dfu_uart_init()是串口初始化函数,当使用串口通讯方式时,需要初始化串口。具体实现可参考user_periph_setup.c中的dfu_uart_init()函数。
- dfu_port_init()是DFU初始化函数,初始化时注册串口发送接口、固件存储地址以及升级过程回调函数。
- uart_send_data是串口发送数据函数,使用UART通信方式升级时,需要注册该接口,具体实现可参考user_periph_setup.c中的uart_send_data()函数。
- DFU_FW_SAVE_ADDR表示向Master推荐的固件存储地址(Bank1起始地址)。以GR551x为例,其值可设置为:
#define DFU_FW_SAVE_ADDR (FLASH_START_ADDR + 0x60000)
说明:该宏的值不是固定的。设置时需注意不能和App bootloader固件、Bank0固件的地址冲突。
- dfu_pro_call是升级过程中的升级进度回调函数结构体全局变量,具体定义可参考如下代码:
static void dfu_program_start_callback(void); static void dfu_programing_callback(uint8_t pro); static void dfu_program_end_callback(uint8_t status); static dfu_pro_callback_t dfu_pro_call = { .dfu_program_start_callback = dfu_program_start_callback, .dfu_programing_callback = dfu_programing_callback, .dfu_program_end_callback = dfu_program_end_callback, }; static void dfu_program_start_callback(void) { APP_LOG_DEBUG("Dfu start program"); } static void dfu_programing_callback(uint8_t pro) { APP_LOG_DEBUG("Dfu programing---%d%%", pro); } static void dfu_program_end_callback(uint8_t status) { APP_LOG_DEBUG("Dfu program end"); if (0x01 == status) { APP_LOG_DEBUG("status: successful"); } else { APP_LOG_DEBUG("status: error"); } }
- 添加DFU调度器,并需添加头文件
#include "dfu_port.h"
,如下所示:#include "dfu_port.h" int main(void) { …… while (1) { dfu_schedule(); …… } }
- DFU服务初始化及数据接收处理。
当使用低功耗蓝牙通信方式升级时,在 user_app.c文件的service_init函数中初始化DFU相关服务,如下所示:
static void services_init(void) { dfu_service_init(dfu_enter); }
dfu_enter()函数定义默认为空,用户可在函数内部添加DFU启动时的自定义操作。
当以UART通信方式升级时,需添加接收数据处理操作,参考代码如下所示:
void dfu_uart_evt_handler(app_uart_evt_t * p_evt) { switch(p_evt->evt_type) { …… case APP_UART_EVT_RX_DATA: …… dfu_uart_receive_data_process(s_dfu_uart_rx_buffer, p_evt->data.size); app_uart_receive_async(APP_UART1_ID, s_dfu_uart_rx_buffer,DFU_UART_RX_BUFF_SIZE); …… break; …… } }
说明:在手机端当前连接设备的DFU任务尚处于停止状态时,点击升级按钮前,若需通过 GRToolbox 获取固件信息,可通过写控制点的方式手动下发唤醒DFU任务的命令,具体操作请参考固件升级。
- 修改固件地址和名称。
-
根据Flash布局设计,修改固件地址。在custom.config.h中设置APP_CODE_LOAD_ADDR和APP_CODE_RUN_ADDR。以GR551x为例,将APP_CODE_RUN_ADDR和APP_CODE_LOAD_ADDR设置为0x01030000。
- 修改固件名称。参考App bootloader查找APP固件规则,如果App bootloader使能了BOOTLOADER_BY_NAME_ENABLE(默认使能),为使App bootloader固件能正确跳转至应用固件,则需匹配两者的固件名称。App bootloader固件默认COMMENTS为"ble_app_temp",因此需在custom.config.h中添加如下的ble_app_template_dfu固件COMMENTS。
#define APP_INFO_COMMENTS "ble_app_temp"
-