
1. 项目概述与功能安全背景在嵌入式系统尤其是家电、工业控制、汽车电子等关乎人身与财产安全的领域系统的可靠性不再是“锦上添花”而是“生死攸关”的底线要求。想象一下一台洗衣机的微控制器程序跑飞或者一个燃气灶的触摸按键因传感器故障而误触发后果可能不堪设想。这正是功能安全Functional Safety要解决的问题通过一系列系统性的设计、测试和诊断手段确保即使在硬件随机故障或软件异常发生时系统也能维持在安全状态或安全地停机。IEC 60730正是针对家用及类似用途电器自动控制器的功能安全国际标准。其附录H详细列举了针对微控制器硬件如CPU、时钟、存储器、ADC等的故障检测方法。对于嵌入式软件工程师而言挑战在于如何高效、可靠地在产品中实现这些标准要求的自检同时不占用过多的CPU资源和存储空间更不能影响主功能的实时性。NXP Semiconductors提供的IEC60730B安全库便是针对其Cortex-M33等内核微控制器的一套经过验证的软件解决方案它将标准中晦涩的要求转化为了可链接、可调用的API函数。本次我们聚焦于该库中两个颇具代表性的测试栈测试Stack Test与触摸传感接口测试TSI Test。栈测试守护的是软件运行的“地基”防止栈溢出导致的数据破坏和程序崩溃而TSI测试则针对日益流行的电容触摸按键确保其人机交互通道的可靠性。理解并正确实施这两项测试是开发生命周期安全Safety Lifecycle中软件验证环节的关键一步能显著提升产品的诊断覆盖率Diagnostic Coverage和整体安全完整性等级Safety Integrity Level。2. 栈测试为程序运行划定安全边界栈Stack是微控制器中用于存储局部变量、函数调用返回地址、寄存器上下文等临时数据的关键内存区域。它的特点是“后进先出”LIFO随着函数的嵌套调用与返回栈指针SP会不断上下移动。栈溢出Stack Overflow是一种常见的软件故障当程序使用的栈空间超过了预先分配的大小就会覆盖栈边界之外的内存区域这可能是其他变量、堆数据甚至是关键的系统配置区导致程序行为异常、数据损坏乃至系统崩溃。IEC 60730标准虽未在附录H的表格中直接列出“栈测试”但栈内存的完整性是确保程序流控制如函数调用、中断返回正确的基础属于对程序计数器PC和内存等核心资源的保护范畴。因此栈测试是满足Class B安全要求的一项重要的、补充性的软件自检措施。2.1 栈测试的核心原理哨兵模式守卫栈测试的精妙之处在于其“非侵入式”和“模式守卫”思想。它并不直接监控栈指针的每一次移动那会带来巨大的性能开销而是在栈内存区域的上方和下方各预留一小块特定的内存区域我们称之为“哨兵区”或“模式块”。在系统初始化阶段如启动后、主循环开始前测试库函数会向这两个区域写入一个特定的、已知的数据模式例如0x77777777。此后在系统运行期间或复位后定期调用测试函数来检查这两个区域中的数据模式是否保持不变。其背后的逻辑是如果发生了栈溢出向上或向下生长溢出的数据必然会覆盖相邻的内存区域。只要栈的生长越过了为其分配的边界就一定会破坏上方或下方的哨兵模式。测试函数通过比对模式就能间接但有效地检测到栈溢出故障。一旦检测到模式被破坏函数会返回一个失败FAIL状态应用程序的安全错误处理Safety Error Handling函数必须被触发将系统引导至安全状态如关闭输出、进入故障安全模式。2.2 链接器配置在内存地图中为哨兵“划地”栈的大小和位置通常由链接器脚本或分散加载文件定义。要实现栈测试首先必须在链接器脚本中精确定义栈区域并为其上方和下方的哨兵区预留空间。这是整个测试能否正确工作的硬件基础。以ARM Compiler的链接器脚本.icf文件为例配置过程如下定义内存区域边界首先明确RAM的起始和结束地址。define symbol __ICFEDIT_region_RAM_start__ 0x1FFFFC10; define symbol __ICFEDIT_region_RAM_end__ 0x20000000; define symbol __region_RAM2_start__ 0x20000000; define symbol __region_RAM2_end__ 0x200017FF;定义栈大小设定应用程序栈C Stack的大小。define exported symbol __ICFEDIT_size_cstack__ 512; // 栈大小为512字节计算哨兵区地址这是配置的关键步骤。我们需要四个关键地址STACK_TEST_P_1: 栈下方哨兵区的起始地址。STACK_TEST_P_2: 栈区域的起始地址即栈底。STACK_TEST_P_3: 栈区域的结束地址即栈顶也是栈上方哨兵区的起始地址。STACK_TEST_P_4: 栈上方哨兵区的结束地址。库用户指南提供了一个计算示例define exported symbol STACK_TEST_BLOCK_SIZE 0x10; // 每个哨兵区大小为16字节 define exported symbol STACK_TEST_P_4 __region_RAM2_end__ - 0x3; define exported symbol STACK_TEST_P_3 STACK_TEST_P_4 - STACK_TEST_BLOCK_SIZE 0x4; define exported symbol __BOOT_STACK_ADDRESS STACK_TEST_P_3 - 0x4; // 通常为初始SP值 define exported symbol STACK_TEST_P_2 __BOOT_STACK_ADDRESS - __ICFEDIT_size_cstack__ - 0x4; define exported symbol STACK_TEST_P_1 STACK_TEST_P_2 - STACK_TEST_BLOCK_SIZE;地址计算逻辑解析计算顺序是从高地址向低地址进行。STACK_TEST_P_4位于RAM末端附近STACK_TEST_P_3是它下方一个哨兵区块的起始。__BOOT_STACK_ADDRESS通常被设置为初始栈指针SP的值即栈顶。STACK_TEST_P_2则是栈底栈起始地址由栈顶减去栈大小得到。最后STACK_TEST_P_1是栈底下方哨兵区的起始。这些加减0x4的操作通常是为了对齐或适应特定的内存保护单元MPU配置。从RAM区域中排除哨兵区必须告知链接器哨兵区占用的空间不能用于分配变量或数据。define region RAM_region mem:[from __ICFEDIT_region_RAM_start__ to __region_RAM2_end__] - mem:[from STACK_TEST_P_1 size STACK_TEST_BLOCK_SIZE] - mem:[from STACK_TEST_P_3 size STACK_TEST_BLOCK_SIZE];通过- mem:[...]语法将这两块地址从可用的RAM区域中“挖掉”确保编译器不会将任何应用程序变量分配到这些位置从而保证哨兵模式的纯净性。注意事项与实操心得地址对齐哨兵区的大小必须是4字节0x4的倍数这是为了适应32位系统的内存访问对齐要求避免硬件异常并提升访问效率。最小尺寸为0x4。栈大小估算__ICFEDIT_size_cstack__的值需要根据应用程序的实际情况进行估算。可以使用静态分析工具如ARM Compiler的--callgraph选项或通过填充模式并在运行时监测的方法来评估最坏情况下的栈使用深度WCET。务必留出足够的余量通常20%-30%。MPU配置如果使用了内存保护单元MPU需要确保为栈区域和哨兵区配置正确的访问权限如可读可写并且哨兵区不应被设置为“不可访问”否则测试函数本身会触发内存错误。多任务/多栈系统在RTOS环境中每个任务通常有自己的栈。栈测试库需要为每个任务的栈单独配置和运行测试。这意味着你需要为每个栈定义独立的哨兵区地址并在任务上下文切换的钩子函数中或在每个任务的安全监控循环里调用对应的测试函数。2.3 栈测试的实现与API调用配置好链接器后在应用程序中实现栈测试就相对直接了。相关函数位于iec60730b_cm33_stack.S汇编实现和iec60730b_cm33_stack.h中。2.3.1 初始化函数FS_CM33_STACK_Init在系统启动后、主应用程序运行前例如在main()函数的开始初始化硬件之后必须调用此函数来“布置哨兵”。#include “iec60730b.h” // 声明链接脚本中定义的符号地址 extern unsigned long STACK_TEST_P_2; extern unsigned long STACK_TEST_P_3; // 定义测试参数 const unsigned long stack_test_first_address (unsigned long)STACK_TEST_P_2; // 栈下哨兵起始 const unsigned long stack_test_second_address (unsigned long)STACK_TEST_P_3; // 栈上哨兵起始 const unsigned long stack_test_pattern 0x77777777; // 哨兵模式 const unsigned long stack_test_block_size 0x10; // 哨兵区大小需与链接脚本一致 // 调用初始化函数 FS_CM33_STACK_Init(stack_test_pattern, stack_test_first_address, stack_test_second_address, stack_test_block_size);函数作用该函数将指定的模式值如0x77777777写入从firstAddress开始的blockSize字节区域以及从secondAddress开始的blockSize字节区域。这两个区域就是栈下方和上方的哨兵区。性能考量根据文档对于16字节的块大小该函数执行约105个周期在特定主频下约1.10 µs。开销极小适合在启动时执行。2.3.2 测试函数FS_CM33_STACK_Test此函数用于在运行时或复位后检查哨兵模式。它应被周期性地调用例如放在一个1ms或10ms的定时器中断服务例程ISR中或者在主循环的安全监控任务里。FS_RESULT result; result FS_CM33_STACK_Test(stack_test_pattern, stack_test_first_address, stack_test_second_address, stack_test_block_size); if (result FS_FAIL_STACK) { // 栈测试失败检测到栈溢出或内存损坏。 Safety_Error_Handler(); // 跳转到安全错误处理函数 }函数作用逐字节比对两个哨兵区的内容是否与stackTestPattern一致。如果任何字节不匹配则返回FS_FAIL_STACK。返回值处理这是安全关键的一步。应用程序必须检查返回值。一旦返回FS_FAIL_STACK意味着潜在的栈溢出已被检测到程序逻辑可能已不可信。此时必须立即调用安全错误处理函数。这个函数的具体实现由应用开发者定义其核心目标是将系统带入或维持在一个安全状态例如关闭所有危险的执行器如关闭电机、继电器、加热管。点亮故障指示灯。停止运行主程序可能进入一个仅维持基本安全功能的简单循环或低功耗模式。记录故障代码到非易失存储器如有。测试策略上电自检Power-On Self Test, POST在系统启动后立即执行一次。运行时自检Run-Time Self Test以一定周期如每100ms周期性执行。周期选择需权衡故障检测时间和CPU负载。复位后检查在某些从低功耗模式唤醒或看门狗复位后也应执行检查。3. TSI触摸传感接口测试确保人机交互的可靠性电容式触摸传感接口TSI因其美观、耐用、易于清洁等优点已广泛应用于家电面板控制。然而其模拟特性也带来了新的故障模式传感器电极开路冷焊、腐蚀、对地或电源短路、PCB受潮、元器件老化等。IEC 60730标准要求对这类输入通道进行功能安全检测。TSI测试的核心思想是通过软件手段主动或被动地验证从传感器电极到MCU内部ADC转换器的整个信号链是否工作正常。NXP的安全库提供了两种互补的测试方法非激励输入检查和激励输入检查信号增量检查。3.1 TSI测试的基本原理与故障模型在深入API之前理解TSI的工作原理和要检测的故障至关重要。TSI工作原理简述TSI模块通过一个电极向外部电容Cp由PCB走线和触摸电极形成注入电荷并测量将其充电到一个参考电平所需的周期数。这个计数值与电极的对地电容成正比。当手指触摸时人体电容并联到Cp上总电容增加导致计数值显著上升。主要故障模型开路故障Open Pin电极与MCU引脚之间的连接断开如冷焊、虚焊、腐蚀。这导致Cp极小或不存在TSI计数值会异常低远低于基线。短路故障Short to GND/VDD电极信号线对地或电源短路。对地短路会使Cp极大计数值异常高对电源短路可能导致读数固定或异常。信号线间短路两个触摸按键的电极线短路导致按键串扰无法独立检测。内部模块故障TSI模块内部的模拟多路复用器、振荡器、计数器等电路故障。3.2 TSI测试架构与API函数概览库函数主要分为针对TSI_v5和TSI_v6两个版本外设的函数名后缀有_v6以示区分。核心测试流程围绕一个状态机展开由fs_tsi_t结构体对象管理。主要函数包括FS_TSI_InputInit()初始化测试状态机。FS_TSI_InputCheckNONStimulated()/_v6()执行非激励输入检查。FS_TSI_InputCheckStimulated()/_v6()执行激励输入检查信号增量检查。FS_TSI_InputStimulate()/_v6()和FS_TSI_InputRelease()/_v6()用于手动控制激励内部上拉/下拉电阻的辅助函数。测试流程通常是先进行非激励检查紧接着对同一通道进行激励检查。3.3 非激励输入检查基线监控法这是最直接的测试方法用于检测开路和严重短路故障。原理在已知传感器未被触摸空闲状态时每个TSI通道都有一个固有的、稳定的计数值范围称为“基线”Baseline。这个基线由PCB布局、电极尺寸、环境温湿度等因素决定在工厂生产阶段通过校准确定并存储在Flash的受保护区域如CRC校验的区域。测试流程初始化调用FS_TSI_InputInit初始化测试对象。配置与启动配置TSI硬件模块自电容或互电容模式然后开始扫描。数据采集与判断周期性调用FS_TSI_InputCheckNONStimulated。该函数读取当前通道的TSI计数值并与预存的基线值及其允许的公差范围例如±25%进行比较。结果如果读数在[基线 - 低水位, 基线 高水位]范围内测试通过返回FS_TSI_PASS_NONSTIM。如果读数低于低水位可能开路或高于高水位可能对地短路、受潮则返回FS_FAIL_TSI。关键配置与校准基线值必须在工厂校准阶段在标准环境温度、湿度下对每个通道进行多次测量取平均并将结果安全地存储起来。水位阈值需要根据产品的实际使用环境如温度漂移、长期老化来设定。阈值太窄会导致环境变化引发误报False Positive太宽则可能漏检故障False Negative。通常需要通过环境试验来确定合理的阈值。3.4 激励输入检查信号增量检查主动注入故障非激励检查可以检测静态故障但对于检测整个信号链特别是MCU引脚内部的模拟开关和路径的动态功能是否完好能力有限。激励输入检查通过软件模拟触摸事件提供了一个更强大的检测手段。原理利用MCU引脚通常兼具GPIO功能的特点。在TSI进行电容测量期间通过软件临时将该引脚配置为GPIO模式并使能内部上拉或下拉电阻。这个电阻会并联到外部电容Cp上从而改变RC充电时间常数导致TSI计数值产生一个可预测的“增量”Delta。工作流程前提必须已完成同一通道的非激励检查并获取了空闲状态下的基准计数值FS_TSI_InputCheckNONStimulated内部会保存此值。施加激励调用FS_TSI_InputCheckStimulated。该函数内部会或通过调用FS_TSI_InputStimulate使能指定引脚的内置上拉/下拉电阻。测量与计算在激励状态下进行一次TSI测量得到新的计数值。计算该值与之前非激励基准值的差值即“信号增量Delta”。验证增量将计算出的Delta值与一个预存的、典型的Delta期望值范围进行比较。这个期望值也是在工厂校准阶段通过在同一台良品设备上使能上拉/下拉电阻测量得到的。释放激励测试完成后函数内部会禁用上拉/下拉电阻引脚恢复为TSI模拟模式。结果如果测得的Delta值在预期范围内例如使能下拉电阻后计数值应有显著的正向增加说明从引脚到内部计数器的整个路径工作正常返回FS_TSI_PASS_STIM。如果Delta值接近零无变化说明激励未能影响测量结果可能引脚复用功能失效、内部电阻开路、或模拟通路阻塞返回FS_FAIL_TSI。为什么需要两种测试非激励检查快速、开销低用于检测“硬”故障开路/短路和环境突变如进水。激励检查更彻底用于检测“软”故障或性能退化如内部模拟开关电阻增大、灵敏度下降。它能验证“控制”和“测量”两条路径都有效。3.5 TSI测试集成与代码示例将TSI测试集成到应用程序中需要遵循一个清晰的状态机流程。下面是一个典型的单通道测试框架// 定义全局或静态测试对象和状态 fs_tsi_t myTsiTestObj; safety_common_t safetyCommon; void TSI_Test_Periodic_Task(void) { FS_RESULT tsiResult; // 第一步初始化仅一次 static bool isTsiInitialized false; if (!isTsiInitialized) { FS_TSI_InputInit(myTsiTestObj); // 配置TSI硬件模块例如电极扫描顺序、扫描频率、阈值等 TSI_DRV_Init(); // 调用NXP标准驱动进行TSI硬件初始化 isTsiInitialized true; safetyCommon.TSI_test_result FS_TSI_INPROGRESS; } // 第二步根据状态机执行测试序列 switch(myTsiTestObj.state) { case FS_TSI_INIT: case FS_TSI_PROGRESS_NONSTIM: // 进行非激励测试 tsiResult FS_TSI_InputCheckNONStimulated(myTsiTestObj, (uint32_t*)TSI0_BASE_PTR); if (tsiResult FS_TSI_PASS_NONSTIM) { // 非激励测试通过状态机自动进入等待或准备激励测试状态 // 通常库会将状态更新为 FS_TSI_PROGRESS_STIM } else if (tsiResult FS_FAIL_TSI) { safetyCommon.TSI_test_result FS_FAIL_TSI; SafetyErrorHandling(safetyCommon); } // FS_TSI_INCORRECT_CALL 表示调用顺序错误应检查代码逻辑 break; case FS_TSI_PROGRESS_STIM: // 进行激励测试 tsiResult FS_TSI_InputCheckStimulated(myTsiTestObj, (uint32_t*)TSI0_BASE_PTR); if (tsiResult FS_TSI_PASS_STIM) { // 整个通道测试通过 safetyCommon.TSI_test_result FS_PASS; // 可以切换到下一个通道测试或标记本通道测试完成 myTsiTestObj.state FS_TSI_INIT; // 为下次测试重置如果需要循环测试 } else if (tsiResult FS_FAIL_TSI) { safetyCommon.TSI_test_result FS_FAIL_TSI; SafetyErrorHandling(safetyCommon); } break; case FS_TSI_PASS_STIM: // 测试已完成并通过可以执行其他操作或等待下一个测试周期 break; default: // 处理未知状态 break; } }实操心得与避坑指南测试顺序不可错必须先调用FS_TSI_InputCheckNONStimulated在其返回成功或状态机推进后才能调用FS_TSI_InputCheckStimulated对同一通道进行测试。乱序调用会返回FS_TSI_INCORRECT_CALL。硬件配置冲突确保在TSI测量期间应用程序或其他驱动没有意外改变该引脚的模式寄存器PCR将其切换回GPIO或其他功能否则会干扰测试。环境噪声TSI测量易受电源噪声、电磁干扰EMI影响。测试阈值基线和Delta必须包含足够的环境噪声容限。在PCB设计时需做好触摸传感器的屏蔽和滤波。多通道管理产品通常有多个触摸键。需要为每个通道创建一个fs_tsi_t对象并循环或分时进行测试。注意测试期间不要响应该通道的触摸事件以免干扰。校准数据存储基线值和Delta期望值属于安全关键参数必须存储在可靠的存储区如带ECC的Flash并使用CRC或其它校验机制防止数据篡改或损坏。上电时应验证其有效性。测试时机TSI测试应在系统空闲或确保安全的情况下进行例如电机未运行时。测试期间该通道的触摸功能会暂时失效需在UI设计上考虑此“盲区”时间。4. 看门狗测试最后的守护者虽然用户提供的材料在TSI测试后戛然而止但IEC60730B库中另一个至关重要的部分是看门狗测试。它是系统运行时的最后一道防线这里简要补充其核心思想因为它常与栈测试、TSI测试等共同构成一个完整的安全监控体系。看门狗Watchdog的本质是一个硬件定时器需要软件定期“喂狗”刷新。如果软件因跑飞、死循环等原因未能及时喂狗看门狗超时后会触发系统复位。但看门狗本身也可能故障IEC60730库中的看门狗测试其目的就是验证看门狗定时器是否真的能在超时时触发复位。测试原理第一阶段首次上电后配置一个独立的、时钟源与看门狗不同的设备定时器如LPTMR。然后调用测试函数A该函数启动看门狗和设备定时器随后故意停止喂狗并进入一个循环捕获设备定时器的值。看门狗预期会超时并引发复位。第二阶段看门狗复位后在复位处理代码中判断复位源是否为看门狗。如果是则调用测试函数B。函数B会检查之前捕获的设备定时器值是否与配置的看门狗超时时间相符在一定误差范围内。同时它还会检查看门狗复位次数是否超过限制防止因永久故障导致不断复位。技术价值这个测试验证了看门狗定时器的“反应能力”确保这个最终的安全机制本身是有效的。它与栈测试防软件溢出、TSI测试防输入通道故障等一起构成了多层次、多维度的故障检测网络。5. 常见问题与排查技巧实录在实际集成IEC60730B安全库时你可能会遇到以下典型问题问题1栈测试始终失败即使应用程序栈使用量很小。排查步骤检查链接器脚本确认STACK_TEST_P_1到_P_4的地址计算是否正确。最可靠的验证方法是查看生成的MAP文件找到栈符号如__initial_sp的地址核对它是否在你定义的栈区域[STACK_TEST_P_2, STACK_TEST_P_3]内。检查MPU/内存保护配置如果使能了MPU确保为哨兵区和栈区设置了正确的可读可写属性。一个常见的错误是将这些区域配置为“不可执行”但误设为“不可访问”。检查中断嵌套高优先级中断及其嵌套可能会使用额外的栈空间中断栈或主栈。确保你估算的栈大小包含了最坏情况下的中断嵌套深度。检查库函数调用时机确保FS_CM33_STACK_Init在系统初始化早期、任何可能使用栈的复杂操作之前调用。同时确保FS_CM33_STACK_Test在调用时栈指针位于正常的栈空间内。问题2TSI非激励测试误报读数波动大频繁触发FAIL。排查步骤检查硬件与PCB测量传感器电极的电容值是否稳定。检查电源是否干净触摸传感器附近是否有噪声源如开关电源、电机驱动。确保传感器走线远离高频信号线。优化TSI配置调整TSI模块的扫描频率、电极电流、扫描次数等参数。过高的灵敏度容易引入噪声。可以尝试增加扫描次数进行滤波或启用TSI模块内部的硬件噪声检测与抑制功能。审查基线值与阈值确认存储在Flash中的基线值是在正确的硬件和环境下校准的。考虑环境温湿度的影响可能需要实现动态基线跟踪算法而不是使用固定基线。适当放宽高/低水位阈值。检查软件时序确保在调用FS_TSI_InputCheckNONStimulated时TSI模块已经完成了一次完整的扫描并更新了数据寄存器。可能需要等待TSI扫描完成中断标志位。问题3TSI激励测试失败Delta值始终为0或异常小。排查步骤确认引脚复用检查该TSI通道对应的引脚其引脚控制寄存器PCR的MUX设置是否正确。在激励测试时库函数会临时切换MUX吗还是需要用户手动配置仔细阅读库函数说明和芯片参考手册。检查上拉/下拉电阻使能使用调试器在激励测试阶段读取该引脚的GPIO端口数据方向寄存器PDDR和上拉/下拉使能寄存器PUE/PDE确认内部电阻是否被正确使能。测量Delta期望值在确认硬件连接无误的良品板上手动使能内部上拉/下拉电阻测量并记录TSI计数值的变化量。这个值就是你的“典型Delta”。确保代码中用于比较的预存Delta值与此相符。检查供电与参考电压TSI模块的模拟部分对供电VDDA和参考电压VREF很敏感。确保这些电压稳定且在规格范围内。问题4集成多个安全测试后系统实时性变差或CPU负载过高。优化策略分时调度不必在每个周期执行所有测试。将栈测试、TSI测试多个通道、看门狗喂狗等任务分散到不同的时间片执行。例如栈测试每10ms一次TSI通道1测试每100ms一次通道2测试在下一个100ms以此类推。利用空闲时间在CPU空闲任务Idle Task或低优先级后台任务中执行耗时较长的测试。评估测试覆盖率与频率根据安全目标SIL等级和故障率FIT要求与安全经理或标准评估人员确定每个测试的最小执行频率。不一定需要最高的频率。使用DMA对于TSI的多通道扫描如果支持可以配置DMA将转换结果自动搬运到内存减少CPU中断开销。问题5安全错误处理函数Safety_Error_Handler()该如何实现实现要点立即动作首先禁用中断防止被其他任务打断。然后立即将所有安全相关的输出设置为安全状态如关闭电机、关闭加热器、打开安全阀等。这些操作应通过直接写硬件寄存器完成避免依赖可能已损坏的软件栈或变量。故障指示点亮专用的硬件故障LED或通过一个安全的通信通道如专用的错误引脚输出故障信号。记录与诊断如果系统有非易失存储器如带ECC的Flash可以将错误代码、程序计数器PC、栈指针SP等关键信息保存下来供后续分析。但此操作本身不能引入新的风险。最终状态通常安全错误处理函数最后会进入一个无限循环或者触发一个系统级复位。选择哪种取决于安全概念。循环可以维持安全输出状态但消耗功耗复位可以尝试恢复但需确保复位原因被记录避免因永久故障导致“复位风暴”。