[LKS32 硬件] 【LKS32AT085评测】03.ClassB看门狗、堆栈溢出、FLASH运行自检

[复制链接]
2436|5
 楼主| GrandLine 发表于 2022-9-25 09:39 | 显示全部楼层 |阅读模式
本帖最后由 GrandLine 于 2022-9-25 09:43 编辑

上一小节我们了解了IEC60730 ClassB以及在KEIL MDK集成开发环境下如何配置生成HEX文件的CRC校验方法,并对烧录到FLASH中的程序进行CRC校验检测,本小节继续来围绕IEC60730 ClassB其它功能实现进行分享。


FLASH CRC运行自检
在上节中提到,在启动自检时,ClassB会对整个应用代码一次性做完整的CRC计算,对计算的结果进行判断比较;而在运行周期性自检时,为了减少ClassB自检程序所占用的时间对应用程序的影响,对于CRC部分会分扇区进行CRC运算,一般一次只计算FLASH中的一个SECTOR或者更小的PAGE,在计算完所有的SECTOR或者PAGE后,再将此时的计算结果进行判断比较。如下所示为FLASH CRC运行自检的实现:
  • FLASH CRC宏定义及初始化:
  1. #define CLASSB_FLASH_START         (uint32_t)(0x00000000)
  2. #define CLASSB_FLASH_END           (uint32_t)((uint32_t *)&__Check_Sum)
  3. #define CLASSB_FLASH_SECTOR_SIZE   (uint32_t)(0x200)

  4. /*******************************************************************************
  5. * [url=home.php?mod=space&uid=247401]@brief[/url]      
  6. * @param      
  7. * @retval      
  8. * [url=home.php?mod=space&uid=93590]@Attention[/url]   
  9. *******************************************************************************/
  10. void CLASSB_FALSH_InitCRC(void)
  11. {
  12.     CRC_CR   = 0x00000000;
  13.     CRC_CR  |= BIT0;
  14.     CRC_POL  = 0x04C11DB7;
  15.     CRC_INIT = 0xFFFFFFFF;
  16. }
  • FLASH CRC运行自检实现部分:
  1. /*******************************************************************************
  2. * [url=home.php?mod=space&uid=247401]@brief[/url]      
  3. * @param      
  4. * @retval      
  5. * [url=home.php?mod=space&uid=93590]@Attention[/url]   
  6. *******************************************************************************/
  7. void CLASSB_FLASH_Running(void)
  8. {
  9.     static uint32_t Address = CLASSB_FLASH_START;

  10.     uint32_t StartAddress = 0, EndAddress = 0;

  11.     if(Address < CLASSB_FLASH_END)
  12.     {
  13.         if((Address + CLASSB_FLASH_SECTOR_SIZE) < CLASSB_FLASH_END)
  14.         {
  15.             StartAddress = Address;
  16.             EndAddress   = Address + CLASSB_FLASH_SECTOR_SIZE;
  17.         }
  18.         else
  19.         {
  20.             StartAddress = Address;
  21.             EndAddress   = CLASSB_FLASH_END;
  22.         }

  23.         for(uint32_t i = StartAddress; i < EndAddress; i += 4)
  24.         {
  25.             REG32(&CRC_DR) = *((uint32_t *)(i));
  26.         }

  27.         Address += CLASSB_FLASH_SECTOR_SIZE;
  28.     }
  29.     else
  30.     {
  31.         if(((REG32(&CRC_DR)) ^ 0x00000000) == __Check_Sum)
  32.         {
  33.             printf("\r\nFlash CRC Correct!");
  34.         }
  35.         else
  36.         {
  37.             printf("\r\nFlash CRC Error!!!");
  38.         }

  39.         CLASSB_FALSH_InitCRC();

  40.         Address = CLASSB_FLASH_START;
  41.     }
  42. }
  • FLASH CRC运行自检调用部分:
在主程序main函数中完成启动自检后,通过调用CLASSB_FALSH_InitCRC函数重新初始化配置CRC配置参数,然后在while(1)中周期性CLASSB_FLASH_Running函数进行FLASH局部CRC的运算,直到将整个FLASH程序数据的CRC计算完成,进行结果比对。


看门狗自检
在SYS_RST_SRC寄存器中标注了系统不同复位源的标识,其中BIT3为看门狗复位标识,我通过这个标识来判断当前系统是正常的上电复位,还是看门狗复位;以此来实现看门狗的启动自检和运行,具体实现如下:
  • 看门狗的初始化、喂狗、周期性喂狗:
  1. /*******************************************************************************
  2. * @brief      
  3. * @param      
  4. * @retval      
  5. * @attention   
  6. *******************************************************************************/
  7. void WDT_Feed(uint32_t TimeOut)
  8. {
  9.     SYS_WR_PROTECT = 0xCAFE;

  10.     switch(TimeOut)
  11.     {
  12.         case SYS_WD_TimeOut2s  : SYS_WDT_CLR = 0x798F; break;
  13.         case SYS_WD_TimeOut4s  : SYS_WDT_CLR = 0x798D; break;
  14.         case SYS_WD_TimeOut8s  : SYS_WDT_CLR = 0x798B; break;
  15.         case SYS_WD_TimeOut64s : SYS_WDT_CLR = 0x7989; break;
  16.         default : break;
  17.     }

  18.     SYS_WR_PROTECT = 0;
  19. }


  20. /*******************************************************************************
  21. * @brief      
  22. * @param      
  23. * @retval      
  24. * @attention   
  25. *******************************************************************************/
  26. void WDT_Init(void)
  27. {
  28.     uint32_t REG_TEMP = SYS_RST_CFG;

  29.     SYS_WR_PROTECT = 0x7A83;

  30.     REG_TEMP |= BIT0;

  31.     SYS_RST_CFG = REG_TEMP;
  32. }


  33. /*******************************************************************************
  34. * @brief      
  35. * @param      
  36. * @retval      
  37. * @attention   
  38. *******************************************************************************/
  39. void WDT_MultiTimerCallback(MultiTimer *timer, void *userData)
  40. {
  41.     WDT_Feed(SYS_WD_TimeOut2s);

  42.     MultiTimerStart(&WDT_MultiTimer, 250, WDT_MultiTimerCallback, "WDT");
  43. }
  • 看门启动自检实现部分:
  1.     if(SYS_RST_SRC & BIT3)
  2.     {
  3.         printf("\r\n-----------------");
  4.         printf("\r\nWDT Reset Test OK\r\n");
  5.         printf("-----------------\r\n");

  6.         MultiTimerStart(&WDT_MultiTimer, 250, WDT_MultiTimerCallback, "WDT");
  7.     }
  8.     else
  9.     {
  10.         WDT_Init();
  11.         WDT_Feed(SYS_WD_TimeOut2s); while(1);
  12.     }
  • 看门狗运行部分:
程序设计中使用了MultiTimer组件,每间隔250ms调用一次喂狗操作。这些需要注意2点:一是喂狗操作不要放在定时器中来实现周期性执行,定时器中断是抢占式的,当后台应用程序卡住了,定时器还是会正常运行的,所以会导致错误的判断;另外一个就是LKS32AT085的看门狗使用的LSI时钟,这个时钟默认就是打开的,且关闭不了,这个时钟在全温范围内具有一定偏差,手册上标注常温在23~42kHz,全温在16~48kHz,所以在喂狗的期间上需要考虑到这一点。


堆栈溢出自检
堆栈溢出检测实现比较简单,就是在栈顶定义一个数组,在程序初始化完成时给这个数组中的每个成员赋值,然后在运行的时候,周期性的来读取这个数组中成员变量的值进行判断,是否是与之前所赋的值相一致,具体的实现如下:
  • 在startup_lks32mc08x.s文件中定义堆栈的大小:
  1. Stack_Size      EQU     0x00000300

  2.                 AREA    STACK, NOINIT, READWRITE, ALIGN=3
  3. Stack_Mem       SPACE   Stack_Size
  4. __initial_sp


  5. ; <h> Heap Configuration
  6. ;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
  7. ; </h>

  8. Heap_Size       EQU     0x00000200

  9.                 AREA    HEAP, NOINIT, READWRITE, ALIGN=3
  10. __heap_base
  11. Heap_Mem        SPACE   Heap_Size
  12. __heap_limit
  • 在ClassB_LKS32MC08x.sct文件中手动规划RAM区域功能,并定义STACK_BOTTOM:
  1. ; *************************************************************
  2. ; *** Scatter-Loading Description File generated by uVision ***
  3. ; *************************************************************

  4. LR_IROM1 0x00000000 0x00010000  {    ; load region size_region
  5.   ER_IROM1 0x00000000 0x00010000  {  ; load address = execution address
  6.    *.o (RESET, +First)
  7.    *(InRoot$Sections)
  8.    .ANY (+RO)
  9.    .ANY (+XO)
  10.    *.o (CHECKSUM, +Last)
  11.   }
  12.   RW_IRAM1 0x20000000 0x00001B00  {  ; RW data
  13.    .ANY (+RW +ZI)
  14.   }
  15.   STACK_NO_HEAP 0x20001B00 UNINIT 0x500
  16.   {
  17.     main.o               (STACK_BOTTOM)
  18.     startup_lks32mc08x.o (STACK, +Last)
  19.   }
  20. }

  • 定义堆栈溢出检测的数组:
  1. /* Private macro -------------------------------------------------------------*/
  2. volatile uint32_t aStackOverFlowPtrn[4] __attribute__((section("STACK_BOTTOM"), zero_init));
  • 给堆栈溢出检测数组的成员变量赋值,并打印地址、数值对应信息:
  1.     aStackOverFlowPtrn[0] = 0xEEEEEEEEuL;
  2.     aStackOverFlowPtrn[1] = 0xCCCCCCCCuL;
  3.     aStackOverFlowPtrn[2] = 0xBBBBBBBBuL;
  4.     aStackOverFlowPtrn[3] = 0xDDDDDDDDuL;

  5.     printf("\r\n");
  6.     printf("\r\n0x%08x : 0x%08x", &aStackOverFlowPtrn[0], aStackOverFlowPtrn[0]);
  7.     printf("\r\n0x%08x : 0x%08x", &aStackOverFlowPtrn[1], aStackOverFlowPtrn[1]);
  8.     printf("\r\n0x%08x : 0x%08x", &aStackOverFlowPtrn[2], aStackOverFlowPtrn[2]);
  9.     printf("\r\n0x%08x : 0x%08x", &aStackOverFlowPtrn[3], aStackOverFlowPtrn[3]);
  10.     printf("\r\n");
  • 堆栈溢出运行检测:
  1. /*******************************************************************************
  2. * @brief      
  3. * @param      
  4. * @retval      
  5. * @attention   
  6. *******************************************************************************/
  7. void CLASSB_CheckStackOverflow(void)
  8. {
  9.     if(aStackOverFlowPtrn[0] != 0xEEEEEEEEuL)
  10.     {
  11.         printf("\r\n%s[%d] : ERROR!", __FUNCTION__, __LINE__);
  12.     }

  13.     if(aStackOverFlowPtrn[1] != 0xCCCCCCCCuL)
  14.     {
  15.         printf("\r\n%s[%d] : ERROR!", __FUNCTION__, __LINE__);
  16.     }

  17.     if(aStackOverFlowPtrn[2] != 0xBBBBBBBBuL)
  18.     {
  19.         printf("\r\n%s[%d] : ERROR!", __FUNCTION__, __LINE__);
  20.     }

  21.     if(aStackOverFlowPtrn[3] != 0xDDDDDDDDuL)
  22.     {
  23.         printf("\r\n%s[%d] : ERROR!", __FUNCTION__, __LINE__);
  24.     }
  25. }


运行结果
1.png
 楼主| GrandLine 发表于 2022-9-25 10:45 | 显示全部楼层
附件
软件工程源代码: ClassB_FlashCRC_WDT_STACK.zip (189.81 KB, 下载次数: 20)
cooldog123pp 发表于 2022-9-25 16:43 | 显示全部楼层
楼主分享的很详细,感谢辛苦付出,如果以后用到这款单片机很有参考价值。
上下而求索 发表于 2022-9-25 19:12 | 显示全部楼层
cooldog123pp 发表于 2022-9-25 16:43
楼主分享的很详细,感谢辛苦付出,如果以后用到这款单片机很有参考价值。 ...

车规级应用,能用到的话,可以联系我哦
 楼主| GrandLine 发表于 2022-9-25 19:44 | 显示全部楼层
cooldog123pp 发表于 2022-9-25 16:43
楼主分享的很详细,感谢辛苦付出,如果以后用到这款单片机很有参考价值。 ...

Henryko 发表于 2022-10-4 19:41 | 显示全部楼层
很详细
您需要登录后才可以回帖 登录 | 注册

本版积分规则

6

主题

35

帖子

7

粉丝
快速回复 在线客服 返回列表 返回顶部