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

上一小节我们了解了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宏定义及初始化:
#define CLASSB_FLASH_START         (uint32_t)(0x00000000)

#define CLASSB_FLASH_END           (uint32_t)((uint32_t *)&__Check_Sum)

#define CLASSB_FLASH_SECTOR_SIZE   (uint32_t)(0x200)



/*******************************************************************************

 * [url=home.php?mod=space&uid=247401]@brief[/url]       

 * @param       

 * @retval      

 * [url=home.php?mod=space&uid=93590]@Attention[/url]   

*******************************************************************************/

void CLASSB_FALSH_InitCRC(void)

{

    CRC_CR   = 0x00000000;

    CRC_CR  |= BIT0;

    CRC_POL  = 0x04C11DB7;

    CRC_INIT = 0xFFFFFFFF;

}
  • FLASH CRC运行自检实现部分:
/*******************************************************************************

 * [url=home.php?mod=space&uid=247401]@brief[/url]       

 * @param       

 * @retval      

 * [url=home.php?mod=space&uid=93590]@Attention[/url]   

*******************************************************************************/

void CLASSB_FLASH_Running(void)

{

    static uint32_t Address = CLASSB_FLASH_START;



    uint32_t StartAddress = 0, EndAddress = 0;



    if(Address < CLASSB_FLASH_END)

    {

        if((Address + CLASSB_FLASH_SECTOR_SIZE) < CLASSB_FLASH_END)

        {

            StartAddress = Address;

            EndAddress   = Address + CLASSB_FLASH_SECTOR_SIZE;

        }

        else

        {

            StartAddress = Address;

            EndAddress   = CLASSB_FLASH_END;

        }



        for(uint32_t i = StartAddress; i < EndAddress; i += 4)

        {

            REG32(&CRC_DR) = *((uint32_t *)(i));

        }



        Address += CLASSB_FLASH_SECTOR_SIZE;

    }

    else

    {

        if(((REG32(&CRC_DR)) ^ 0x00000000) == __Check_Sum)

        {

            printf("\r\nFlash CRC Correct!");

        }

        else

        {

            printf("\r\nFlash CRC Error!!!");

        }



        CLASSB_FALSH_InitCRC();



        Address = CLASSB_FLASH_START;

    }

}
  • FLASH CRC运行自检调用部分:

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


看门狗自检
在SYS_RST_SRC寄存器中标注了系统不同复位源的标识,其中BIT3为看门狗复位标识,我通过这个标识来判断当前系统是正常的上电复位,还是看门狗复位;以此来实现看门狗的启动自检和运行,具体实现如下:

  • 看门狗的初始化、喂狗、周期性喂狗:
/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void WDT_Feed(uint32_t TimeOut)

{

    SYS_WR_PROTECT = 0xCAFE;



    switch(TimeOut)

    {

        case SYS_WD_TimeOut2s  : SYS_WDT_CLR = 0x798F; break;

        case SYS_WD_TimeOut4s  : SYS_WDT_CLR = 0x798D; break;

        case SYS_WD_TimeOut8s  : SYS_WDT_CLR = 0x798B; break;

        case SYS_WD_TimeOut64s : SYS_WDT_CLR = 0x7989; break;

        default : break;

    }



    SYS_WR_PROTECT = 0;

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void WDT_Init(void)

{

    uint32_t REG_TEMP = SYS_RST_CFG;



    SYS_WR_PROTECT = 0x7A83;



    REG_TEMP |= BIT0;



    SYS_RST_CFG = REG_TEMP;

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void WDT_MultiTimerCallback(MultiTimer *timer, void *userData)

{

    WDT_Feed(SYS_WD_TimeOut2s);



    MultiTimerStart(&WDT_MultiTimer, 250, WDT_MultiTimerCallback, "WDT");

}
  • 看门启动自检实现部分:
    if(SYS_RST_SRC & BIT3)

    {

        printf("\r\n-----------------");

        printf("\r\nWDT Reset Test OK\r\n");

        printf("-----------------\r\n");



        MultiTimerStart(&WDT_MultiTimer, 250, WDT_MultiTimerCallback, "WDT");

    }

    else

    {

        WDT_Init();

        WDT_Feed(SYS_WD_TimeOut2s); while(1);

    }
  • 看门狗运行部分:

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


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

  • 在startup_lks32mc08x.s文件中定义堆栈的大小:
Stack_Size      EQU     0x00000300



                AREA    STACK, NOINIT, READWRITE, ALIGN=3

Stack_Mem       SPACE   Stack_Size

__initial_sp





; <h> Heap Configuration

;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>

; </h>



Heap_Size       EQU     0x00000200



                AREA    HEAP, NOINIT, READWRITE, ALIGN=3

__heap_base

Heap_Mem        SPACE   Heap_Size

__heap_limit
  • 在ClassB_LKS32MC08x.sct文件中手动规划RAM区域功能,并定义STACK_BOTTOM:
; *************************************************************

; *** Scatter-Loading Description File generated by uVision ***

; *************************************************************



LR_IROM1 0x00000000 0x00010000  {    ; load region size_region

  ER_IROM1 0x00000000 0x00010000  {  ; load address = execution address

   *.o (RESET, +First)

   *(InRoot$Sections)

   .ANY (+RO)

   .ANY (+XO)

   *.o (CHECKSUM, +Last)

  }

  RW_IRAM1 0x20000000 0x00001B00  {  ; RW data

   .ANY (+RW +ZI)

  }

  STACK_NO_HEAP 0x20001B00 UNINIT 0x500

  {

    main.o               (STACK_BOTTOM)

    startup_lks32mc08x.o (STACK, +Last)

  }

}



  • 定义堆栈溢出检测的数组:
/* Private macro -------------------------------------------------------------*/

volatile uint32_t aStackOverFlowPtrn[4] __attribute__((section("STACK_BOTTOM"), zero_init));

  • 给堆栈溢出检测数组的成员变量赋值,并打印地址、数值对应信息:
    aStackOverFlowPtrn[0] = 0xEEEEEEEEuL;

    aStackOverFlowPtrn[1] = 0xCCCCCCCCuL;

    aStackOverFlowPtrn[2] = 0xBBBBBBBBuL;

    aStackOverFlowPtrn[3] = 0xDDDDDDDDuL;



    printf("\r\n");

    printf("\r\n0x%08x : 0x%08x", &aStackOverFlowPtrn[0], aStackOverFlowPtrn[0]);

    printf("\r\n0x%08x : 0x%08x", &aStackOverFlowPtrn[1], aStackOverFlowPtrn[1]);

    printf("\r\n0x%08x : 0x%08x", &aStackOverFlowPtrn[2], aStackOverFlowPtrn[2]);

    printf("\r\n0x%08x : 0x%08x", &aStackOverFlowPtrn[3], aStackOverFlowPtrn[3]);

    printf("\r\n");
  • 堆栈溢出运行检测:
/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void CLASSB_CheckStackOverflow(void)

{

    if(aStackOverFlowPtrn[0] != 0xEEEEEEEEuL)

    {

        printf("\r\n%s[%d] : ERROR!", __FUNCTION__, __LINE__);

    }



    if(aStackOverFlowPtrn[1] != 0xCCCCCCCCuL)

    {

        printf("\r\n%s[%d] : ERROR!", __FUNCTION__, __LINE__);

    }



    if(aStackOverFlowPtrn[2] != 0xBBBBBBBBuL)

    {

        printf("\r\n%s[%d] : ERROR!", __FUNCTION__, __LINE__);

    }



    if(aStackOverFlowPtrn[3] != 0xDDDDDDDDuL)

    {

        printf("\r\n%s[%d] : ERROR!", __FUNCTION__, __LINE__);

    }

}



运行结果

---------------------
作者:GrandLine
链接:https://bbs.21ic.com/icview-3255152-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值