在上文ch5xx 固定库更改地址实现方式讲解了不同起始地址的固定库的配置方法,本文将以 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 区域的代码均可直接使用原例程,仅需对 Peripheral 工程进行如下六个步骤的修改。

二、配置步骤详解(共六步)

整个配置过程分为以下六个步骤。为保持配置一致性,必须直接先复制粘贴 OnlyUpdateApp_Peripheral 例程中的 Link.ld 和 Startup.s 文件,然后再根据当前工程需求进行以下修改:

步骤1:修改链接脚本文件(Link.ld)

Link.ld 文件定义了各个存储区域的起始地址与占用空间。使用固定库时协议栈被放置于Flash的高地址区域,因此需要相应调整应用程序(APP)区域的起始地址与占用空间。

以起始地址为 0x00010000 的 CH59xBLE_ROM.hex 为例,修改后的 MEMORY 配置如下:

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)在使用固定库时需要配置跳转目标地址,使其跳转至固定库所在的起始地址。修改汇编跳转指令如下:

    la t0, main
    csrw mepc, t0

    j 0x10000          /* 跳转至协议栈基址,与所选ROM版本一致 */

步骤3:添加固定库使能宏定义

在工程的预处理宏定义中,需添加 CH59xBLE_ROM=1,用于启用 ROM 固定库。该宏会引导 CONFIG.h 头文件包含 CH59xBLE_ROM.h(而非 CH59xBLE_LIB.h ),从而调用固化的协议栈 API 。

工程中所有包含协议栈头文件的地方,严禁直接包含 CH59xBLE_LIB.h ,必须统一采用如下条件编译写法:

#ifdef CH59xBLE_ROM
#include "CH59xBLE_ROM.h"
#else
#include "CH59xBLE_LIB.h"
#endif

步骤4:添加固定库地址宏定义

程序中需要添加固定库对应地址的宏定义,使编译系统明确协议栈固件在 Flash 中的具体位置。在预处理宏中添加:

LIB_FLASH_BASE_ADDRESSS=0x00010000

步骤5:添加OTA文件标志

为使手机APP能识别有效的升级固件,需在应用程序中嵌入一个固定的标志位。该标志将被放置在独立的段(section)中,供上位机 APP 程序读取判断。在代码中添加如下定义:

/* 用于IAP校验文件有效性的标志 */
const uint32_t Address = 0xFFFFFFFF;
__attribute__((aligned(4))) uint32_t Image_Flag __attribute__((section(".ImageFlag"))) = (uint32_t)&Address;

步骤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();
}

三、编译结果与验证

完成以上六步修改后,使用 WCHISPTOOL 将 Jump IAPIAP、Peripheral 以及 ROM 一并烧录至 CH592F 芯片。通过手机 APP 连接设备,向特性 SIMPLEPROFILE_CHAR3 写入特定值,即可触发OTA流程,观察串口打印可确认跳转成功,跳转成功后使用 OTA APP 连接进行升级。

 

posted on 2026-07-22 14:46  WCH蓝牙应用分享  阅读(70)  评论(0)    收藏  举报