CH592 Peripheral例程OTA实战:基于固定协议栈的配置与实现
在上文讲解了固定协议栈不同起始地址的配置方法后,本文将以 Peripheral 从机例程为基础,进行 带OTA升级功能 的实战改造。
一、Flash地址规划
为实现OTA,需将Flash划分为四个独立区域,各区域起始地址与大小如下表所示:
| 区域 | 起始地址 | 大小 | 说明 |
|---|---|---|---|
| Jump IAP | 0x00000000 | 4 KB | 启动跳转程序,负责判断是否进入IAP |
| Peripheral APP | 0x00001000 | 44 KB | 应用程序主体(从4KB开始) |
| IAP | 0x0000C000 | 16 KB | 升级管理程序(48KB~64KB) |
| 协议栈(ROM) | 0x00010000 | 192 KB | 固定协议栈(64KB~256KB) |
说明:
Jump IAP、IAP以及ROM区域的代码均可直接沿用原例程(如OnlyUpdateApp_Peripheral中的相关文件),仅需对Peripheral工程进行如下六个步骤的修改。
二、修改步骤(共六步)
以下配置均基于 CH59xBLE_ROM.hex(起始地址 0x00010000)进行。为保持一致性,建议直接参考并移植 OnlyUpdateApp_Peripheral 例程中的相关文件,再按需调整。
步骤1:修改链接脚本(Link.ld)
链接脚本(.ld)定义了各存储区域的基址与长度。根据地址规划,将APP区域起始地址设为 0x00001000,长度设为 44KB;同时调整RAM起始地址,为协议栈保留前8KB空间。
MEMORY
{
FLASH (rx) : ORIGIN = 0x00001000, LENGTH = 44K /* APP从4KB开始,可用44KB */
RAM (xrw) : ORIGIN = 0x20002000, LENGTH = 18K /* 0x20000000~0x20002000预留给协议栈 */
}
注意:此处
LENGTH = 44K即对应地址范围0x00001000 ~ 0x0000BFFF(4KB ~ 48KB),与JUMP IAP区域(0KB-4KB)IAP区域(48KB~64KB)无缝衔接。
步骤2:修改启动文件(Startup.s)
启动文件(startup_CH592.S)负责复位后的初始跳转。固定库模式下,需将程序指针跳转至协议栈固件的起始地址 0x00010000。
修改汇编代码中的跳转指令:
la t0, main
csrw mepc, t0
j 0x10000 /* 跳转至协议栈基址,与所选ROM版本一致 */
步骤3:添加协议栈使能宏
在工程的预处理宏定义中添加 CH59xBLE_ROM=1,告知编译器使用固化协议栈接口(CH59xBLE_ROM.h),而非源码库。
同时,所有包含协议栈头文件的地方必须采用条件编译形式,严禁直接包含 CH59xBLE_LIB.h:
#ifdef CH59xBLE_ROM
#include "CH59xBLE_ROM.h"
#else
#include "CH59xBLE_LIB.h"
#endif
步骤4:添加固定库地址宏
为配合链接脚本中的协议栈起始地址,需定义宏 LIB_FLASH_BASE_ADDRESS,其值须与启动文件跳转地址及ROM文件实际起始地址严格一致。
在预处理宏中添加:
LIB_FLASH_BASE_ADDRESS=0x00010000
步骤5:添加OTA标志,用于手机APP校验升级文件有效性
为使手机APP能识别有效的升级固件,需在应用程序中嵌入一个固定的标志位。该标志将被放置在独立的段(section)中,供IAP程序读取判断。
在代码中添加如下定义:
/* 用于IAP校验文件有效性的标志 */
const uint32_t Address = 0xFFFFFFFF;
__attribute__((aligned(4))) uint32_t Image_Flag __attribute__((section(".ImageFlag"))) = (uint32_t)&Address;
说明:
Image_Flag的值固定为&Address(即0xFFFFFFFF的地址),实际值可根据需要调整。该段需在链接脚本中显式放置,确保位于APP固件的固定偏移处。
步骤6:添加触发OTA跳转的逻辑
通过蓝牙特性写入触发OTA升级。本例利用 SIMPLEPROFILE_CHAR3 特性接收特定指令,调用 Jump_OTA() 函数设置升级标志并执行软复位。
首先,在特性回调函数中添加跳转处理:
static void simpleProfileChangeCB(uint8_t paramID, uint8_t *pValue, uint16_t len)
{
switch(paramID)
{
case SIMPLEPROFILE_CHAR1:
{
uint8_t newValue[SIMPLEPROFILE_CHAR1_LEN];
tmos_memcpy(newValue, pValue, len);
PRINT("profile ChangeCB CHAR1.. \n");
break;
}
case SIMPLEPROFILE_CHAR3:
{
uint8_t newValue[SIMPLEPROFILE_CHAR3_LEN];
tmos_memcpy(newValue, pValue, len);
PRINT("profile ChangeCB CHAR3..\n");
PRINT("jump OTA \n");
mDelaymS(5);
Jump_OTA(); /* 触发OTA跳转 */
break;
}
default:
break;
}
}
其次,实现 Jump_OTA() 函数,该函数在DataFlash中写入OTA标志,然后复位芯片,使Jump IAP程序判断该标志并引导至IAP升级流程。
/* OTA升级标志值 */
#define IMAGE_OTA_FLAG 0x03
/* DataFlash存储地址(需避开蓝牙协议栈使用的区域) */
#define OTA_DATAFLASH_ADD 0x00076000 - FLASH_ROM_MAX_SIZE
/* DataFlash临时缓冲区 */
__attribute__((aligned(8))) uint8_t block_buf[16];
/*********************************************************************
* @fn Jump_OTA
*
* @brief 设置OTA标志并软复位,跳转至IAP
*
* @return none
*/
void Jump_OTA(void)
{
uint16_t i;
uint32_t ver_flag;
/* 读取第一块DataFlash原有数据 */
EEPROM_READ(OTA_DATAFLASH_ADD, (uint32_t *)&block_buf[0], 4);
/* 擦除第一块DataFlash */
EEPROM_ERASE(OTA_DATAFLASH_ADD, EEPROM_PAGE_SIZE);
/* 更新Image信息,写入OTA标志 */
block_buf[0] = IMAGE_OTA_FLAG;
/* 编程DataFlash */
EEPROM_WRITE(OTA_DATAFLASH_ADD, (uint32_t *)&block_buf[0], 4);
/* 执行软复位,Jump IAP将根据标志决定是否进入IAP */
SYS_ResetExecute();
}
注意:
OTA_DATAFLASH_ADD的计算基于FLASH_ROM_MAX_SIZE(通常为芯片总Flash容量),此处确保地址位于安全区域,不要与其他数据区域冲突。
三、编译结果与验证
完成以上六步修改后,使用ISP工具将 Jump IAP、IAP 以及 APP 固件(连同协议栈ROM文件)一并烧录至CH592F芯片。通过手机APP连接设备,向特性 SIMPLEPROFILE_CHAR3 写入特定值,即可触发OTA流程,观察串口打印可确认跳转成功。
浙公网安备 33010602011771号