开发环境
- windows
- simplicity studio 5
- geck sdk 4.1
一 bootloader
新建BGAPI UART DFU工程
- 工程新建完成以后看一下linkerfile.ld文件的flash和ram的配置跟自己的application工程是否对应得上
- 配置串口波特率和引脚
- 默认使用PB0进入bootloader模式,这里改成None
二 准备bt_host_uart_dfu.exe
geck sdk里面提供了bt_host_uart_dfu.exe的源码,但是需要自己编译。windows环境需要使用MinGW工具,linux使用make指令直接就可以编译出可执行文件。
2.1 安装MinGW
下载地址: https://sourceforge.net/projects/mingw-w64/files/
MinGW-W64-install.exe是在线安装,经常会提示错误,在这里建议直接下载x86_64-win32-seh。
下载完之后直接解压出来即可。
将bin的路径设置到环境变量Path中
在cmd界面中执行gcc -v,显示版本号说明安装成功。
2.2 编译
bt_host_uart_dfu的源码在gecko_sdk\app\bluetooth\example_host\bt_host_uart_dfu目录下
在该目录下使用shell power执行命令 mingw32-make 生成exe
不出意外在exe目录下生成了一个bt_host_uart_dfu.exe
下载MinGW有困难的可以直接下载这个 bt_host_uart_dfu.exe
三 升级
升级的过程如下图:
- 固件(APP)收到 bt_host_uart_dfu.exe 发过来的升级指令:20 00 FF 02,固件收到改指令以后重启并进入bootloader模式
- bootloader接收 bt_host_uart_dfu.exe 发送过来的新固件。
- bootloader将新固件直接写到APP区域
全部写完以后直接启动APP,在升级过程中如果被中断了,那么设备将一直处于bootloader模式。
首先,当前固件需要能够接收串口发送过来的数据。
将bt_host_uart_dfu.exe 和 application.gbl放在同一个文件夹里面,在该文件夹下打开power shell执行如下指令
.\bt_host_uart_dfu.exe -u COM14 -f -l 4 -b 115200 .\application.gbl
- -u指定串口号
- -f 表示禁止使用流控
- -l 4 指定log日志级别
- -b 指定波特率
特别注意:bt_host_uart_dfu.exe默认是开启流控的,如果你的bootloader没有开启流控,一定要加上-f参数,否者你会看到数据发出来了但是对方却怎么也收不到
bt_host_uart_dfu.exe 执行的最初会发送指令20 00 FF 02,固件收到这个数据之后就进入bootloader模式。
#define BOOTLOADER_RESET_REASON_BOOTLOAD 0x0202u
#define BOOTLOADER_RESET_SIGNATURE_VALID 0xF00Fu
#define SRAM_BASE (0x20000000UL)
void bootloader_mode(void)
{
BootloaderResetCause_t *cause = (BootloaderResetCause_t *) (SRAM_BASE);
cause->reason = BOOTLOADER_RESET_REASON_BOOTLOAD;
cause->signature = BOOTLOADER_RESET_SIGNATURE_VALID;
CHIP_Reset();
}
之后不出意外就可以升级成功了。
四 改进bootloader
BGAPI默认是单区更新的,也就是bootloader会把收到的新固件直接覆盖掉原来的固件。如果在升级的过程中被中断了,那么设备将一直处于bootloader模式。
4.1 升级过程描述
通过下面几步操作可以实现双区更新,并且升级过程被中断还可以启动老的固件。
- 固件(APP)收到 bt_host_uart_dfu.exe 发过来的升级指令:20 00 FF 02,固件收到改指令以后重启并进入bootloader模式
- bootloader接收 bt_host_uart_dfu.exe 发送过来的新固件。
- bootloader将新固件写到APP_bak区域。
一直重复步骤2和3直到所有固件都接收完成
- 新固件验证完成以后,bootloader将APP_bak区域的新固件搬运到APP区域,并启动新的APP
4.2 代码修改
- 修改btl_bootloader.c的flashData函数
static void flashData(uint32_t address,
uint8_t data[],
size_t length)
{
const uint32_t pageSize = (uint32_t)FLASH_PAGE_SIZE;
address += 360448;
if (address % pageSize == 0UL) {
flash_erasePage(address);
}
for (uint32_t pageAddress = (address + pageSize) & ~(pageSize - 1UL);
pageAddress < (address + length);
pageAddress += pageSize) {
flash_erasePage(pageAddress);
}
flash_writeBuffer_dma(address, data, length, SL_GBL_MSC_LDMA_CHANNEL);
}
- 修改btl_bootloader.c的bootload_applicationCallback函数
#define PACK_LEN 1024
static void install_application(uint32_t length)
{
const uint32_t pageSize = (uint32_t)FLASH_PAGE_SIZE;
uint32_t bak_address = 0x5C000;
uint32_t write_address = 0x4000;
uint8_t buffer[PACK_LEN];
uint16_t seg = length / PACK_LEN;
if(length % PACK_LEN){
seg += 1;
}
LOGD("seg: %d\n", seg);
for(int i = 0; i < seg; i++){
LOGD("write_address: %08x\n", write_address);
if(write_address % pageSize == 0){
flash_erasePage(write_address);
}
memset(buffer, 0, PACK_LEN);
memcpy(buffer, (uint32_t *)(bak_address + i * PACK_LEN), PACK_LEN);
flash_writeBuffer(write_address, buffer, PACK_LEN);
write_address += PACK_LEN;
}
}
void bootload_applicationCallback(uint32_t address,
uint8_t data[],
size_t length,
void *context)
{
static uint32_t app_length = 0;
(void)context;
if(length == 0xA5A5A5A5){
LOGD("all length: %d\n", app_length);
install_application(app_length);
app_length = 0;
return;
}
if ((address < (uint32_t)(mainBootloaderTable->startOfAppSpace))
|| ((address + length)
> (uint32_t)(mainBootloaderTable->endOfAppSpace))) {
BTL_DEBUG_PRINT("OOB 0x");
BTL_DEBUG_PRINT_WORD_HEX(address);
BTL_DEBUG_PRINT_LF();
return;
}
app_length += length;
flashData(address, data, length);
}
- 修改btl_comm_bgapi_common.c的bootloader_bgapi_communication_main函数
当收到更新完成指令后调用applicationCallback回调并传入len = 0xA5A5A5A5
else if (command.header.class == BGAPI_PACKET_CLASS_SYSTEM) {
switch (command.header.command) {
case SYSTEM_RESET:
LOGD("Reset request\n");
parseCb->applicationCallback(0, NULL, 0xA5A5A5A5, NULL);
break;
完成以上步骤之后,bootloader就实现了双区更新的功能。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)