搜索

[MM32软件] MM32F013x——IEC60730-1 B类认证软件设计指南(三)

[复制链接]
1636|13
probedog|  楼主 | 2021-6-2 09:42 | 显示全部楼层 |阅读模式
在上一章节中我们介绍了CPU寄存器检测的实现方法,本章节我们将给大家介绍RAM检测的实现方法。SRAM检测不仅检测数据区域的错误,还检测其内部地址和数据路径的错误。
检测时由于需要执行软件算法(March-C),会影响CPU的利用率,所以SRAM测试采用拓扑模式,按位阵列推进测试,阵列中的逻辑邻位(属于单字)物理上彼此分离,而带后续逻辑地址的字对在物理上却共享邻位,此时可采用按字测试的方法。

使用特权

评论回复
probedog|  楼主 | 2021-6-2 09:43 | 显示全部楼层
SRAM自检采用March-C算法,March-C是一种用于嵌入式芯片RAM测试的算法,是安全认证的一部分,可用于测试那些未被硬件奇偶校验覆盖的部分RAM。为了不影响MCU的运行,将RAM分成很多小块,每次测试其中一块, 先将要测试的块清零,然后按位逐位置1,每置一位,测试该位是不是1,是就继续,不是就报错;全部置完后,再逐位清0,每清一个位,测试该位清0是不是0,如果是就正确,不是就报错。如果是对工作区的RAM,数据需要保留,在RAM中开一个安全保留区,先对安全保留区March-C,然后把要测试的区的数据copy进安全区,再对要测试的工作区进行March-C,测试-- copy进安全区-- 测试-- copy进安全区...... 完成整个空间的测试。

使用特权

评论回复
probedog|  楼主 | 2021-6-2 09:45 | 显示全部楼层
在ClassB检测中,RAM自检也分为启动自检与运行自检两部分。

01 ClassB RAM启动自检
RAM在启动自检过程中会检测全部的RAM。算法中会用值(0x00000000)和值(0xFFFFFFFF)逐字填充,填充后读取出来比较看值是否相等。

具体的运行流程图如下:
133447yrcacs195ageyva7.png.thumb.jpg

使用特权

评论回复
probedog|  楼主 | 2021-6-2 09:46 | 显示全部楼层
主要有6步:
对所有测试单元写0 (按地址增加的顺序)
逐个检测每个单元是否为0,如果全为0,然后写为0xFF* (按地址增加的顺序)
逐个检测每个单元是否为0xFF*,如果全为F,然后写为0 (按地址增加的顺序)
逐个检测每个单元是否为0,如果全为0,然后写为0xFF* (按地址递减的顺序)
逐个检测每个单元是否为0xFF*,如果全为F,然后写为0 (按地址递减的顺序)
逐个检测每个单元是否为0(按地址递减的顺序)

使用特权

评论回复
probedog|  楼主 | 2021-6-2 09:47 | 显示全部楼层
Class_FullRamMarchC
  PUSH  {R4-R7}
  MOVS  R4, #0x1       ; Test success status by default
  MOVS  R3,R2         ; setup inverted background pattern
  RSBS  R3, R3, #0
  SUBS  R3,R3, #1

; *** Step 1 ***
; Write background pattern with addresses increasing
  MOVS  R5,R0
__FULL1_LOOP
  CMP   R5,R1
  BHI   __FULL_RET

  LDR   R7,[R5, #+0]

  STR   R2,[R5, #+0]
  LDR   R6,[R5, #+0]
  CMP   R2,R6
  BNE   __FULL_ERR

  STR   R3,[R5, #+0]
  LDR   R6,[R5, #+0]
  CMP   R3,R6  
  BNE   __FULL_ERR

  STR   R7,[R5, #+0]  

  ADDS  R5,R5,#+4
  B     __FULL1_LOOP

; *** Step 2 ***
; Write background pattern with addresses decreasing  

  MOVS  R5,R1
  SUBS  R5,R5,#+4
__FULL2_LOOP
  CMP   R5,R0
  BLO   __FULL_RET

  LDR   R7,[R5, #+0]

  STR   R2,[R5, #+0]
  LDR   R6,[R5, #+0]
  CMP   R2,R6
  BNE   __FULL_ERR

  STR   R3,[R5, #+0]
  LDR   R6,[R5, #+0]
  CMP   R3,R6  
  BNE   __FULL_ERR

  STR   R7,[R5, #+0]  

  SUBS  R5,R5,#+4
  B     __FULL2_LOOP  

__FULL_ERR
  MOVS  R4,#0       ; error result

__FULL_RET

  MOVS  R0,R4
  POP   {R4-R7}
  BX    LR          ; return to the caller

使用特权

评论回复
probedog|  楼主 | 2021-6-2 09:48 | 显示全部楼层
02 ClassB RAM运行自检程序
RAM在运行自检的过程中只检测部分RAM,不会检测全部的RAM。目前主要自检0x20000030-0x2000007B范围内的RAM以及0x20000000-0x2000001F缓冲区范围的RAM,具体的操作流程如下:
133528mfc4dfnicxrixffo.png.thumb.jpg

使用特权

评论回复
probedog|  楼主 | 2021-6-2 09:51 | 显示全部楼层
在mm32_RamMcMxKeil.c进行如下操作:

; ***************** test of the RAM slice *********************
  MOVS  R5, #0       ; NO - save content of the RAM slice into the backup buffer
__SAVE_LOOP
  LDR   R6,[R4, R5]  ; load data offset
  LDR   R7,[R0, R6]  ; load data from RAM
  ADDS  R5,R5,#4     ; original data are stored starting from second item of the buffer
  STR   R7,[R1, R5]  ; (first and last items are used for testing purpose exclusively)
  CMP   R5, #20
  BLE   __SAVE_LOOP

; *** Step 1 ***
; Write background pattern with addresses increasing
  MOVS  R5, #0
__STEP1_LOOP
  LDR   R6,[R4, R5]  ; load data offset
  STR   R2,[R0, R6]  ; store background pattern
  ADDS  R5,R5,#4
  CMP   R5, #20
  BLE   __STEP1_LOOP

; *** Step 2 ***
; VerIFy background and write inverted background with addresses increasing
  MOVS  R5, #0
__STEP2_LOOP
  LDR   R6,[R4, R5]  ; load data offset
  LDR   R7,[R0, R6]  ; verify background pattern
  CMP   R7, R2
  BNE   __STEP_ERR
  STR   R3,[R0, R6]  ; store inverted background pattern
  ADDS  R5,R5,#4
  CMP   R5, #20
  BLE   __STEP2_LOOP

使用特权

评论回复
probedog|  楼主 | 2021-6-2 09:54 | 显示全部楼层
在MDK工程的mm32_STLClassBvar.h文件中设置一些变量进行定址,并在工程配置中设定区域。

  /* RAM location for temporary storage of original values at run time RAM transparent test */
  EXTERN uint32_t aRunTimeRamBuf[RT_RAM_BLOCKSIZE + 2] __attribute__((section("RUN_TIME_RAM_BUF")));

  /* RAM pointer for run-time tests */
  EXTERN uint32_t *pRunTimeRamChk        __attribute__((section("RUN_TIME_RAM_PNT")));
  EXTERN uint32_t *pRunTimeRamChkInv     __attribute__((section("RUN_TIME_RAM_PNT")));
  EXTERN uint32_t aGAP_FOR_RAM_TEST_OVERLAY[2] __attribute__((section("RUN_TIME_RAM_PNT")));

  /*Note:the zero_init forces the linker to place variables in the bsssection */
  /*This allows the UNINIT directive(in scatter file)to work. On the contrary */
  /* all Class B variables pairs should be initialized properly by user before using them */

  /* Counter for verifying correct program execution at start */
  EXTERN uint32_t CtrlFlowCnt             __attribute__((section("CLASS_B_RAM"), zero_init));
  EXTERN uint32_t CtrlFlowCntInv          __attribute__((section("CLASS_B_RAM_REV"), zero_init));

  /* Counter for verifying correct program execution in interrupt */
  EXTERN uint32_t ISRCtrlFlowCnt          __attribute__((section("CLASS_B_RAM"), zero_init));
  EXTERN uint32_t ISRCtrlFlowCntInv       __attribute__((section("CLASS_B_RAM_REV"), zero_init));

  /* LSI period measurement at TIM5 IRQHandler */
  EXTERN uint32_t PeriodValue           __attribute__((section("CLASS_B_RAM"), zero_init));
  EXTERN uint32_t PeriodValueInv        __attribute__((section("CLASS_B_RAM_REV"), zero_init));

  /* Sofware time base used in main program (incremented in SysTick timer ISR */
  EXTERN uint32_t TickCounter             __attribute__((section("CLASS_B_RAM"), zero_init));
  EXTERN uint32_t TickCounterInv          __attribute__((section("CLASS_B_RAM_REV"), zero_init));

  /* Indicates to the main routine a 100ms tick */
  EXTERN __IO uint32_t TimeBaseFlag       __attribute__((section("CLASS_B_RAM"), zero_init));
  EXTERN __IO uint32_t TimeBaseFlagInv    __attribute__((section("CLASS_B_RAM_REV"), zero_init));

  /* Indicates to the main routine a 100ms tick */
  EXTERN __IO uint32_t LSIPeriodFlag      __attribute__((section("CLASS_B_RAM"), zero_init));
  EXTERN __IO uint32_t LSIPeriodFlagInv   __attribute__((section("CLASS_B_RAM_REV"), zero_init));

  /* Stores the Control flow counter from one main loop to the other */
  EXTERN uint32_t LastCtrlFlowCnt         __attribute__((section("CLASS_B_RAM"), zero_init));
  EXTERN uint32_t LastCtrlFlowCntInv      __attribute__((section("CLASS_B_RAM_REV"), zero_init));

  /* Pointer to FLASH for crc32 run-time tests */
  EXTERN uint32_t *pRunCrc32Chk           __attribute__((section("CLASS_B_RAM"), zero_init));
  EXTERN uint32_t *pRunCrc32ChkInv        __attribute__((section("CLASS_B_RAM_REV"), zero_init));

/* Reference 32-bit CRC for run-time tests */
  EXTERN uint32_t RefCrc32                __attribute__((section("CLASS_B_RAM"), zero_init));
  EXTERN uint32_t RefCrc32Inv             __attribute__((section("CLASS_B_RAM_REV"), zero_init));
  EXTERN uint32_t LSI_Freq                __attribute__((section("CLASS_B_RAM"), zero_init));
  /* Magic pattern for Stack oveRFlow in this array */
  EXTERN __IO uint32_t aStackOverFlowPtrn[4]   __attribute__((section("STACK_BOTTOM"), zero_init));

使用特权

评论回复
laocuo1142| | 2021-6-2 10:11 | 显示全部楼层
本帖最后由 laocuo1142 于 2021-6-2 10:33 编辑

很棒的小讲堂,每天学习一点点

使用特权

评论回复
probedog|  楼主 | 2021-6-2 10:34 | 显示全部楼层
在MDK的Options for Target   选项卡中进行如下配置:
133741lkzdfgid4ykgy7oz.png.thumb.jpg

使用特权

评论回复
probedog|  楼主 | 2021-6-2 10:35 | 显示全部楼层
在ClassBtest.sct文件中可以看到如下结果:
133758bgxm4ilurmmxxro5.png.thumb.jpg

使用特权

评论回复
probedog|  楼主 | 2021-6-2 10:37 | 显示全部楼层
栈检查的操作原理:设定特定的值在栈底,当检测到栈底的数值发生变化了,就认为栈溢出了。

    control_flow_call(STACK_OVERFLOW_TEST);
    aStackOverFlowPtrn[0] = 0xEEEEEEEEuL;
    aStackOverFlowPtrn[1] = 0xCCCCCCCCuL;
    aStackOverFlowPtrn[2] = 0xBBBBBBBBuL;
    aStackOverFlowPtrn[3] = 0xDDDDDDDDuL;
    control_flow_resume(STACK_OVERFLOW_TEST);

/**
  * @Brief  This function verifies that Stack didn't overflow
  * @param  : None
  * @retval : ErrorStatus = (ERROR, SUCCESS)
  */
ErrorStatus STL_CheckStack(void)
{
  ErrorStatus result = SUCCESS;

  CtrlFlowCnt += STACK_OVERFLOW_CALLEE;

  if ( aStackOverFlowPtrn[0] != 0xEEEEEEEEuL )
  {
    result = ERROR;
  }
  if ( aStackOverFlowPtrn[1] != 0xCCCCCCCCuL )
  {
    result = ERROR;
  }
  if ( aStackOverFlowPtrn[2] != 0xBBBBBBBBuL )
  {
    result = ERROR;
  }
  if ( aStackOverFlowPtrn[3] != 0xDDDDDDDDuL )
  {
    result = ERROR;
  }
  CtrlFlowCntInv -= STACK_OVERFLOW_CALLEE;
  return (result);
}

使用特权

评论回复
probedog|  楼主 | 2021-6-2 10:37 | 显示全部楼层
以上代码是RAM自检的汇编代码,整个算法执行会花费一定时间,如果整个内存范围的测试时间太长,就会对用户应用程序造成较大的局限性,所以将其分成若干片段,这些片段与执行程序的本地区域相一致。对被测试区域进行动态修改,然后进行单独执行测试。检测出问题则会跳转后面的故障函数,可以添加对应的操作进行故障处理。

使用特权

评论回复
yangxiaor520| | 2021-6-4 07:57 | 显示全部楼层
学习一下

使用特权

评论回复
扫描二维码,随时随地手机跟帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

我要发帖 我要提问 投诉建议 申请版主

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式

本版热帖

本版活跃用户

优质原创写原创,赢大奖

编辑推荐

  • 1 wolfe_yu 得到打赏 ¥180.00
  • 2 最美葫芦娃 得到打赏 ¥155.00
  • 3 hk386 得到打赏 ¥75.00
  • 4 火星国务卿 得到打赏 ¥63.00
  • 5 两只袜子 得到打赏 ¥56.00
  • 6 laocuo1142 得到打赏 ¥50.00
  • 7 ezcui 得到打赏 ¥45.00
  • 8 linghz 得到打赏 ¥45.00
  • 9 gaon2 得到打赏 ¥45.00
  • 10 liang-1011 得到打赏 ¥40.00
在线客服 快速回复 返回顶部 返回列表