【WCH蓝牙系列芯片】-基于CH584开发板—串口IAP升级说明和移植过程

------------------------------------------------------------------------------------------------------------------------------------ 

  在CH585例程中,包含有线升级的IAP例程,其中UART_IAP可以配合APP进行串口更新片上程序。在CH584芯片中实际就烧录两个程序一个是IAP和APP的HEX固件。

  IAP 程序(Bootloader):通常存放在 Flash 的最起始位置(地址 0x00000000),体积非常小(例程是4KB)。它是用来接收新固件、擦写 Flash,并引导启动。

  APP 程序(用户程序):存放在 IAP 之后的空间(如地址 0x00001000 开始)。放在IAP的4K后面,它负责执行用户的程序逻辑功能。

一、UART_IAP程序

  在UART_IAP程序中,先看一下LD文件中FLASH起始地址,IAP的起始地址是从0x00000000开始的,设置大小为16K给IAP使用。

image

  整个 IAP 程序的运行过程可以分为三大阶段:启动与分流判定串口数据轮询与协议解析Flash擦写与程序跳转

  当芯片上电复位后,首先运行的是位于地址 0x00000000 的 IAP 程序。在main() 函数中决定:是留在 IAP 等待串口发来新固件,还是直接跳去执行旧的 APP 业务代码;在主循环中有两个方式进行判断是否升级固件操作

第一阶段:启动与分流判定

  方式一:读取 DataFlash 中的标志位,如果读出的标志不是 0x55 (代表要求升级),则说明是正常开机,执行jumpApp()函数,直接跳转到 APP 地址执行。

image

  方式二:检测外部硬件引脚电平状态,这个程序中,将 PB4 配置为升级按键, 如果PB4状态是高电平则不进入升级过程,正常跳转到APP里面,执行用户程序,如果PB4是低电平状态,那就会进入升级过程。

image

  如果程序运行到这个位置,说明触发UART_IAP升级操作,决定留在 IAP 模式,对串口1(PA8\PA9)进行初始化操作,打开FIFO。串口初始化完毕调用Main_Circulation(); 进入 IAP 核心死循环,开始接收上位机发来的数据包并执行升级动作。

image

第二阶段:数据轮询与协议解析

  进入 Main_Circulation() 后,程序进入死循环。 函数带有 __attribute__((section(".highcode"))) 修饰符,将这段代码会被加载到 RAM 中运行。通过无中断的纯轮询方式,接收串口下发的固件数据包;利用一个状态机解析协议;最后将解析出的固件数据安全、高效地烧写到 Flash 中。

1、通过串口轮询的方式接收数据,在串口通信极易受干扰丢包,利用超时防死锁判断;如果使用串口中断,进出中断需要压栈出栈,且需要中断向量表,这会占用极大的 Flash 空间,为了不占用FLASH空间,采用串口轮询接收数据。

image

  在超时机制中包含有短超时和长超时,短超时(防烂包死锁)如果收到一半的数据突然断了,程序里的 g_tcnt 会在没有数据时不断累加。当超过 43 次循环(约 1毫秒,等同于 10 个字节的时间)没收到新数据,就会判定这包数据废了,直接丢弃并复位状态机,向主机报错。

长超时(防开机卡死)如果用户误入了 IAP 模式,但长达 120 秒 (g_tcnt > 6000000) 都没有上位机发数据过来,程序会认为“不需要升级了”,自动调用 jumpApp() 跳回正常APP程序中。

image

2、串口接收数据,通过协议包格式为:[包头AA] [包头55] [命令CMD] [长度LEN] [地址4字节] [数据载荷] [校验和2字节] [包尾55] [包尾AA]取出一包完整的数据。

image

第三阶段:Flash擦写与程序跳转

3、当成功接收到一包数据(IAP_DATA_REC_STATE_OK),就会根据命令字 CMD 执行擦除烧录动作

image

image

image

  上位机必须先发擦除命令 (CMD_IAP_ERASE),擦除成功后,代码将 g_update_permition 置为 1。如果没有这一步,后面的写入命令统统拒接,这是防误写保护。上位机每次下发是 Flash 按页写入(256 字节)。 所以,程序设立了 g_write_buf[256 + 64] 缓存。每次收到数据先塞进缓存(my_memcpy),等 g_buf_write_ptr >= 256 满了一页,才调用底层的 FLASH_ROM_WRITE 一次性刷入 Flash 中。剩下的结尾的数据则被挪到下一次拼装。

4、写完数据之后,执行校验命令CMD_IAP_VERIFY,如果检验失败就直接报错。

image

5、升级结束,跳转到APP程序中,执行新固件的APP程序

image

在IAP程序中,还包含APP的起始地址和结束地址。还有标志位定义的数据,如果后续要修改空间大小就得修改这部分地址参数

image

二、APP程序

  在APP程序中,可以先看一下LD文件里面FLASH的起始位置是16K位置(0x00004000),FLASH的大小给432K,直接把APP固件放在IAP固件的后面放置。

image


int main()
{
    uint16_t i = 0;
    uint8_t  s = 0;

    HSECFG_Capacitance(HSECap_18p);
    SetSysClock(SYSCLK_FREQ);
    /* 配置串口调试 */
    DebugInit();
    PRINT("Start @ChipID=%02x\n", R8_CHIP_ID);
    printf(" Build Date: %s\r\n", __DATE__); //打印编译时的日期
    printf(" Build Time: %s\r\n", __TIME__); //打印编译时的时间

    /* app程序必须执行该语句,保证app更新失败时,下次依然运行IAP */
    // 这里的 FLAG_USER_CALL_APP 通常是 0xAA。
    // 这样做的目的是防止 IAP 升级失败后死机,只要成功跑进 APP,
    // 就 APP是好的,下次断电重启,IAP 读取到 0xAA 就会直接跳回 APP。
    SwitchImageFlag(FLAG_USER_CALL_APP);      // 把 DataFlash 里的升级标志位清除。

    GPIOB_ModeCfg(GPIO_Pin_4, GPIO_ModeIN_PU);    //配置按键引脚(PB4 为升级触发引脚)
    while (1)
    {
        PRINT("i:%d\n",i);
        i++;
        DelayMs(10);
        if (GPIOB_ReadPortPin(GPIO_Pin_4) == 0)  // 检测到低电平(按键按下) 触发升级
        {
            s++;
            //连续两次检测到按键按下(软件消抖逻辑),跳转到IAP
            if(s >= 2)
            {
                jumpToIap();  // 触发跳转
            }
        }
        else
        {
            s = 0;
        }
        DelayMs(100);
    }
}

  在APP的主函数程序里面,先执行 SwitchImageFlag(FLAG_USER_CALL_APP); 这段程序。APP 和 IAP 是两个独立的程序,它们约定了一个掉电不丢失的区域(DataFlash 的 0 地址)作为标志位判断。

image

  这里写入的是 FLAG_USER_CALL_APP设置为0xAA,只要代码能成功跑到 main 函数这里,说明刚才 IAP 刷入的这个新 APP 是好用的、没跑飞的。就把DataFlash 里的升级标志(0x55)擦掉,换成正常启动标志(0xAA)。这样下次断电重启时,IAP 读取到 0xAA,就会直接放行跳回 APP,不再死等串口了。这里使用 0x55 (01010101) 和 0xAA (10101010) 的二进制位是交替的, 这样在 Flash 中极难因为单比特翻转发生误判,是最安全的标志位选择。

image

  在APP主函数中判断完跳转的标志位之后,配置升级触发条件,这里使用PB4作为按键触发功能,然后进入主循环中,一直打印 i++数值;如果 检测到 PB4 被拉低之后,就会触发跳转jumpToIap(); 改写标志位为 0x55 并软复位单片机,芯片内部硬件会自动将 PC 指针指回 0x00000000,从IAP程序的起始位置开始运行。如果没有检测到PB4拉低,就会一直i++数值打印。

image

IAP+APP程序运行大体流程:

image

三、BLE程序移植UART_IAP的功能

1、将APP例程里面的app_flah.c和app_flah.h复制到蓝牙从机Peripheral工程中。

image

2、修改LD文件,将FLASH的起始地址改为0x00004000(16k),FLASH大小设置为432K.

image

3、修改启动文件,将原本这里的 0x88修改为0x1888,改为机器模式

image

4、在蓝牙程序中,添加dataflash的标志位判断程序,和触发条件的的按键初始化。

SwitchImageFlag(FLAG_USER_CALL_APP); // 把 DataFlash 里的升级标志位清除。 GPIOB_ModeCfg(GPIO_Pin_4, GPIO_ModeIN_PU); //配置按键引脚(PB4 为升级触发引脚)

然后再主循环中加入是否跳转的判断——jumpToIap();

image

image

5、配合PC端的上位机工具,进行串口IAP的升级,进行验证测试

image

image

image

image

 

 

 

 

posted on 2026-05-25 09:12  凡仕  阅读(24)  评论(0)    收藏  举报