之前写过一篇文章介绍过 CRC 的原理和应用。在程序升级的情况下,我们可以在烧录下载的 bin 文件添加 CRC 校验值,以校验我们获取的bin文件是否正确。
下面我打算使用 APM32F407 的工程代码,介绍下如何在 Keil 环境和 IAR 环境对编译生成的 bin 文件添加 CRC 校验值。
准备:
1、首先你得准备一个可以正常编译运行的 Keil 和 IAR 工程。
1. 基于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/
1.1 修改Options配置界面
1.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:指定校验和进行迭代时的单元大小
1.1.2 Extra Options添加一条命令
在配置好 Checksum 选项是,我编译程序是发现并没有把CRC校验值添加值Bin文件指定的位置。网上找了好久,说需要添加 –keep __checksum 这条命令,然后可以防止IAR优化掉CRC变量值。
1.1.3 生成bin文件
如果还需要bin文件的画卷,选择下面的选项配置。
1.2 修改IAR链接文件
我们找到对应MCU的 .icf 文件(一般在对应的IAR安装目录下 .\arm\config\linker ),然后复制一份到自己的工程目录下进行修改。主要其实就是根据前面的 Checksum 配置,把CRC值存放的地址,在 .icf 文件要对应修改链接进代码里面。
place at address mem:0x0803FFFC { readonly section .checksum };
只要在 .icf 文件添加上面的语句就行。但是 0x0803FFFC 这个地址要与 Checksum 界面的配置要一致。
然后在配置界面,选择这个 icf 文件作为IAR链接文件,如下:
1.3 验证IAR生成的bin文件CRC值是否正确
我们可以写代码测试一下,使用IAR在bin文件生成的这个CRC值,是否正确。
首先我们可以使用芯片自带的CRC硬件计算(当然也可以使用软件CRC),从 0x08000000 起始地址开始读取,直到 0x0803FFFC 这个地址结束,读取这个区间Flash的内容,然后计算出来的结果,与IAR软件计算出来的结果进行比较是否相等。如果相等那么说明IAR生成的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的数据计算出来的值进行比较,测试两者是否相等。
2. 基于Keil环境
Keil平台,是没有像IAR平台那样,自身带有一个工具可以为bin文件生成CRC校验值。所以,要在Keil环境中添加CRC校验码,就需要借助第三方的工具。
下面我 srecord 这个工具生成 CRC 校验码,然后再使用 hex2bin 工具把具有CRC校验码的 hex 文件转换为bin文件。
srecord 工具官网:
https://srecord.sourceforge.net/
hex2bin 工具下载:
https://sourceforge.net/projects/hex2bin/
2.1 工具配置
把之前下载好的 srecord 工具包,其中的一个 srec_cat.exe 工具,放到keil的工程t同级目录下面。
然后 hex2bin 工具也是,放到keil的工程同级目录下。
2.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 -intelhex2bin .\output_crc_mdk.hex
第一条命令就是使用 srec_cat 这个工具,生成带有 CRC 校验码的hex文件。然后再把这个hex文件,使用 hex2bin 工具生成bin文件。
2.3 Keil配置
然后keil里面配置,编译完代码之后,执行刚刚的哪个 .bat 文件就可以生成带有CRC校验码的hex文件和bin文件了。
2.4 测试验证
Keil环境生成的CRC校验码的bin文件,验证方法和IAR环境生成的也是一样的。都是计算 0x08000000~0x0803FFFC 之间的CRC校验值,然后和Keil环境生成的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文件,查看运行结果如下。