OTA设计思路概述
华大H32F460和HC32F448系列单片机支持通过无线网络(如Wi-Fi、BLE)或有线接口(如UART、USB)进行固件升级。OTA设计需考虑固件分区、校验机制、安全性和回滚策略。
固件分区设计
将Flash划分为多个区域:Bootloader区、应用程序区、备份区、参数存储区。Bootloader负责验证固件合法性并执行跳转。应用程序区运行当前固件,备份区存储新固件。参数存储区保存版本号、CRC校验值等元数据,这个分区可以根据自己的需求自己定义(注意:分区的起始位置一定要按照扇区的大小定义,分区的起始位置一定是某个扇区号的起始位置)
按照华大HC32F448举例,F448的flash容量高达256KB,每个扇区为8KB,Bootloader区的起始位置肯定是0,APP区的位置是根据Bootloader的大小定义,Bootloader区的大小一定是8KB(F448扇区大小)的倍数,这样是根据flash特性决定的,方便擦除和写入。
安全机制
本文提供两种思路,
(1)使用AES-128或SHA-256对固件加密/签名。Bootloader验证签名合法性后才允许升级。防止未经授权的固件写入。启用Flash写保护功能,避免运行时意外修改关键区域,这个是一种思路,但是加密算法对于单片机性能要求高。影响运行速度。
// SHA-256验证示例
bool verify_firmware(uint8_t *data, uint32_t len, uint8_t *signature) {
uint8_t hash[32];
sha256_calculate(data, len, hash);
return memcmp(hash, signature, 32) == 0;
}
(2)第二种方法比较简单,也是我经常用的办法,一般OTA升级,或者各种方式的升级都是将APP区代码编译成bin文件,完成的。我们可以直接在APP区的启动文件(也就是.s文件),写入一段标志码,每次升级的时候,在bootloader中对此校验码进行读取,看看是不是有效的bin文件,再进行升级跳转。
具体操作步骤(以华大HC32F448为例)
打开.s文件

一般启动文件开头都会预留几个位置,我们在这个位置写入我们的校验码即可。

我们在预留区随便写入校验码

这样我们每次升级的时候检验这个校验码就可以了。
程序下载
BOOTLOADER下载
bootloder下载和正常区用keil工具下载流程一样
APP下载
APP区程序下载要根据起始位置设置(这里还是根据HC32F448举例),如我这里将我的APP区的起始位置设置为0x8000,需要将VECT_TAB_OFFSET这个宏定义设置成0x8000,其中默认是0,
它表示中断向量表在内存中的起始地址可以动态调整,默认值是0(从Flash首地址开始),但可以通过设置偏移量将向量表放到其他位置。
/* Vector Table base offset field */
#ifndef VECT_TAB_OFFSET
#define VECT_TAB_OFFSET (0x8000UL) /*!< This value must be a multiple of 0x400. */
接下来更改,SCT文件。点击这个按钮。

然后再点击Linker按钮,取消掉Use Memory Layout from Target Dialog 这个对勾(不然SCAtter file这一项会是灰色),然后再点击Edit。

将这两项改成0x8000就可以了


这样用keil调试下载软件的时候每次下载APP都会默认下载到0x8000这个位置
BIN文件生成
点击这个按钮。

点击User这个选项卡,在After build/Rebuild这里填入fromelf –bin -o “$L@L.bin” “#L”这个字段,并将Run#1这个对勾勾上

对fromelf –bin -o “$L@L.bin” “#L”这一段的解释
fromelf 是Keil提供的工具,用于转换/提取ELF格式文件(.axf)
–bin 指定输出格式为**原始二进制文件**
`-o “$L@L.bin”` 输出文件名(Keil宏替换)
`”#L”` 输入文件(Keil宏替换,即链接生成的.axf文件)
按照这样设置后点击编译,即可生成BIN文件,我么打开生成的BIN文件

这个位置正好对应起来我们刚才写入在启动文件里面的0xFCCF1123,方便我们在BOOT文件里面做校验。
升级流程
设备接收到升级指令后进入Bootloader模式。下载新固件至备份区,校验通过后擦除应用程序区并复制数据。更新参数存储区的版本信息,重启后从新固件启动。若升级失败,自动回滚至旧版本。这里我们可以将APP分别存在两个区域,存储两个版本的APP,如果新版本没有更新成功,(可以在APP区放入一段擦除标志位的程序,运行成功擦除标志位,在BOOT区判断标志位是否擦除,来判断是否返回上个版本,及升级失败)
回滚策略
在参数存储区保存当前固件状态标记(如0x55表示成功,0xAA表示失败)。Bootloader检测到失败标记时,从备份区恢复旧固件。双重备份机制可提高可靠性。
// 回滚判断逻辑
if (*(uint8_t*)0x00160000 == 0xAA) {
restore_firmware();
}
跳转APP代码
此代码,我是参考华大的官方例程。其中u32Addr这个参数就是我们要跳转的地址(估计上面例子可以为0x8000),可以在此函数基础上再加上我们说的安全机制校验,判断是否是合法的BIn文件。
int32_t IAP_JumpToApp(uint32_t u32Addr)
{
uint32_t u32StackTop = *((__IO uint32_t *)u32Addr);
/* Check stack top pointer. */
if ((u32StackTop > SRAM_BASE) && (u32StackTop <= (SRAM_BASE + SRAM_SIZE))) {
IAP_PeriphDeinit();
/* Jump to user application */
JumpAddr = *(__IO uint32_t *)(u32Addr + 4U);
JumpToApp = (func_ptr_t)JumpAddr;
/* Initialize user application's Stack Pointer */
__set_MSP(u32StackTop);
JumpToApp();
}
return LL_ERR;
}
调试与测试
通过串口日志输出OTA过程状态。使用硬件看门狗防止死机。测试断电恢复、数据包丢失等异常场景,确保升级过程鲁棒性。
至此升级流程完成,有什么不足或者不对的地方欢迎大家指出,希望大家多交流,一起进步。















暂无评论内容