嵌入式 MCU 的 Class B 安全功能实现

打印 上一主题 下一主题

主题 921|帖子 921|积分 2763

前言

在家用电器及类似电气控制设备的筹划和制造中,安全性始终是至关重要的。全球标准化机构,如国际电工委员会(IEC)、美国保险商实行室(UL)和加拿大标准协会(CSA),制定了相关安全标准,以确保电器的可靠性和安全性。其中,IEC60730 标准为电器设备的自动控制系统提供了一套全面的规范,旨在确保设备在各种使用场景中的安全性、可靠性和性能。尽管该标准最初主要针对家用电器,如洗衣机、冰箱和烤箱,但其应用范围已经扩展到商业和某些工业设备。如今,TUV、VDE(主要在欧洲)、UL及CSA(主要在美国和加拿大)等机构均认可并要求在认证过程中应用这一标准。
IEC60730 标准的 A、B、C三类功能

IEC60730 标准界说了A、B、C三类功能,分别关注于设备的使用便利性、安全性和特殊伤害防备。这些分类帮助筹划人员确保设备在各种操纵条件下能够安全可靠地运行,为用户提供了更高的操纵安全和舒适体验。


  • A类功能是指那些用于一样寻常自动控制目标的设备,这些设备的主要目标是进步使用便利性和效率,而不直接涉及到设备的根本安全保障。A类功能的筹划通常关注设备的操纵舒适性和用户友好性。如智能家居系统中的智能灯光控制,可以通过定时器或传感器自动调节室内灯光。家用洗衣机的洗涤步伐控制提供选择差异的洗涤模式,如快速洗、节能洗等。
  • B类功能是指那些直接涉及到设备安全的自动控制功能。这些功能的主要目标是防止设备在使用过程中出现大概导致用户受伤或设备破坏的情况。好比烤箱或电热水壶的热堵截装置,防止烤箱或电热水壶等设备过热,当温度超过设定值时自动堵截电源,以避免火灾或设备破坏。
  • C类功能是指那些用于防止特殊伤害、或更高风险的自动控制功能,特别是在大概出现爆炸、火灾等严重事故的环境中。如热水器的压力保护装置,实时监控热水器内部的压力,防止因压力过高而导致的爆炸或水箱破坏。电动窗帘的安全装置,在窗帘起落过程中,如果感应到停滞物,自动停止或反向操纵以防止夹伤等等。
IEC60730 标准认证对软硬件的要求

Class A、B 和 C 等级反映了对设备安全性、可靠性和错误处置惩罚本领的差异要求。Class A 认证实用于那些对安全性和可靠性要求较低的设备,Class B 认证针对的是那些需要较高安全性但不如 Class C 严格的自动电气控制装置,Class C 的要求比 Class B 更高,涵盖了更广泛的安全性和可靠性方面,确保设备在更苛刻的环境下也能稳固、安全地运行。
Class A:


  • 硬件要求:底子的电气安全和机械强度,主要确保设备在正常条件下的稳固运行。
  • 软件要求:实现根本功能并提供用户友好的操纵界面。错误检测和恢复本领要求较低,关注点在于操纵的轻便性和根本功能的实现。
  • 安全上的要求主要看硬件筹划,软件正常业务通常足以满足要求。
Class B:


  • 硬件要求:提升了电气安全性,要求更高的耐用性和抗干扰本领。

    • 绝缘和保护:必须确保设备的绝缘筹划满足安全标准,以防电气冲击和短路。
    • 机械强度:硬件应具备充足的机械强度,能抵御正常使用中的物理压力或碰撞。
    • 组件需经得起长期使用中的磨损和老化,确保长期的安全运行。
    • 必须符合电气安全标准,如电气绝缘、电气间隙等要求,避免出现过热或短路问题。
    • 硬件筹划需考虑电磁兼容性(EMC),避免或减轻电磁干扰(EMI)对设备功能的影响。

  • 软件要求:要求较高的错误检测和恢复本领,致力于实现高水平的功能安全和长期可靠性。

    • 软件筹划需要满足功能安全要求,包括对故障条件的处置惩罚本领和错误检测机制。
    • 应用步伐应能有效处置惩罚意外的操纵错误,避免因软件故障导致的安全问题。

  • 安全上的要求除了看硬件筹划,还要考虑硬件失效后软件的保护,以及软件的周期性自检以包管软件保护功能能正常起作用。
Class C:


  • 硬件要求:重点在于特殊伤害防备,要求额外的防护步伐,以应对潜在的特殊风险,如高温、高湿等。
  • 软件要求:针对特殊伤害情境的软件处置惩罚,如应对极度条件下的功能失效。实现额外的错误处置惩罚和防备机制,确保在特殊情况下仍能保持功能安全。
  • 无论硬件筹划还是软件筹划,都要提供更多重的保护机制,好比软硬件的一重保护失效后,有第二重保护防范。
Class B 安全功能筹划

在嵌入式设备的筹划中,安全功能的界说往往是基于特定业务场景而拆分出来的,这种方法通常满足了开端的安全需求,例如移动机器人,机器人在自动导航时遇到停滞物(如人)会立刻停止,这一功能是符合根本的安全要求的。然而,这种基于业务场景的安全界说通常只是一个出发点,它并未考虑到更深条理的问题和潜在的安全隐患。例如,如果机器人的雷达传感器发生故障,导致其无法正确感应到停滞物,大概控制机器移动的轮毂失控,那么本来筹划良好的安全功能就会失效。这种问题的存在说明,安全功能的筹划不仅需要关注单一场景的准确实现,还必须在系统层面上考虑到各种大概的故障模式和失效情况。
为应对这些复杂的安全挑衅,需要从更高级别的认证标准(如Class B)出发,细化安全功能的分类,以全面覆盖潜在的故障模式和风险。
例如,MCU(微控制单元)自检功能可以确保处置惩罚器在正常工作状态下进行自我监测,从而包管系统的稳固性。同时,通讯检测功能能够确保当雷达检测到停滞物时,相关的控制指令(如轮毂停止)能够实时且正确地传递。轮毂的编码器检测,能够确保轮毂真实地移动或停止等等,这些步伐帮助确保在复杂或异常情况下,系统的安全功能仍能有效地保护人身安全。
详细来说,我们可以从以下方面实现安全功能:
安全功能说明CPU 寄存器自检包括 R13(栈指针)、R14(链接寄存器)和 PSP(历程栈指针)PC步伐计数器防止步伐计数器丢失或终止看门狗自检避免出现复位时间太快、太慢或卡滞不工作的情况非易失性存储器完备性检查主要是 FLASH,避免目标 FLASH 区域被修改或破坏易失性存储器检查主要是 RAM,检查 RAM 是否可正常读写系统时钟频率检查检查外部输入时钟源是否正确IO 外设检查涉及安全功能的输入输出信号,如限位传感器信号、PWM 脉冲信号ADC 检查涉及安全功能的模拟信号量,如温度、电压、电流中断检查避免中断频率过高或过低或无中断响应通讯检查涉及安全功能的通讯,如基于 SPI、UART、CAN 通讯的轮毂电机控制 安全功能软件库

在现实开发中,部分 MCU 厂商会提供符合认证要求的安全功能包,以便用户快速实现 MCU 功能自检。例如,STM32 的 STL 软件包。

经过认证的 STM32 STL 固件包由下列软件模块组成:
• CPU寄存器测试
• 系统时钟监控
• RAM功能检查
• Flash CRC完备性检查
• 看门狗自检
• 栈上溢监控
借助厂商提供的安全功能固件包,我们可以针对性地开发自检步伐,从而加快认证过程。
启动自检与运行自检

在复位微控制器后,首次检查应包括在初始化阶段运行启动自检。这一过程在应用业务尚未启动之前,对 MCU 相关组件(CPU寄存器、看门狗、Flash完备性、RAM功能、系统时钟)进行全面的检测,确保系统的底子功能都处于最佳状态。
启动自检结构:

运行时测试是在主循环中定期执行的测试块。除了包罗 MCU 启动自检相关的测试(其中部分启动自检功能大概在运行时检测时会简化),还应包括应用业务中的安全功能相关测试。这些测试应涵盖与安全功能相关的 IO、ADC、中断、通讯等模块,以确保这些功能在运行期间的准确性和可靠性。
运行时自检结构:

CPU 寄存器自检

CPU启动自检检查内核标记、寄存器和栈指针的准确功能。如果发现任何错误,应进行故障
处置惩罚并上报异常。
详细实现:从 ACC 寄存器开始,用 0x55、0xAA分别填充全部 CPU 寄存器(大概引起 CPU 工作异常的特殊寄存器除外),再读出对比,测试读写是否正常。

以下是ST提供的部分CPU自检代码:
  1.   /********************/
  2.   /* CPU Test modules */
  3.   /********************/
  4. #ifdef ARTI_FAILING_CPU_TM
  5.   /* Artificial failing feature -
  6.      when activated, it forces the STL outputs to predefined values */
  7.   ArtifFailing.aCpuTmStatus[0] = STL_PASSED;
  8.   ArtifFailing.aCpuTmStatus[1] = STL_PASSED;
  9.   ArtifFailing.aCpuTmStatus[2] = STL_FAILED;
  10.   STL_SCH_StartArtifFailing(&ArtifFailing);
  11. #endif /* ARTI_FAILING_CPU_TM */
  12.   /* CPU TM1L */
  13.   if (STL_SCH_RunCpuTM1L(&StlCpuTm1LStatus) != STL_OK)
  14.   {
  15.     FailSafe_Handler(TM1L_ERR_CODE + DEF_PROG_OFFSET);
  16.   }
  17.   if (StlCpuTm1LStatus != STL_PASSED)
  18.   {
  19.     FailSafe_Handler(TM1L_ERR_CODE);
  20.   }
  21.   /* CPU TM7 */
  22.   if (STL_SCH_RunCpuTM7(&StlCpuTm7Status) != STL_OK)
  23.   {
  24.     FailSafe_Handler(TM7_ERR_CODE + DEF_PROG_OFFSET);
  25.   }
  26.   if (StlCpuTm7Status != STL_PASSED)
  27.   {
  28.     FailSafe_Handler(TM7_ERR_CODE);
  29.   }
  30.   /* CPU TMCB */
  31.   if (STL_SCH_RunCpuTMCB(&StlCpuTmCBStatus) != STL_OK)
  32.   {
  33.     FailSafe_Handler(TMCB_ERR_CODE + DEF_PROG_OFFSET);
  34.   }
  35.   if (StlCpuTmCBStatus != STL_PASSED)
  36.   {
  37.     FailSafe_Handler(TMCB_ERR_CODE);
  38.   }
  39. #ifdef ARTI_FAILING_CPU_TM
  40.   STL_SCH_StopArtifFailing();
  41. #endif /* ARTI_FAILING_CPU_TM */
复制代码
看门狗启动自检

看门狗自检基于复位状态寄存器内容,差异的复位原因会有相应的寄存器标记。在系统正常上电时,IWDG 和 WWDG 都应处于未触发状态。起首进行 IWDG 的复位测试,将 IWDG 设置为最短复位周期,扫除所有复位标记后,进入等待状态。经过设定时间后,IWDG 应触发系统复位。复位重启后,IWDG 标记应被设置,并且应该是唯一的复位原因,否则需扫除所有复位标记并重新开始检测。随后进行 WWDG 测试,将 WWDG 设置为最短复位周期,等待系统再次触发复位,复位重启后,IWDG 和 WWDG 寄存器标记均被设置时,测试才算通过,否则需扫除所有复位标记并重新开始检测。测试通过后记得扫除所有复位标记。

以下是ST提供的看门狗自检代码:
  1. /******************************************************************************/
  2. /**
  3.   * @brief  Verifies the watchdog by forcing watchdog resets
  4.   * @param  : None
  5.   * @retval : None
  6.   */
  7. void STL_WDGSelfTest(void)
  8. {
  9.   /* ==============================================================================*/
  10.   /* MISRA violation of rule 12.4 - side effect of && and || operators ignored */
  11.   #ifdef __IAR_SYSTEMS_ICC__  /* IAR Compiler */
  12.     #pragma diag_suppress=Pm026
  13.   #endif /* __IAR_SYSTEMS_ICC__ */
  14.   #ifdef STL_VERBOSE_POR  
  15.     if (__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST)  != RESET) printf("Pin reset \r\n");
  16.     if (__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST)  != RESET) printf("POR reset \r\n");
  17.     if (__HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST)  != RESET) printf("SW reset \r\n");
  18.     if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST) != RESET) printf("IWDG reset \r\n");
  19.     if (__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST) != RESET) printf("WWDG reset \r\n");
  20.     if (__HAL_RCC_GET_FLAG(RCC_FLAG_LPWRRST) != RESET) printf("LP reset \r\n");
  21.   #endif /* STL_VERBOSE_POR */
  22.   /* start watchdogs test if one of the 4 conditions below is valid */
  23.   if ( (__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST) != RESET)\
  24.    ||  (__HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST) != RESET)\
  25.    ||  (__HAL_RCC_GET_FLAG(RCC_FLAG_LPWRRST) != RESET)\
  26.    || ((__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST) != RESET) && (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST) == RESET) && (__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST) == RESET)))
  27.   {
  28.     #ifdef STL_VERBOSE_POR
  29.       printf("... Power-on or software reset, testing IWDG ... \r\n");
  30.     #endif  /* STL_VERBOSE_POR */
  31.     #if defined(STL_EVAL_MODE)
  32.       /* IWDG at debug mode */
  33.       __DBGMCU_CLK_ENABLE();
  34.       __DBGMCU_FREEZE_IWDG();
  35.     #endif  /* STL_EVAL_MODE */
  36.     /* Clear all flags before resuming test */
  37.     __HAL_RCC_CLEAR_FLAG();
  38.     /* Setup IWDG to minimum period */
  39.     IwdgHandle.Instance = IWDG;
  40.     IwdgHandle.Init.Prescaler = IWDG_PRESCALER_4;
  41.     IwdgHandle.Init.Reload = 1U;
  42.     #ifdef IWDG_FEATURES_BY_WINDOW_OPTION
  43.       IwdgHandle.Init.Window = IWDG_WINDOW_DISABLE;
  44.     #endif /* IWDG_FEATURES_BY_WINDOW_OPTION */
  45.     /* Initialization */
  46.     HAL_IWDG_Init(&IwdgHandle);
  47.     /* Wait for an independent watchdog reset */
  48.     while(1)
  49.     { }
  50.   }
  51.   else  /* Watchdog test or software reset triggered by application failure */
  52.   {
  53.     /* If WWDG only was set, re-start the complete test (indicates a reset triggered by safety routines */
  54.     if ((__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST)  != RESET) && (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST) == RESET) && (__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST) != RESET))
  55.     {
  56.       __HAL_RCC_CLEAR_FLAG();
  57.       #ifdef STL_VERBOSE_POR
  58.         printf("... WWDG reset, re-start WDG test ... \r\n");
  59.       #endif  /* STL_VERBOSE_POR */
  60.       NVIC_SystemReset();
  61.     }
  62.     else  /* If IWDG only was set, continue the test with WWDG test*/
  63.     {
  64.       if ((__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST)  != RESET) && (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST) != RESET) && (__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST) == RESET))
  65.       { /* If IWDG only was set, test WWDG*/
  66.         #ifdef STL_VERBOSE_POR
  67.           printf("... IWDG reset from test or application, testing WWDG\r\n");
  68.         #endif  /* STL_VERBOSE_POR */
  69.          
  70.         #if defined(STL_EVAL_MODE)
  71.           /* WWDG at debug mode */
  72.           __DBGMCU_CLK_ENABLE();
  73.           __DBGMCU_FREEZE_WWDG();
  74.         #endif  /* STL_EVAL_MODE */
  75.          
  76.          /* Setup WWDG to minimum period */
  77.         __WWDG_CLK_ENABLE();
  78.         WwdgHandle.Instance = WWDG;
  79.         WwdgHandle.Init.Prescaler = WWDG_PRESCALER_1;
  80.         WwdgHandle.Init.Counter = 64U;
  81.         WwdgHandle.Init.Window = 63U;
  82.         WwdgHandle.Init.EWIMode = WWDG_EWI_DISABLE;
  83.         HAL_WWDG_Init(&WwdgHandle);
  84.         while(1)
  85.         { }
  86.       }
  87.       else  /* If both flags IWDG & WWDG flags are set, means that watchdog test is completed */
  88.       {
  89.         if ((__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST)  != RESET) && (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST) != RESET) && (__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST) != RESET))
  90.         {
  91.           __HAL_RCC_CLEAR_FLAG();
  92.           #ifdef STL_VERBOSE_POR
  93.             printf("... WWDG reset, WDG test completed ... \r\n");
  94.           #endif  /* STL_VERBOSE_POR */
  95.         }
  96.         else  /* Unexpected Flag configuration, re-start WDG test */
  97.         {
  98.           __HAL_RCC_CLEAR_FLAG();
  99.           #ifdef STL_VERBOSE_POR
  100.             printf("...Unexpected Flag configuration, re-start WDG test... \r\n");
  101.           #endif  /* STL_VERBOSE_POR */
  102.         NVIC_SystemReset();
  103.         } /* End of Unexpected Flag configuration */
  104.       } /* End of normal test sequence */
  105.     } /* End of partial WDG test (IWDG test done) */
  106.   } /* End of part where 1 or 2 Watchdog flags are set */
  107.   #ifdef __IAR_SYSTEMS_ICC__  /* IAR Compiler */
  108.     #pragma diag_default=Pm026
  109.   #endif /* __IAR_SYSTEMS_ICC__ */
  110.   /* ==============================================================================*/
  111. }
复制代码
Flash存储器完备校验和自检

ST 的 Flash 自检主要是通过在编译时盘算 bin 文件整个用户区 FLASH 的 CRC 校验值,并通过 ST 提供的 CRC 预盘算工具 STM32CubeProgrammer 存储在 bin 文件用户区 Flash 末端所在位置,然后烧录进芯片 Flash。


  • 步伐刚启动时,用同样的算法重新盘算整个 FLASH 的 CRC 校验值(不包括前面存储在 FLASH 末端位置的 CRC 校验值),并与存储在 FLASH 中的 CRC 校验值做比力。
  • 在运行过程周期检测时,则是对 FLASH 分块逐次盘算出最终的 CRC 校验值;将最终结果与准确的CRC 校验值做比力。

以下是ST提供的部分Flash启动自检代码:
  1. /*********************/
  2.   /* FLASH Test Module */
  3.   /*********************/
  4. #ifdef ARTI_FAILING_FLASH_TM
  5.     /* forced STL_FAILED status simulates the TM configuration error and
  6.        STL_NOT_TESTED status simulates TM run error */
  7.     ArtifFailing.FlashTmStatus = STL_FAILED;
  8.   STL_SCH_StartArtifFailing(&ArtifFailing);
  9. #endif /* ARTI_FAILING_FLASH_TM */
  10.   /* The following configuration tests the entire program in the flash, in one shot */
  11.   STL_MemSubset_t FlashSubsetFullTest = {
  12.       .StartAddr = TEST_ROM_START_ADDR,
  13.       .EndAddr   = TEST_ROM_END_ADDR,
  14.       .pNext     = NULL
  15.   };
  16.   STL_MemConfig_t FlashConfigFullTest = {
  17.       .NumSectionsAtomic = UINT32_MAX,
  18.       .pSubset           = &FlashSubsetFullTest
  19.   };
  20.   if (STL_SCH_InitFlash(&StlFlashStatus) != STL_OK)
  21.   {
  22.     FailSafe_Handler(TMF_ERR_CODE + DEF_PROG_OFFSET);
  23.   }
  24.   if (STL_SCH_ConfigureFlash(&StlFlashStatus, &FlashConfigFullTest) != STL_OK)
  25.   {
  26.     FailSafe_Handler(TMF_ERR_CODE + DEF_PROG_OFFSET);
  27.   }
  28.   else if (StlFlashStatus != STL_NOT_TESTED)
  29.   {
  30.     FailSafe_Handler(TMF_ERR_CODE);
  31.   }
  32.   if (STL_SCH_RunFlashTM(&StlFlashStatus) != STL_OK)
  33.   {
  34.     FailSafe_Handler(TMF_ERR_CODE + DEF_PROG_OFFSET);
  35.   }
  36.   else if (StlFlashStatus != STL_PASSED){
  37.     FailSafe_Handler(TMF_ERR_CODE);
  38.   }
  39.   StlFlashStatus = STL_NOT_TESTED;
  40. #ifdef ARTI_FAILING_FLASH_TM
  41.   STL_SCH_StopArtifFailing();
  42. #endif /* ARTI_FAILING_FLASH_TM */
复制代码
运行时 Flash 分块逐步盘算获取最终 CRC,与启动时盘算整个 Flash CRC 的区别在于 盘算区域NumSectionsAtomic 设定为每次 1KB 而不是最大值 UINT32_MAX。
  1.   /* FLASH test Config
  2.      *****************
  3.      In this example, single continuous area (subset) is tested under unique configuration setting.
  4.      User can apply wider set of subsets tested sequentially to cover separated memory areas
  5.      as well as different configurations to be applied for selected subset(s) - see UM */
  6.   FlashSubsetRunTime.StartAddr = TEST_ROM_START_ADDR;
  7.   FlashSubsetRunTime.EndAddr = TEST_ROM_END_ADDR;
  8.   FlashSubsetRunTime.pNext = NULL;
  9.   FlashConfigRunTime.pSubset = &FlashSubsetRunTime;
  10.   FlashConfigRunTime.NumSectionsAtomic = 1; /* split test into sections of 1kB */
复制代码
完备 RAM March-C自检

RAM自检接纳 March-C 算法,为了不影响 MCU 的运行,将 RAM 分成很多小块,每次测试其中一块, 先将要测试的块清零,然后按位逐位置1,每置一位,测试该位是不是1,是就继承,不是就报错;全部置完后,再逐位清0,每清一个位,测试该位清0是不是0,如果是就准确,不是就报错。如果是对工作区的 RAM,数据需要保留,需要在 RAM 中开一个安全保留区(好比一块4字节大小的安全区域),先对安全保留区 March C,然后把要测试的区的数据复制进安全区,再对要测试的工作区进行 March-C,测试-- 复制进安全区-- 测试–复制进安全区… 完成整个空间的测试。
RAM自检也分为启动自检和运行自检两部分:


  • RAM 在启动自检的过程中会检测全部的 RAM。在下图所示的 6个循环中,March-C 算法会瓜代检查整个RAM空间,并用配景模式(值0x00000000)和反向配景模式(值0xFFFFFFFF)逐字填充。前三个循环按所在的递增次序执行,后三个循环按相反的次序执行。填充后读取出来比力看值是否相称。
  • RAM 在运行自检的过程中只检测部分 RAM,也就是局部分块分多步检测,每个测试的内存块都始终与测试上一步和下一步的两个附加的相邻字重叠。目前主要检测现实使用区域范围内的 RAM。

以下是ST提供的部分RAM启动自检代码:
  1. /********************/
  2.   /* RAM Test module  */
  3.   /********************/
  4. #ifdef ARTI_FAILING_RAM_TM
  5.     /* forced STL_FAILED status simulates the TM configuration error and
  6.        STL_NOT_TESTED status simulates TM run error */
  7.     ArtifFailing.RamTmStatus = STL_FAILED;
  8.   STL_SCH_StartArtifFailing(&ArtifFailing);
  9. #endif /* ARTI_FAILING_RAM_TM */
  10.   /* The following configuration tests the entire user-defined range of RAM at once */
  11.   STL_MemSubset_t RamSubsetFullTest = {
  12.       .StartAddr = TEST_RAM_START_ADDR,
  13.       .EndAddr   = TEST_RAM_END_ADDR_FULL,
  14.       .pNext     = NULL
  15.   };
  16.   STL_MemConfig_t RamConfigFullTest = {
  17.       .NumSectionsAtomic = UINT32_MAX,
  18.       .pSubset = &RamSubsetFullTest
  19.   };
  20.   if (STL_SCH_InitRam(&StlRamStatus) != STL_OK)
  21.   {
  22.     FailSafe_Handler(TMR_ERR_CODE + DEF_PROG_OFFSET);
  23.   }
  24.   if (STL_SCH_ConfigureRam(&StlRamStatus, &RamConfigFullTest) != STL_OK)
  25.   {
  26.     FailSafe_Handler(TMR_ERR_CODE + DEF_PROG_OFFSET);
  27.   }
  28.   else if (StlRamStatus != STL_NOT_TESTED)
  29.   {
  30.     FailSafe_Handler(TMR_ERR_CODE);
  31.   }
  32.   if (STL_SCH_RunRamTM(&StlRamStatus) != STL_OK)
  33.   {
  34.     FailSafe_Handler(TMR_ERR_CODE + DEF_PROG_OFFSET);
  35.   }
  36.   else if (StlRamStatus != STL_PASSED)
  37.   {
  38.     FailSafe_Handler(TMR_ERR_CODE);
  39.   }
  40.   StlRamStatus = STL_NOT_TESTED;
  41. #ifdef ARTI_FAILING_RAM_TM
  42.   STL_SCH_StopArtifFailing();
  43. #endif /* ARTI_FAILING_RAM_TM */
复制代码
运行时 RAM 分块测试 RAM 区域,与启动时检测整个 RAM 的区别在于检测区域 NumSectionsAtomic 设定为每次128字节而不是最大值 UINT32_MAX。
  1.    /* RAM test Config
  2.      ***************
  3.      In this example, single continuous area (subset) is tested under unique configuration setting.
  4.      User can apply wider set of subsets tested sequentially to cover separated memory areas
  5.      as well as different configurations to be applied for selected subset(s) - see UM */
  6.   RamSubsetRunTime.StartAddr = TEST_RAM_START_ADDR;
  7.   RamSubsetRunTime.EndAddr = TEST_RAM_START_ADDR + TEST_RAM_SECTION_NB_RUN * RAM_SECTION_SIZE - 1;
  8.   RamSubsetRunTime.pNext = NULL;
  9.   RamConfigRunTime.pSubset = &RamSubsetRunTime;
  10.   RamConfigRunTime.NumSectionsAtomic = 1; /* split test into sections of 128 bytes */
  11.   /* RamConfig.NumSectionsAtomic = (2 * TEST_RAM_SECTION_NB);  */  /* - use this setting for one shot */
复制代码
时钟自检

时钟自检的检测方法是接纳两个独立时钟源交错检查来进行测量,一个已知的时钟源做为定时器时钟输入,另一个被测试的时钟源做为定时器的外部捕获通道输入源。
例如,使用内部低速RC振荡器时基LSI (32.768KHz)可检测外部晶振(HSE)的频率是否准确。根据定时器时钟频率 LSI 和定时器脉冲捕获计数,盘算出捕获通道输入信号 HSE 的现实频率。接着测试检查 HSE 率是否在预期范围内(标称值的±25%),如果发现差异较大或 HSE 信号丢失,或测量中断消散,则 CPU 时钟源会立刻切换回 HIS 且 HSE 返回故障状态,否则,测试返回至正常状态。

以下是ST提供的 Clock 自检代码:
  1. /* Value of the system clock frequency at run time in Hz */
  2. #define SYSTCLK_AT_RUN (uint32_t)(64000000uL)
  3. /* Value of the Internal LSI oscillator in Hz */
  4. #define LSI_Freq    ((uint32_t)32000uL)
  5. /* CLK frequency above this limit considered as harmonics at case of HSE */
  6. #define CLK_LimitHigh(fcy) ((uint32_t)(((fcy)/LSI_Freq)*8u*5u)/4u) /* (Value + 25%) */
  7. /* CLK frequency below this limit considered as sub-harmonics at case of HSE */
  8. #define CLK_LimitLow(fcy) ((uint32_t)(((fcy)/LSI_Freq)*8u*3u)/4u)  /* (Value - 25%) */
  9. /* if SYSCK is derived from HSI, the upper fixed clock limits can be set more severe
  10.    e.g., ...*8u*6u)/5 resp ...*8u*4u)/5 (~ value +/- 20%) but such a severe restriction
  11.    can require including some adaptive flow to compensate possible temperature drift
  12.    of HSI by making acceptable window defined by these limits variable in time */
  13. /**
  14.   * @brief  Verification result of the cross check frequencies process
  15.   * @param  : None
  16.   * @retval : None
  17.   */
  18. STL_Status_t STL_RunClockTest(STL_TmStatus_t *clk_sts)
  19. {
  20.   STL_Status_t tst_res;
  21.   
  22.   *clk_sts = STL_PARTIAL_PASSED;
  23.   /* next line can produce compilation warning due to accessing of two volatile
  24.      variables making single result value integrity pair. The pair is changed
  25.      simultaneously exclusively at TIM16 IRQ and its integrity is verified here
  26.      before the clock measurement is compared if it fits within expected range */
  27.   if (((PeriodValue ^ PeriodValueInv) == 0xFFFFFFFFuL)\
  28.   &&   (LSIPeriodFlag == 0xAAAA5555u) )
  29.   {
  30.   #ifndef ARTI_FAILING_CLK_TM
  31.     *clk_sts = STL_PASSED;
  32.     if (PeriodValue < CLK_LimitLow(SYSTCLK_AT_RUN))
  33.     {
  34.       *clk_sts = STL_FAILED;        /* Sub-harmonics: HSE -25% below expected */
  35.     }
  36.     if (PeriodValue > CLK_LimitHigh(SYSTCLK_AT_RUN))
  37.     {
  38.       *clk_sts = STL_FAILED;        /* Harmonics: HSE +25% above expected */
  39.     }
  40.   #else
  41.     *clk_sts = STL_FAILED;
  42.   #endif /* ARTI_FAILING_CLK_TM */
  43.    
  44.     /* clear flag here to ensure refreshed LSI measurement result will be taken at next check */
  45.     LSIPeriodFlag = 0u;
  46.     tst_res = STL_OK;
  47.   }
  48.   else
  49.   {
  50.     tst_res = STL_KO; /* Clock measurement flow error */
  51.   }
  52.   return(tst_res);
  53. }
复制代码
中断检测

中断检测的主要目标是监测中断的频率是否正常。由于中断的发生具有随机性,监测大概会比力复杂,因此需要联合现实业务场景进行分析。以下是一些参考思路:


  • 对于定时中断和 MCU 主动触发的中断,如定时器中断、ADC 转换完成中断、串口/CAN 发送中断等。可以为每种中断界说一个独立的计数器,用于记载每种中断的发生次数。然后,在一个独立的时钟周期性中断中,检查这些中断的计数值,以判断是否存在频仍中断或无中断的异常情况。
  • 对于外部信号触发的中断,如PWM 捕获中断、GPIO 捕获中断、串口/CAN 吸收中断等。可以通过检查现实业务功能的正常性来间接检测中断。例如:对于用于检测电机转速的 PWM 捕获中断,可以设定电机目标转速,并与现实捕获的转速进行比力。如果现实转速与目标转速不符,大概表明从输入信号到中断处置惩罚的整个环节存在问题。对于传感器的串口吸收中断,可以根据传感器数据的吸收帧率来判断。如果帧率不符合预期,大概表明串口吸收中断处置惩罚存在问题。
这些方法可以帮助我们更有效地监测中断的正常性,并实时发现潜在的异常情况。
IO 检测

IO 检测主要目标是监测 IO 引脚是否可以拉高拉低,如果是模拟 IO 的输入,可以和 ADC 配合检测。


  • 对于数字 I/O,选用适当的 I/O,输出 0/1,再检查 I/O 状态是否正常,以及 I/O 与电源之间是否有短路或开路。对大概会导致伤害的关键信号引脚,可以用冗余输入引脚检查信号状态是否正常。
  • 对于模拟 I/O,可以输入一个恒定电压,用 AD 转换,检查转换值是否在可接受的较小范围内。
固然,在现实应用中,这种测试大概会影响业务的正常运转。因此,我们也可以通过检测现实业务功能的正常性来间接检测 IO 状态。例如:


  • 当加热(大概制冷)控制引脚打开(大概关闭)时,应该检查温度传感器的模拟信号变化是否正常。
  • 对于电机的方向控制引脚,如果电机配备了相应的到位传感器或编码器组件,我们可以使用这些传感器和编码器的反馈来判断方向引脚的设置是否准确。需要注意的是,这些传感器和编码器自己也需要进行自检,以确保它们的功能正常。因此,涉及安全功能的业务通常由多个组件协同工作,这种方法不仅能检测单个组件的状态,还能反映各组件之间的协作是否顺畅。
ADC检测

对于ADC的检测,为了验证 ADC 的准确性,可以使用多路 ADC 监控同一输入信号源。


  • 好比通过在硬件上复用信号源,使用多个ADC通道,或在同一引脚上分别使用多个 ADC(例如 ADC1 和 ADC2)检测相互验证。
  • 固然,也可以检测现实业务功能的正常性来验证ADC,如模拟信号采样转换过来的电压、电流、温度是否处于在正常范围内,并且变化规律符合预期。
通讯检测

为确保通讯数据交换的准确性,可以通过参加冗余进行检查。


  • 例如,使用奇偶校验、同步信号、CRC 校验和、块重复或协议编号等方法。
  • 也可以使用稳固的应用软件协议栈(如 UAVCAN、Modbus、TCP/IP)等,确保通讯正常和可靠。
  • 别的,还必须对通讯事件的周期性、发生率以及协议错误信号进行持续监控。
认证的一些建议



  • 安全功能实现原理:深入明白和验证每个安全功能的实现原理,确保其在现实应用中的有效性。
  • 灵活处置惩罚:根据现实业务需求灵活调整测试计谋,特别是针对中断、IO、ADC 和通讯模块的运行时测试。
  • 测试记载:记载所有测试步调、输入数据、环境配置、预期结果、现实结果和问题形貌。为后续的检察提供充足的依据。
  • 软件模块筹划书:确保筹划文档包括系统架构图、模块筹划、功能实现原理、软件仿真和测试记载、修改管理等,做到内容全面、正确,方便后续检察和认证。
  • 认证机构沟通:与认证机构保持定期沟通,了解他们的要求和期望,确保测试和文档符合认证标准。
  • 持续更新:关注标准更新和认证要求的变化,实时调整测试和文档以符合最新要求。
末了,祝各人的产品都能顺利通过认证。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

小小小幸运

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表