2.10. 双备份升级介绍
杰理双备份升级(Dual-Bank Update),核心是使能双备份功能、工具生成正确格式固件、通过自定义OTA接收并写入备用分区、校验成功后切换启动。全程不影响当前运行、升级失败可回退
2.10.1. 原理(快速理解)
2.10.2. 升级流程
2.10.3. 开发端:启用双备份(SDK 配置)
使能双备份升级,ini文件会自动配置输出 db_update_data.bin,该文件即为需要升级的文件升级流程可参考 dual_bank_demo.c 文件
#define TCFG_DUAL_BANK_ENABLE ENABLE_THIS_MOUDLE //双备份升级使能
2.10.4. 升级相关的API介绍
2.10.4.1. dual_bank_passive_update_init
函数原型:
u32 dual_bank_passive_update_init(u32 fw_crc, u32 fw_size, u16 max_pkt_len, void *priv);
功能说明:升级初始化,并设置新固件的CRC校验值和文件总大小;
参数说明:
参数
说明
fw_crc
新固件文件的CRC校验值(用于升级完成后校验固件完整性) - 可传0
fw_size
新固件文件的总大小(字节数)
max_pkt_len
单次烧写支持的最大数据包长度,决定每次烧写的最大数据量,最大256byte
priv
保留,直接传 NULL
- 返回值:
返回值
说明
0
成功
非0
失败
示例:
1u16 code_crc = 0x55aa;//升级文件CRC,通过对db_update_data.bin获取到(与上位机通信得到) 2u32 code_len = 0x8000;//升级文件大小,通过计算db_update_data.bin的长度得到(与上位机通信得到) 3u32 ret = dual_bank_passive_update_init(code_crc, code_len, 256, NULL);
2.10.4.2. dual_bank_update_allow_check
函数原型:
u32 dual_bank_update_allow_check(u32 fw_size);
功能说明:判断Flash是否有足够空间存放新固件文件;
参数说明:
参数
说明
fw_size
新固件文件的大小(字节数)
- 返回值:
返回值
说明
0
正确:空间足够,可以升级
非0
错误:空间不足,无法升级
note: 必须在调用 dual_bank_passive_update_init(…) 之后使用
示例:
1u32 code_len = 0x8000;//升级文件大小,通过计算db_update_data.bin的长度得到(与上位机通信得到) 2u32 ret = dual_bank_update_allow_check(code_crc, code_len, 256, NULL);
2.10.4.3. dual_bank_passive_update_exit
函数原型:
u32 dual_bank_passive_update_exit(void *priv);
功能说明:终止当前的双备份升级流程,释放资源;
参数说明:
参数
说明
priv
保留参数,传 NULL 即可
- 返回值:
返回值
说明
0
成功
非0
失败
示例:
1dual_bank_passive_update_exit(NULL);
2.10.4.4. dual_bank_update_write
函数原型:
u32 dual_bank_update_write(void *data, u16 len, int (*write_complete_cb)(void *priv));
功能说明:把缓冲区数据写入非易失性存储(Flash)并可通过回调函数告知应用层写入成功or失败
参数说明:
参数
说明
data
下载数据的指针(就是你通过上位机收到的升级包数据缓存)
len
本次要写入的数据长度(字节数),必须 ≤ 初始化时的 max_pkt_len
write_complete_cb
本次烧写完成回调函数,执行成功 priv = 0,执行失败 priv != 0;非必要可传NULL
- 返回值:
返回值
说明
0
写入成功
非0
写入失败
示例:
1// 示例:收到一包数据,调用写入 2u8 buf[256]; // 接收数据缓存 3u16 rx_len = 256; // 实际收到长度 4// 写入升级数据(回调传 NULL 也可以) 5u32 ret = dual_bank_update_write(buf, rx_len, NULL);
2.10.4.5. dual_bank_update_verify
函数原型:
u32 dual_bank_update_verify( void (*crc_init_hdl)(void), u32(*crc_calc_hdl)(u32 init_crc, const void *data, u32 len), int (*verify_result_hdl)(int calc_crc));
功能说明:计算所有已经烧写的固件数据的CRC值,并与升级初始化时传入的CRC值进行对比校验
参数说明:
参数
说明
crc_init_hdl
如果传NULL,使用内部默认CRC算法(CRC16-CCITT标准);传自定义函数则使用用户CRC初始化
crc_calc_hdl
如果传NULL,使用内部默认CRC计算;传自定义函数则使用用户CRC计算
verify_result_hdl
校验完成的结果回调; calc_crc = 1:校验成功; calc_crc = 0:校验失败;
- 返回值:
返回值
说明
0
校验成功
非0
校验失败
示例:
1// 1. 先定义校验结果回调函数 2static int dual_verify_result_hdl(int calc_crc) 3{ 4 if(calc_crc == 1){ 5 // CRC 校验成功 → 可以进行下一步:升级确认 + 重启 6 printf("固件校验成功\n"); 7 }else{ 8 // 校验失败 → 升级作废,不切换分区,旧系统继续用 9 printf("固件校验失败\n"); 10 } 11 return 0; 12} 13 14// 2. 调用校验函数(全部用内部默认CRC,最省心) 15dual_bank_update_verify(NULL, NULL, dual_verify_result_hdl);
2.10.4.6. dual_bank_update_burn_boot_info
函数原型:
u32 dual_bank_update_burn_boot_info(int (*burn_boot_info_result_hdl)(int err));
功能说明:新固件校验成功后,调用该接口烧写新的启动引导信息(作用:告诉芯片下次重启从新固件分区启动)
参数说明:
参数
说明
burn_boot_info_result_hdl
烧写启动信息结果回调 err = 0:烧写成功 err ≠ 0:烧写失败
- 返回值:
返回值
说明
0
烧写启动信息成功
非0
烧写启动信息失败
示例:
1// 1. 定义启动信息烧写结果回调 2static int dual_burn_boot_info_result_hdl(int err) 3{ 4 if(err == 0){ 5 // 启动信息烧写成功 → 可以重启了 6 printf("启动标志更新成功,即将重启生效\n"); 7 8 // 这里可以延时后调用系统重启 9 // sys_reset(); 10 }else{ 11 // 烧写失败 → 不切换,继续用旧固件 12 printf("更新启动信息失败\n"); 13 } 14 return 0; 15} 16 17// 2. 在校验成功后调用 18dual_bank_update_burn_boot_info(dual_burn_boot_info_result_hdl);
2.10.4.7. dual_bank_update_verify_without_crc
函数原型:
u8 dual_bank_update_verify_without_crc(void);
功能说明:适用于:上位机端没有下发新固件的CRC校验值的场景,函数会自动读取Flash里的新固件文件,进行完整性校验
参数说明:无传参
- 返回值:
返回值
说明
0
校验成功
非0
校验失败
示例:
1// 写完所有升级数据后,直接调用 2u8 verify_res = dual_bank_update_verify_without_crc(); 3if(verify_res == 0) { 4 // 校验成功 → 烧写启动信息,准备重启 5 dual_bank_update_burn_boot_info(dual_burn_boot_info_result_hdl); 6} else { 7 // 校验失败 → 升级终止,保留旧固件 8 printf("新固件校验失败\n"); 9}
2.10.4.8. flash_update_clr_boot_info
函数原型:
int flash_update_clr_boot_info(u8 type);
功能说明:此API用于擦除指定分区的启动信息,使用时需非常谨慎!
- 参数说明:
参数
说明
type
0:擦除当前运行分区的启动信息 1:擦除升级分区的启动信息
- 返回值:
返回值
说明
0
擦除成功
非0
擦除失败
示例:
1// 注意擦除前后需要加解除和添加写保护,慎用!!! 2norflash_set_write_protect(0, boot_info.vm.vm_saddr); 3flash_update_clr_boot_info(1); 4norflash_set_write_protect(1, boot_info.vm.vm_saddr);
2.10.5. 升级示例(伪代码)
1// 全局/上层传入信息
2u32 new_fw_crc; // 上位机发过来的固件CRC
3u32 new_fw_size; // 上位机发过来的固件大小
4u8 frame_buf[256]; // 上位机发过来的数据帧缓存
5u32 frame_len; // 上位机发过来的数据帧长度
6u32 write_len; // 记录写入flash大小
7
8static int burn_boot_info_result(int err)
9{
10 if (0 == err) {
11 // 启动信息烧写成功 → 可以重启了
12 cpu_reset();
13 }
14 return 0;
15}
16
17// ====================== 带 CRC 升级(verify 不传回调)======================
18void dual_bank_update_demo_with_crc(void)
19{
20 // 1. 解除flash写保护
21 norflash_set_write_protect(0, boot_info.vm.vm_saddr);
22
23 // 2. 初始化升级
24 if (dual_bank_passive_update_init(new_fw_crc, new_fw_size, 256, NULL)) {
25 //升级终止,初始化失败
26 goto __err_ret;
27 }
28
29 // 3. 检查Flash空间是否足够
30 if(dual_bank_update_allow_check(new_fw_size)) {
31 //升级终止, 空间不足;
32 goto __err_ret;
33 }
34
35 // 4. 循环接收数据包并写入Flash
36 write_len = 0;
37 while(write_len < new_fw_size) {
38 //接收一包数据 frame_buf, frame_len;
39 if (dual_bank_update_write(frame_buf, frame_len, NULL)) {
40 //升级终止,写入失败
41 goto __err_ret;
42 }
43 write_len += frame_len;
44 }
45
46 // 5. 带CRC校验(使用内部CRC,不传入回调函数)
47 if (dual_bank_update_verify(NULL, NULL, NULL)) {
48 //升级终止,校验失败
49 goto __err_ret;
50 }
51
52 // 6. 烧写启动信息
53 if (dual_bank_update_burn_boot_info(burn_boot_info_result)) {
54 //升级终止,烧写启动信息失败
55 goto __err_ret;
56 }
57
58 // 7. 升级成功,如果升级完成在回调函数不重启系统,需要把资源释放及写保护恢复了
59__err_ret:
60 // 8. 升级失败, 释放资源重新写保护flash
61 dual_bank_passive_update_exit();
62 norflash_set_write_protect(1, boot_info.vm.vm_saddr);
63}
64
65// ====================== 不带 CRC 升级(手机不传 CRC)======================
66void dual_bank_update_demo_without_crc(void)
67{
68 // 1. 解除flash写保护
69 norflash_set_write_protect(0, boot_info.vm.vm_saddr);
70
71 // 2. 初始化升级
72 if (dual_bank_passive_update_init(0, new_fw_size, 256, NULL)) {
73 //升级终止,初始化失败
74 goto __err_ret;
75 }
76
77 // 3. 检查Flash空间是否足够
78 if(dual_bank_update_allow_check(new_fw_size) != 0) {
79 //升级终止, 空间不足;
80 goto __err_ret;
81 }
82
83 // 4. 循环接收数据包并写入Flash
84 write_len = 0;
85 while(write_len < new_fw_size) {
86 //接收一包数据 frame_buf, frame_len;
87 if (dual_bank_update_write(frame_buf, frame_len, NULL)) {
88 //升级终止,写入失败
89 goto __err_ret;
90 }
91 write_len += frame_len;
92 }
93
94 // 5. 无CRC自动校验(杰理内部校验固件完整性)
95 u8 verify_result = dual_bank_update_verify_without_crc();
96 if (verify_result) {
97 //升级终止,校验失败
98 goto __err_ret;
99 }
100
101 // 6. 烧写启动信息
102 if (dual_bank_update_burn_boot_info(burn_boot_info_result)) {
103 //升级终止,烧写启动信息失败
104 goto __err_ret;
105 }
106
107 // 7. 升级成功,如果升级完成在回调函数不重启系统,需要把资源释放及写保护恢复了
108__err_ret:
109 // 8. 升级失败, 释放资源重新写保护flash
110 dual_bank_passive_update_exit();
111 norflash_set_write_protect(1, boot_info.vm.vm_saddr);
112 return;
113}

