一、引言
GD32 作为一款性能优异的微控制器,通过基于 CAN 总线的 IAP(In Application Programming,在应用编程)升级方案,能够实现高效、可靠的远程软件更新,为设备的持续优化和维护提供了便捷途径。
二、GD32 IAP 升级方案概览
GD32 的 IAP 升级方案打破了传统需要现场连接编程器进行程序更新的局限。借助 CAN 总线的高可靠性和远距离传输能力,实现了设备在运行状态下的远程自主升级。这不仅大大降低了维护成本,提高了效率,还使得设备能够及时适应新的功能需求和修复潜在的问题。该方案广泛应用于汽车电子、工业自动化、智能仪器仪表等领域,为各类嵌入式系统的持续发展注入了强大动力。
三、GD32 BOOT
(一)BOOT 核心职责
BOOT 程序在系统启动和更新过程中扮演着至关重要的角色。它就像一位忠诚的卫士,负责守护系统的入口并决定系统的运行方向。在系统上电时,BOOT 首先被执行,它会进行一系列的初始化工作,如硬件初始化、时钟配置等。然后,BOOT 会检测是否有更新的需求。如果需要更新,它会引导系统进入更新模式,接收并处理新的程序代码;如果不需要更新,BOOT 则会迅速跳转到 APP 区,启动主程序的运行。
可以将 BOOT 比作是一个铁路道岔,根据不同的情况将系统的运行轨道切换到更新线路或主程序运行线路,确保系统始终能够按照正确的方式启动和运行。
(二)内部 FLASH 分区规划
以内部 Flash 总大小 512KB 为例,分区规划如下:
BOOT 区是系统启动的起点,其中的程序负责整个启动和升级流程的控制。APP 区则是设备正常运行时主程序的存储空间,承载着设备的核心功能和业务逻辑。数据缓存区用于暂时存储从外部接收到的待更新的固件数据,为后续的更新操作做准备。参数区则保存着设备运行所需的各种参数和配置信息,这些信息在系统启动和运行过程中被读取和使用,以确保设备能够在不同的环境和条件下正确地工作。
(三)代码示例
#include "gd32f10x.h"
// 定义跳转目标地址
#define APP_START_ADDRESS 0x8008000
void boot_jump_to_app(void)
{
// 关闭所有中断,确保跳转过程不受中断干扰
__disable_irq();
// 初始化栈指针,为跳转后的程序运行准备好栈空间
__set_MSP(*(uint32_t *)APP_START_ADDRESS);
// 跳转到应用程序起始地址,实现从 BOOT 到 APP 的切换
((void (*)(void))APP_START_ADDRESS)();
}
void boot_update_check(void)
{
// 在此处添加检测更新标志的代码
if (update_needed)
{
// 执行更新相关的操作
}
else
{
// 不需要更新,直接跳转至 APP
boot_jump_to_app();
}
}
int main(void)
{
// 进行 BOOT 程序的初始化操作
// 例如硬件初始化、时钟配置等
boot_update_check();
while (1)
{
// 可以添加 BOOT 程序的其他处理逻辑,如果跳转未执行
}
}
在上述代码中,boot_jump_to_app 函数用于实现从 BOOT 区跳转到 APP 区的操作。首先通过 __disable_irq 关闭所有中断,以避免跳转过程中被中断干扰。然后使用 __set_MSP 初始化栈指针,确保跳转后的 APP 程序有正确的栈空间可用。最后通过强制类型转换将 APP 区的起始地址转换为函数指针,并直接调用该指针实现跳转。
boot_update_check 函数用于检查是否需要进行更新,如果需要更新则执行相应的更新操作,否则调用 boot_jump_to_app 函数跳转到 APP 区。
(四)BOOT逻辑流程
系统上电后先进行初始化,然后检查升级标志。若有升级标志,则检测缓存区固件的合法性。合法则将代码搬运到 APP 区,清除更新标识并复位;不合法则跳转到 APP 运行。若无升级标志,直接跳转到 APP 运行。
四、CAN 总线自定义协议
(一)CAN 总线基础
CAN 总线是一种广泛应用于汽车、工业控制等领域的串行通信总线。它具有多主通信、高可靠性、实时性强等优点。CAN 总线采用差分信号传输,能够在恶劣的电磁环境下稳定工作。其数据帧包含标识符、控制域、数据域和校验域等部分,通过标识符来确定消息的优先级,实现了非破坏性的总线仲裁机制,保证了高优先级的消息能够及时传输。
CAN 总线的高可靠性使得它非常适合用于对数据传输要求严格的场合,如汽车的电子控制系统。在这些系统中,CAN 总线能够确保各个控制单元之间的通信准确无误,从而保障车辆的安全和稳定运行。
(二)自定义协议定义
升级开始
指令:START_UPGRADE
数据:{版本号,文件大小}
错误码:
ERR_VERSION_MISMATCH:版本不匹配
ERR_FILE_SIZE_INVALID:文件大小无效
升级中
指令:DATA_TRANSFER
数据:{数据包序号,数据}
错误码:
ERR_PACKET_SEQUENCE_ERROR:数据包序号错误
ERR_DATA_CORRUPT:数据损坏
升级完成
指令:UPGRADE_COMPLETE
数据:{校验和}
错误码:
ERR_CHECKSUM_ERROR:校验和错误
数据结构体定义:
typedef struct
{
uint8_t command;
uint16_t data_length;
uint8_t data[255];
uint16_t crc;
} can_message_t;
示例代码:
#include "can.h"
void send_upgrade_start(can_message_t *msg)
{
msg->command = START_UPGRADE;
msg->data_length = sizeof(uint16_t) + sizeof(uint32_t); // 版本号和文件大小的长度
// 填充版本号和文件大小数据
calculate_crc(msg); // 计算 CRC 校验值
can_send_message(msg); // 发送消息
}
void handle_can_message(can_message_t *msg)
{
switch (msg->command)
{
case START_UPGRADE:
// 处理升级开始的逻辑
break;
case DATA_TRANSFER:
// 处理数据传输的逻辑
break;
case UPGRADE_COMPLETE:
// 处理升级完成的逻辑
break;
default:
// 处理未知指令
break;
}
}
五、IAP 升级流程
(一)升级开始
终端设备向 GD32 设备发送升级请求指令,指令中包含要升级的版本号和文件大小。GD32 设备收到请求后,回复确认指令,并与终端进行握手,确认双方通信正常且具备升级条件。
(二)升级中
终端将升级文件按照预定的数据包大小进行分包发送。每个数据包都包含数据包序号和数据内容。GD32 设备收到数据包后,进行校验和确认,并回复确认指令给终端。如果数据包校验错误,GD32 设备会请求终端重新发送该数据包。
(三)升级完成
终端发送升级完成指令,指令中包含整个升级文件的校验和。GD32 设备收到指令后,对已接收的升级文件进行校验和计算,并与终端发送的校验和进行比较。如果校验一致,GD32 设备回复确认指令,并进行重启,加载新的程序。如果校验不一致,GD32 设备回复错误指令,要求终端重新发起升级流程。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/pigliuxu/article/details/144930920
|