大家好,我是情报小哥~ 今天给大家带来一个我常用的单片机固件版本定义方式。我相信一些朋友在入职一些小公司的时候一般都是一V1、V2等等这类的版本定义,然而随着项目的不断迭代,软件的逐步铺开,这样的建议版本定义已经无法满足需求,并且产生一大堆问题,比如: · 设备变砖:某工厂误将适配硬件V3 的固件刷入V2 设备,导致整批次报废 · 问题追溯难:客户反馈设备异常,工程师耗费3天定位到是v1.2.3 的PWM驱动BUG · 生产混乱:产线同时存在测试版 /量产版 固件,误刷率高达15% · 协作低效:硬件工程师更换传感器后,软件组未同步更新版本,引发通信故障 等等,以上这些总结下来主要是这四种风险 :
一、完备的版本号设计方案 1.1 版本号定义模版
主版本.次版本.补丁-hw硬件版本+日期.git哈希.crc校验 示例:2.3.5-hw4+20250504.8a3f2c1.78A2B9C4
1.2 字段详解表
二、具体如何实施? 2.1 固件代码实现 现在单片机基本上都还是C语言为主导,主打还是一个高效,那么下面以结构体的方式进行说明如下: 2.1.1 版本信息结构体 // version.h #pragma once #include <stdint.h>
// 存储到Flash的0x0800F000地址 typedefstruct __attribute__((packed)) { uint8_t major; // 主版本 uint8_t minor; // 次版本 uint16_t patch; // 补丁号(自动生成) uint8_t hw_version; // 硬件主版本 uint32_t build_date; // 构建日期 char git_sha[8]; // Git提交哈希(7字符+结束符) uint32_t file_crc; // 固件文件CRC32校验码 } FirmwareVersion;
// 通过指针访问版本信息 #define FW_VERSION ((FirmwareVersion*)0x0800F000)
2.1.2 CRC校验集成 // 在链接脚本中保留CRC存储区域 LR_ROM 0x08000000 0x100000 { ER_CRC 0x0800FFF0 EMPTY 0x00000004 { } }
// 编译后脚本自动注入CRC值 $ arm-none-eabi-objcopy --update-section .CRC=checksum.bin firmware.hex
比较简单吧,基本上方法就是在flash的固定区域中预留一段空间出来便于用于后续自动化工具的填充,当然你也可以自己去填充,不过就是麻烦了点,而且容易搞错。2.2 制作自动化工具 自己做的工具肯定是要好用,每次设计我主要考虑如下四个方面的功能,也是我觉得非常有必要的四个方面。 · 1、能够自动打包带版本号的固件文件 ·2、读取PCB配置文件中的硬件版本 · 3、完整性保护,自动计算并注入CRC校验码 · 4、追溯支持,嵌入Git提交信息和构建时间 2.2.3 核心代码片段 对于自动化工具的开发这里不过多展示,因为windows有非常多的方式,这里仅仅给出来一些大致的思路伪代码,供大家参考,思路也很简单,结合IDE生成的bin文件或者hex文件进行版本信息获取后填充到bin和hex中。 # 自动生成版本信息 def generate_version(): # 获取Git信息 git_sha = subprocess.check_output( ['git', 'rev-parse', '--short=7', 'HEAD'] ).decode().strip() # 读取硬件版本 with open('hw_config.json') as f: hw_ver = json.load(f)['main_version'] # 计算CRC32 with open('firmware.bin', 'rb') as f: crc_val = zlib.crc32(f.read()) & 0xFFFFFFFF return { 'version': f'{major}.{minor}.{patch}', 'hw_version': hw_ver, 'build_date': datetime.now().strftime('%Y%m%d'), 'git_sha': git_sha, 'crc': f'{crc_val:08X}' }
既然我们在版本号中进行设计,那总得把各个字段用起来吧,当然这个也需要结合大家实际项目的需求,比如我这边通常会在Bootloader有个校验逻辑如下代码所示: // 固件升级时执行校验 int validate_firmware(FirmwareVersion *new_ver) { // 硬件版本检查 if (new_ver->hw_version != CURRENT_HW_VERSION) { send_error('ERR_HW_MISMATCH'); return-1; } // CRC完整性校验 uint32_t calculated_crc = calculate_crc(new_ver); if (calculated_crc != new_ver->file_crc) { send_error('ERR_CRC_FAIL'); return-2; } // 防版本降级 if (compare_version(new_ver, current_ver) < 0) { send_error('ERR_VERSION_ROLLBACK'); return-3; } return0; }
这样的话,在产品量产的时候进行硬件版本的自动校验,而不会导致误刷;每个版本中都有Git哈希能够快速锁定问题代码版本;CRC校验能够拦截一部分的篡改和异常。 当然在上面的基础上还可以更加的精益求精,比如将打包工具集成到Jenkins/GitLab CI,在内网搭建版本看板,实时显示各版本状态等等,这个就看各个公司对版本的重视程度了。
|