luobeihai 发表于 2024-11-17 16:46

如何给编译生成的bin文件添加CRC校验值

本帖最后由 luobeihai 于 2024-11-17 16:54 编辑

#申请原创# @21小跑堂

有些时候我们需要在编译生成的bin文件中添加CRC校验码,在程序升级等情况下,可以获取存放在bin文件的校验码与通过相同的CRC算法计算出来的CRC校验码进行比较,如果相等,说明程序数据正确,可以执行升级操作,否则不进行升级操作。
我研究了下如何通过MDK环境或者IAR环境,在编译生成的bin文件中添加CRC校验码,下面我使用极海的 APM32F407 的工程代码,记录一下这个过程。我们首先得准备一个可以正常编译运行的 Keil 和 IAR 工程。
1. 基于MDK Keil环境在MDK Keil平台上,其本身没有自带的工具可以生成CRC校验码,所以,我们需要借助第三方的工具。
下面我 srecord 这个工具生成 CRC 校验码,然后再使用 hex2bin 工具把具有CRC校验码的 hex 文件转换为bin文件。
srecord 工具官网:https://srecord.sourceforge.net/
hex2bin 工具下载:https://sourceforge.net/projects/hex2bin/
1.1 工具配置

把之前下载好的 srecord 工具包,其中的一个 srec_cat.exe 工具,放到keil的工程t同级目录下面。

然后 hex2bin 工具也是,放到keil的工程同级目录下。
1.2 编写 .bat 命令脚本

我们编写一份 .bat 文件的命令脚本,以供 keil 调用 srecord 和 hex2bin 工具去生成bin文件。
我自己编写名为 hex_crc.bat 文件,其内容如下:
srec_cat.exe .\out\CRC_Calculation_Bin_CRC.hex -intel -crop 0x08000000 0x0803FFFC -fill 0xFF 0x08000000 0x0803FFFC -STM32_Little_Endian 0x0803FFFC -o .\output_crc_mdk.hex -intel

hex2bin .\output_crc_mdk.hex
第一条命令就是使用 srec_cat 这个工具,生成带有 CRC 校验码的hex文件。然后再把这个hex文件,使用 hex2bin 工具生成bin文件。
1.3 Keil配置

然后keil里面配置,编译完代码之后,执行刚刚的哪个 .bat 文件就可以生成带有CRC校验码的hex文件和bin文件了。

1.4 测试验证

我们可以写代码测试一下,使用IAR在bin文件生成的这个CRC值,是否正确。
首先我们可以使用芯片自带的CRC硬件计算(当然也可以使用软件CRC),从 0x08000000 起始地址开始读取,直到 0x0803FFFC 这个地址结束,读取这个区间Flash的内容,然后计算出来的结果,与使用Srec工具计算出来的结果进行比较是否相等。如果相等那么说明生成的bin文件CRC值时正确的。
代码思路也是一样的,如下:
uint32_t MDK_CRC_CheckVal = *((uint32_t *) 0x0803FFFC);

/* Calculate bin file CRC value */
uCRCValue = CRC_CalculateBlockCRC((uint32_t *)0x08000000, (0x40000 - 4) / 4);
LOG_Print("\r\nCalculateBlockCRC = 0x%08X, MDK_CRC_CheckVal = 0x%08X \r\n", uCRCValue, MDK_CRC_CheckVal);   

if (uCRCValue == MDK_CRC_CheckVal)
{
    LOG_Print("MDK CRC32 Check successful\r\n");
    APM_MINI_LEDOn(LED2);
}
else
{
    LOG_Print("MDK CRC32 Check error\r\n");
    APM_MINI_LEDOn(LED3);
}
然后可以通过J-Flash工具烧写bin文件,查看运行结果如下。

2. 基于IAR环境

IAR软件自带了 IAR ELF Tool 这个工具,它可以把编译生成的bin文件添加CRC校验码,所以使用起来也比较简单就能获得CRC的校验码。只要修改下选项配置还有配合修改下链接文件就可以了。
对于如何在bin文件添加CRC校验码,IAR官方网站也有相关介绍,如下:
https://www.iar.com/knowledge/support/technical-notes/general/calculate-crc32-as-in-stm32-hardware-v.5.50-and-later/
2.1 修改Options配置界面

2.1.1 Checksum选项配置

因为是是要把CRC校验码链接到我们编译生成的bin文件,所以肯定是要配置链接相关的参数的。

该页面有两部分配置。
第一部分是Flash的起始和结束地址,介绍地址要留出4字节的大小存放CRC校验值。然后剩余的Flash空间用0xFF填充。一般来说我们可以把CRC校验值存放在Flash空间的结束地址,这样在查找bin文件的CRC值时比较容易找到。
第二部分是生成CRC校验码的参数配置,我们要配置为和自己使用的CRC模型一致的配置,对于MCU自动的硬件CRC来说,大多数都是CRC32的模型。
该界面CRC参数的一些配置解释:
[*]1、Checksum size:CRC校验值的大小,4字节
[*]2、Alignment:指定校验值的对齐方式,4字节
[*]3、Algorithm:指定算法。CRC32 (0x4C11DB7)
[*]4、Complement:是否进行补码运算。as is 选择保留原样
[*]5、Bit order:位顺序。MSB优先
[*]6、Reverse byte order within word:反转字内的字节顺序
[*]7、Initial value:初始值。0xFFFFFFFF
[*]8、Checksum unit size:指定校验和进行迭代时的单元大小
2.1.2 Extra Options添加一条命令

在配置好 Checksum 选项是,我编译程序是发现并没有把CRC校验值添加值Bin文件指定的位置。网上找了好久,说需要添加 --keep __checksum这条命令,然后可以防止IAR优化掉CRC变量值。

2.1.3 生成bin文件

如果还需要bin文件的画卷,选择下面的选项配置。

2.2 修改IAR链接文件

我们找到对应MCU的 .icf 文件(一般在对应的IAR安装目录下 .\arm\config\linker ),然后复制一份到自己的工程目录下进行修改。主要其实就是根据前面的 Checksum 配置,把CRC值存放的地址,在 .icf 文件要对应修改链接进代码里面。
place at address mem:0x0803FFFC { readonly section .checksum };
只要在 .icf 文件添加上面的语句就行。但是 0x0803FFFC 这个地址要与 Checksum 界面的配置要一致。
然后在配置界面,选择这个 icf 文件作为IAR链接文件,如下:

2.3 验证IAR生成的bin文件CRC值是否正确

IAR环境生成的CRC校验码的bin文件,验证方法和Keil环境生成的也是一样的。都是计算 0x08000000~0x0803FFFC 之间的CRC校验值,然后和生成的bin文件的CRC值进行对比,验证是否相等。
主要代码如下:
extern uint32_t __checksum;

/* Calculate bin file CRC value */
uCRCValue = CRC_CalculateBlockCRC((uint32_t *)0x08000000, (0x40000 - 4) / 4);
LOG_Print("CalculateBlockCRC = 0x%08X, IAR_CRC_CheckVal = 0x%08X \r\n", uCRCValue, __checksum);   

if (uCRCValue == __checksum)
{
    LOG_Print("IAR CRC32 successful\r\n");
    APM_MINI_LEDOn(LED2);
}
else
{
    LOG_Print("IAR CRC32 error\r\n");
    APM_MINI_LEDOn(LED3);
}
__checksum 这个变量,其实就是IAR软件生成CRC校验值的一个内部变量,使用这个值与我们读取Flash的数据计算出来的值进行比较,测试两者是否相等。



呐咯密密 发表于 2024-11-20 10:11

CRC校验确实有必要

dalarang 发表于 2024-11-20 10:34

有用,收藏了

LEDyyds 发表于 2024-11-20 20:19

keil烧录的时候会校验CRC吗
页: [1]
查看完整版本: 如何给编译生成的bin文件添加CRC校验值