跳转到主要内容

MM32F013x——IEC60730-1 B类认证软件设计指南(四)

cathy 提交于

在<a href="http://mcu.eetrend.com/content/2021/100113929.html">上一章节</a>中我们介绍了RAM检测…,本章节我们将给大家介绍FLASH检测的实现方法。

测试Flash存储器完整性时,需要用到CRC校验,在参考代码中我们使用了硬件的CRC单元,通过硬件CRC生成器完成的CRC计算大大降低CPU负载。

Flash存储器测试的范围由用户界定,在运行时,如果整个内存范围因测试时间太长而不能接受,用户可将其分成若干片段,Flash存储器测试范围由用户界定,我们需要对被测试区域进行动态修改,以便在那些区域单独执行测试。

检查区域的边界必须与测试中用到的多重测试块的大小一致。根据mm32_STLparam.h文件中定义的参数FLASH_BLOCK_WORDS,块大小默认设为16字( 64字节),检查中未使用的内存区域可通过预定义值来识别。

我们会将CRC校验值存储在某一个地址,然后将CRC计算结果与相应的参考值进行比较,参考模式可由编译器( IAR™)自动提供或由在外部计算后由最终用户添加( MDK-ARM®和AC6)。

在ClassB检测中,Flash存储器检测也分为启动自检与运行自检两部分。

<strong>启动时对FLASH的检测方法:</strong>

<ul><li>编译时计算整个FLASH的CRC校验值,并存储在FLASH末尾位置</li>

<li>启动时,用同样的算法重新计算整个FLASH的CRC校验值(不包括前面存储在FLASH中的CRC校验值),并与存储在FLASH中的CRC校验值做比较</li></ul>

函数为:

<pre style="overflow-x:auto; background-color:#e9e9e9;">void STL_StartUp(void);</pre>

<strong>运行时对FLASH的检测方法:</strong>

<ul><li>对FLASH分块逐次计算出最终的CRC校验值</li>

<li>将最终结果与正确的CRC校验值做比较</li></ul>

函数为:

<pre style="overflow-x:auto; background-color:#e9e9e9;">ClassBTestStatus STL_crc32Run(void);</pre>

<strong><font color="#004a85">01、FLASH验证方法</font> </strong>

FLASH的验证分为2个步骤,如下所示:

1. 读取PC端计算FLASH对应的CRC值。

2. MCU运行计算出来的CRC值与读取到的PC端计算的CRC值进行比较。

<center><img src="http://mcu.eetrend.com/files/2021-07/wen_zhang_/100114083-210893-1.png&…; alt=“MM32F013x——IEC60730-1 B类认证软件设计指南(四)"></center>

<strong><font color="red">1.1、设置IAR生成CRC</font> </strong>

1)IAR可以很方便的支持在编译时计算CRC32,并存储在FLASH指定位置。

<center><img src="http://mcu.eetrend.com/files/2021-07/wen_zhang_/100114083-210894-2.png&…; alt=“MM32F013x——IEC60730-1 B类认证软件设计指南(四)"></center>

Fill unused code memory:定义了FLASH中需要计算CRC的范围和空闲字节填充值;

Checksum size:选择checksum的大小(字节数);

Alignment:指定checksum的对齐方式,不填的话默认2字节对齐;

Algorithm:选择checksum的算法;

Complement:是否需要进行补码计算,选择“As is”就是不进行补码计算;

Bit order:位输出的顺序,MSB first,每个字节的高位在前;LSB first,每个字节的低位在前;

Reverse byte order within word:对于输入数据,在一个字内反转各个字节的顺序;

Initial value:checksum计算的初始化值;

Checksum unit size:选择进行迭代的单元大小,按8-bit,16-bit还是32-bit进行迭代。

2)指定checksum在FLASH中的存储位置——修改linker文件:

place at end of ROM_region { ro section .checksum };

<strong><font color="red">1.2、设置Keil生成CRC脚本</font> </strong>

在Keil中需要单独计算CRC的值,并手动添加代码将其放在FLASH末尾。

当MDK在工程编译完成以后会在option for target ->User页面下面,勾选After build/Rebuild中的Run#1选项,则会在工程编译完成以后执行After build/Rebuild中的Run#1选项后面User Command路径选择中选择的脚本(crc_gen_keil.bat脚本)。

<center><img src="http://mcu.eetrend.com/files/2021-07/wen_zhang_/100114083-210895-3.png&…; alt=“MM32F013x——IEC60730-1 B类认证软件设计指南(四)"></center>

SREC_PATH:设定工具路径;

TARGET_NAME:生成Hex文件名;

MAP_FILE:原始生成的map文件;

INPUT_FILE:原始生产的HEX文件;

OUTPUT_FILE:计算CRC后的CRC文件;

crc_gen_keil.bat脚本内容:

<pre style="overflow-x:auto; background-color:#e9e9e9;">REM Path configuration
SET SREC_PATH=C:\SREC
SET TARGET_NAME=CLASSBTEST
SET TARGET_PATH=OBJ
SET BYTE_SWAP=1
SET COMPARE_HEX=1
SET CRC_ADDR_FROM_MAP=1
REM Not used when CRC_ADDR_FROM_MAP=1
SET CRC_ADDR=0x08007ce0</pre>

执行SET批处理命令,将相关的文件赋值给相对应的变量。

<pre style="overflow-x:auto; background-color:#e9e9e9;">REM Derived configuration
SET MAP_FILE=%TARGET_PATH%\%TARGET_NAME%.map
SET INPUT_HEX=%TARGET_PATH%\%TARGET_NAME%.hex
SET OUTPUT_HEX=%TARGET_PATH%\%TARGET_NAME%_CRC.hex
SET TMP_FILE=crc_tmp_file.txt</pre>

通过srec_cat.exe工具查找map文件中的__check_sum地址,并把计算的新的CRC的值填入到这个地址。

<center><img src="http://mcu.eetrend.com/files/2021-07/wen_zhang_/100114083-210896-4.png&…; alt=“MM32F013x——IEC60730-1 B类认证软件设计指南(四)"></center>

<strong><font color="red">1.3、在启动文件中设置CRC校验</font> </strong>

<pre style="overflow-x:auto; background-color:#e9e9e9;">AREA CHECKSUM, DATA, READONLY, ALIGN=6
EXPORT __Check_Sum
ALIGN
__Check_Sum DCD 0x8A7A061D;
END</pre>

<strong><font color="red">1.4、配置硬件CRC</font> </strong>

MM32的CRC初始化配置较简单,使能CRC时钟,复位 CRC 计算单元即可。

<pre style="overflow-x:auto; background-color:#e9e9e9;">RCC_AHBPeriphClockCmd(RCC_AHBENR_CRCEN,ENABLE);
CRC_ResetDR();</pre>

计算CRC的数值:

<pre style="overflow-x:auto; background-color:#e9e9e9;"> for(index = 0; index &lt; (uint32_t)ROM_SIZEinWORDS; index++)
{
CRC->DR = __REV(*((uint32_t *)ROM_START + index));
}
crc_result = CRC->DR;</pre>

<strong><font color="#004a85">02、MCU运行中计算FLASH中的CRC</font> </strong>

把要计算的FLASH大小分成多块累计计算CRC。

<pre style="overflow-x:auto; background-color:#e9e9e9;">uint32_t index;

for(index = 0; index &lt; (uint32_t)FLASH_BLOCK_WORDS; index++)
{
CRC->DR = __REV(*(pRunCrc32Chk + index));
}
pRunCrc32Chk += FLASH_BLOCK_WORDS;
pRunCrc32ChkInv = ((uint32_t *)~((uint32_t)pRunCrc32Chk));

result = TEST_RUNNING;</pre>

<strong><font color="red">2.1 MCU运行中计算的CRC的数值与PC端计算的CRC数值进行比较</font> </strong>

如果两者计算的CRC的数值相同则FLASH验证通过,否则验证失败。

启动时对比结果:

<pre style="overflow-x:auto; background-color:#e9e9e9;">#if defined(__CC_ARM) || defined(__GNUC__)
if(crc_result != *(uint32_t *)(&REF_CRC32))
#endif
{
#ifdef STL_VERBOSE_POR
printf("FLASH 32-bit CRC Error at Start-up\n\r");
#endif /* STL_VERBOSE_POR */
FailSafePOR(); //for ROM test realse must open;
//control_flow_resume(CRC_TEST_CALLER);
}
else
{ /* Test OK */
#ifdef STL_VERBOSE_POR
printf(" Start-up FLASH 32-bit CRC OK\n\r");
#endif /* STL_VERBOSE_POR */

control_flow_resume(CRC_TEST_CALLER);
}</pre>

运行时对比结果:

<pre style="overflow-x:auto; background-color:#e9e9e9;">if(CRC->DR == *(uint32_t *)(&REF_CRC32))
{
result = TEST_OK;
}
else
{
//result = TEST_OK ; // for ROM test realse must open;*******
result = TEST_FAILURE;
}</pre>

如果该块的FLASH检测通过,则进行下一次的检测,循环这一个过程。

至此,FLASH的校验已经全部完成,具体的配置程序可以参考官网例程。

来源:<a href="https://mp.weixin.qq.com/s/1GPnfUNuwY8Wl6IEZWSftg">灵动微电子</a&gt;
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。