Bluetooth SDK里的soc-empty例程里面包含了一个AppLoader,可以用OTA_DFU(Over The Air -Device Firmware Upgrade)的方式升级应用程序。但是这个方式需要主机端(手机APP)也按照Silabs定义的OTA profile(包括服务和特性的UUID,以及升级过程中的主从设备之间的交互流程)来做。
实际应用中,通常需要按照生态系统(如腾讯连连)定义的OTA协议来对设备的软件进行升级,因此需要使用Gecko Bootloader配合应用程序来实现。Gecko Bootloader有standalone和application两种模式,这里要用后者,升级的流程如下图:
主机端仍可使用AN1086所述的方法:
- 把一块开发板连接到电脑,给它烧写Bluetooth SDK中的例程NCP–Empty Target。
- 在电脑上安装MinGW开发工具,然后在命令行窗口cd到目录SimplicityStudio\v4\developer\sdks\gecko_sdk_suite\<version>\app\bluetooth\examples_ncp_host\ota_dfu 中,执行mingw32-make,就可以编译出ota-dfu.exe可执行文件。
设备端使用另一块开发板,需要制作BootLoader和应用程序两个工程:
- 创建BootLoader工程时,使用Gecko Bootloader的Internal Storage Bootloader(single image on 512kB device)例程,完全按缺省配置Generate代码就可以了。编译后用“Debug”或“Flash Programmer”把它烧写到开发板中。
- 使用Bluetooth SDK里的soc-empty例程创建应用程序,
- 把SimplicityStudio\v4\developer\sdks\gecko_sdk_suite\v2.4\platform\bootloader\api文件夹中的所有文件复制到工程目录下的\platform\bootloader\api文件夹里;
- 在工程目录下新建\platform\bootloader\core文件夹,并把SimplicityStudio\v4\developer\sdks\gecko_sdk_suite\v2.4\platform\bootloader\core\btl_util.h复制到里面。
- 在应用程序的工程设置中,把apploader从链接的目标中删掉,如下面一行:
${workspace_loc:/${ProjName}/protocol/bluetooth/lib/EFR32MG13P/GCC/binapploader.o}
设置完了如下图:
- 修改main.c文件,如下:
#define OTA_DEMO 1
#if OTA_DEMO
#include "btl_interface.h"
#include "btl_interface_storage.h"
int ota_image_position, ota_in_progress, ota_image_finished;
uint32_t connection, characteristic;
BootloaderStorageSlot_t slot;
uint32_t flash_page_erased;
#else
// Flag for indicating DFU Reset must be performed
uint8_t boot_to_dfu = 0;
#endif
在主循环中:
case gecko_evt_le_connection_closed_id:
#if OTA_DEMO
if(ota_image_finished)
{
bootloader_setImageToBootload(0);
bootloader_rebootAndInstall();
}
#else
/* Check if need to boot to dfu mode */
if (boot_to_dfu) {
/* Enter to DFU OTA mode */
gecko_cmd_system_reset(2);
} else {
/* Restart advertising after client has disconnected */
gecko_cmd_le_gap_start_advertising(0, le_gap_general_discoverable, le_gap_connectable_scannable);
}
#endif
break;
case gecko_evt_gatt_server_user_write_request_id:
#if OTA_DEMO
/*OTA support*/
connection = evt->data.evt_gatt_server_user_write_request.connection;
characteristic = evt->data.evt_gatt_server_user_write_request.characteristic;
if (characteristic == gattdb_ota_control)
{
switch (evt->data.evt_gatt_server_user_write_request.value.data[0])
{
case 0://Erase and use slot 0
bootloader_init();
//bootloader_eraseStorageSlot(0);
bootloader_getStorageSlotInfo(0, &slot);
bootloader_eraseRawStorage(slot.address, FLASH_PAGE_SIZE);
flash_page_erased = slot.address;
ota_image_position = 0;
ota_in_progress = 1;
break;
case 3://END OTA process
//wait for connection close and then reboot
ota_in_progress = 0;
ota_image_finished = 1;
break;
default:
UARTDRV_Transmit(handle, "unknown OTA command\n", 20, callback);
break;
}
} else if (characteristic == gattdb_ota_data)
{
if(ota_in_progress)
{
bootloader_writeStorage(0,//use slot 0
ota_image_position,
evt->data .evt_gatt_server_user_write_request.value.data,
evt->data.evt_gatt_server_user_write_request.value.len);
ota_image_position += evt->data.evt_gatt_server_user_write_request.value.len;
if((slot.address + ota_image_position) > flash_page_erased)
{
flash_page_erased += FLASH_PAGE_SIZE;
if(flash_page_erased < (slot.address + slot.length))
bootloader_eraseRawStorage(flash_page_erased, FLASH_PAGE_SIZE);
}
}
} else
{
UARTDRV_Transmit(handle, "unknown characteristic\n", 23, callback);
}
gecko_cmd_gatt_server_send_user_write_response(connection, characteristic, 0);
#else
if (evt->data.evt_gatt_server_user_write_request.characteristic == gattdb_ota_control) {
/* Set flag to enter to OTA mode */
boot_to_dfu = 1;
/* Send response to Write Request */
gecko_cmd_gatt_server_send_user_write_response(
evt->data.evt_gatt_server_user_write_request.connection,
gattdb_ota_control,
bg_err_success);
/* Close connection to enter to DFU OTA mode */
gecko_cmd_le_connection_close(evt->data.evt_gatt_server_user_write_request.connection);
}
#endif
break;
- 在GATT配置器中添加Silicon Labs OTA Data特性,并把它设置为可变长度和可写,如下图:
记得点“Generate”生成代码,然后编译并用“Debug”或“Flash Programmer”把它烧写到开发板中。至此,设备端的初始软件就准备好了。
测试OTA升级软件功能:
- 稍微修改应用程序,如把串口打印的“BLE OTA APP V1”改为“BLE OTA APP V2”,重新编译生成目标文件。
- 然后,执行工程目录里的create_bl_files.bat脚本,它会在工程目录里创建output_gbl\application.gbl文件。
- 把前面做好的ota-dfu.exe文件复制到output_gbl文件夹里,在命令行窗口执行它(COM8是主机端开发板的JLINK CDC UART串口,波特率必须用115200,00:0B:57:93:31:A2是设备端的蓝牙MAC地址),结果如下:
PS E:\Temp\workspace\soc-empty_uart_test\output_gbl> .\ota-dfu.exe COM8 115200 .\application.gbl 00:0B:57:93:31:A2
System rebooted
Local address:00:0b:57:31:5a:e1
Bytes to send:141588
Scanning...OK
Device address found, connecting.
Connecting...OK
Discovering services...ATT MTU exchanged: 247
OK
Discovering characteristics...OK
Control handle:19
Data handle:21
OTA Data characteristic properties:0x0c
DFU mode...OK
OTA DFU - write with response
100% 39.06kbit/s
time: 29.00s
Finishing DFU block...OK
Closing connection...OK