Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

1.5 物理的骰子——alpha粒子与SRAM翻转

不是bug,是物理

你花了两周写完了一个CAN通信任务,代码评审通过,静态分析通过,单元测试通过。集成测试跑到第3000次循环,ECU突然复位了,看门狗超时。你翻遍日志,找不到死循环,找不到空指针,找不到栈溢出。一切逻辑路径都是对的。

你把问题缩小到SRAM:某一个全局变量的一个bit,在某个不可预测的时刻,自己从0翻成了1。你排除了软件写入的所有可能,这段变量只有一个写入点,那个点在那500微秒里没有被执行。

这不是软件bug,这是一个六晶体管存储单元的物理翻转

你的代码没有错,编译器没有错,逻辑没有错,错的是物理世界在给逻辑世界投骰子。一个alpha粒子从封装树脂的某个微量铀同位素里衰变出来,以大约5MeV的能量穿过硅晶格,它在穿越的路径上电离了几十万个硅原子,产生了一条短暂的电子-空穴对链。

而这条链恰好穿过了存储“1“的那个SRAM单元的存储结点,那一瞬间涌入的额外电荷,改变了交叉耦合反相器的状态。1变成了0。你的全局变量的最高位从1翻转成了0,导致定时器比较值从一个合理的数字跳变成了一个极小值,看门狗在下一个周期就超时了。

SRAM的6T单元——一个被物理学包围的逻辑

SRAM的一个bit由六个晶体管组成。其中四个构成两个交叉耦合的反相器,构成正反馈锁存器,维持着0或1的状态。另外两个是存取晶体管,连接bit line和反相器,用于读写。这个结构叫6T单元。

在28nm或40nm制程下,这个6T单元的面积大约是0.1到0.3平方微米。它里面的存储结点,维持“1“状态的那个结点,大约有两三百个掺杂离子。这个数字很重要。

如果一颗带电粒子穿过这个结点,它电离硅晶格,释放电子-空穴对。如果释放的电荷超过了存储结点的“临界电荷“,存储的1就翻成了0。这叫单粒子翻转(SEU,Single Event Upset)。它不是永久损坏,下一次写入会恢复正常。但在这个翻转发生的瞬间,你的所有逻辑推理都失效了。一个正确的程序的运行,被一个它完全不知道的外部物理事件改写了数据。

这个问题在地面上的汽车上有多严重?非常严重。alpha粒子的来源不只是外太空宇宙射线,封装材料本身就有微量放射性同位素。树脂填充物中的铀-238和钍-232在自然衰变中释放alpha粒子。焊料中的铅-210。封装就是放射源。不需要太阳风暴。芯片的包装壳本身就每秒释放若干个alpha粒子,这就是为什么车规MCU的封装工艺要求低alpha材料(low-alpha molding compound)。

ECC——不是纠正你的错误,是纠正物理的错误

SRAM的ECC(Error Correcting Code)在最简单的形式下,是一场算术插值。以最常见的SECDED(单错纠正、双错检测)为例,每32位数据附加7位ECC校验位。ECC引擎在每次写入时根据数据计算出7位校验码,和数据一起写入SRAM。每次读取时,引擎重新根据读出的数据计算校验码,和存储的7位比较。

如果有一位翻转,校验码的异或结果指向翻转的那一位。引擎翻转它,纠正完成。如果有两位翻转,校验码的异或结果指出的位“不对应于一个有效的纠错向量“,这被解释为“不可纠正错误“,引擎不读数据,改为告警。

你用7位的开销,换来了每一字读取时的即时纠错。 如果alpha粒子撞击的概率是每千小时一次,ECC让你的系统在几十年内都不需要因为SEU复位。

ECC不是在对抗你写的代码,它是在对抗封装材料里铀原子核的随机衰变。这不是软件工程的范畴,是放射物理学的范畴。功能安全论证的一半时间不是在讲逻辑,是在论证物理故障有足够的管控。

lockstep——两条腿同时站立

如果ECC是保护存储的,lockstep是保护处理器的。两个完全相同的CPU核心,执行完全相同的一段代码。每个时钟周期,硬件比较器比较两条内部总线的结果。一致就继续,不一致就由比较器立即触发告警。这种冗余不是“一个做计算、另一个做校验“,它是两个都做计算、两个的结果必须在每个周期都符合。

lockstep的额外成本不低:两个核心吃掉双倍的功耗和双倍的芯片面积。但它的好处是:不需要软件参与。代码不需要修改任何一行。你在单核上写的C代码,编译后放到lockstep双核上跑,硬件的比较器在总线周期内自动解决了所有比对。

当比较器检测到不一致,它不知道哪个核是对的。它只知道不一致。所以lockstep不“修正“,它只能关闭、告警、进安全状态。从这个意义上,lockstep不是一个“错误纠正“机制,它是一个“错误检测“机制,它的后级(通常是SMU,安全管理单元或看门狗)执行实际的故障响应。

冗余与共因失效——两个肾还不够

lockstep比单核强很多,但它有一个软肋:共因失效(Common Cause Failure)。 两个核在同一片晶片上,共享同一个时钟源、同一个电源域、同一个封装。如果电源瞬降幅度太大,两个核同时被干扰,lockstep比较器发现不了问题,因为两个核的错误结果也是一致的。

这就是为什么对ASIL D系统(比如制动和转向系统)有时候需要异构冗余:主处理器是Infineon AURIX TriCore TC3xx,独立安全监控MCU是另一家厂商的Cortex-R5或RL78。不同晶片、不同设计团队、不同时钟。同一个物理事件无法同时击穿两者。

冗余的等级不只是“有没有备份“,是“备份和主份共享什么“。共享电源域?电源瞬断同时干掉两者。共享时钟?时钟毛刺同时影响两者的时序。共享晶片?同一颗alpha粒子可以同时翻转两者的相邻bit。共享设计团队?同一条bug在两个芯片上同时存在。共因失效分析就是追查“什么东西是两者都靠的“,把所有的共同依赖清掉,才叫真正的独立冗余。

PMHF——功能安全的度量基础

“随机硬件故障不可避免”,你和ISO 26262都同意这一点。问题是:不可避免到什么程度才算可接受的?

ISO 26262-5用定量指标规定了不同ASIL等级的随机硬件故障容忍度上限,其中最关键的指标是PMHF(Probabilistic Metric for random Hardware Failures),即每小时的平均不可覆盖硬件故障概率。ASIL D的目标是<10 FIT(Failures In Time)。10 FIT意味着在10^9小时(大约114000年)的持续运行中,发生少于10次违反安全目标的随机硬件故障。

你不可能运行一块ECU 114000年来验证它。PMHF不是测试值,它是基于FMEDA和可靠性统计学推算出来的概率目标。你需要对每一个硬件器件(MCU、电源芯片、CAN收发器、传感器)建模它的失效率和失效模式分布。然后算出在所有安全机制覆盖的前提下,残余失效的总概率是否小于ASIL要求的FIT限值。

这个数字(10 FIT),它骨子里的哲学含义在前面几节已经铺好了:绝对安全是不可能的。存在一个不为零的概率,虽然极小,随机硬件故障会穿透所有安全机制。标准没有要求你消除这个概率,它要求你把概率压到一个“社会认为可接受“的范围。

故障-错误-失效的传播链

前面你看到了alpha粒子→bit flip→看门狗超时→ECU复位这条物理链。在ISO 26262的术语体系里,这条链的每一步都有精确的名称,你不掌握这些名称,就没法读懂安全手册里的FMEDA报告。

这四个名称构成了一个严格的传播层级:

故障(Fault):系统内部的一个非预期异常状态。在ISO 26262-1的定义里,故障是“可能导致元素或相关项失效的异常条件“。alpha粒子击中SRAM单元的那一刻,存储结点上出现了额外的电荷,这就是故障。故障的本质是“炸弹已经埋下去了“,但它可能永远不会被读到。如果这个bit翻在一个用作调试日志的char数组里,而你的正式发版把debug关了,这个故障对功能没有影响。它不是无害,它暂时还“没产生错误“。

错误(Error):故障在被读取的那一刻,从“异常状态“变成了“偏差值“。ISO 26262-1定义错误为“计算出的、观测到的或测量出的值或条件与真实的、指定的或理论上正确的值或条件之间的差异“。当你的程序下一次读这个被翻转的bit,读到的值是错的,这就是错误。故障是“炸弹埋了“,错误是“炸弹炸了,暂时还没伤到人,但碎片已经开始飞了“。

失效(Failure):错误传播到了系统对外提供服务的输出端。ISO 26262-1说失效是“元素或相关项执行所要求功能的能力的终止“。被翻转的定时器比较值导致PWM输出了一个错误占空比,转向电机接到了错误的电流指令,转向系统的助力功能出现了偏差。这就是失效。失效是“碎片击中了系统的输出端口“,你已经无法按设计承诺提供服务了。

危害(Hazard):失效在特定的车辆运行场景下,构成了导致人身伤害的潜在来源。失效本身不一定是危害,同样是错误的100N额外转向力矩,在车辆停在路边时只是一个让人吓一跳的抖动,不算危害。同样的失效在高速公路以120km/h过弯时,可能让车辆偏离车道导致碰撞。危害是“失效+特定运行场景“的组合产物。

这四个步骤的传播链(Fault→Error→Failure→Hazard),不是瞬时的。每一步之间都有时间和逻辑窗口可以插入检测和拦截。ECU上所有安全机制的本质:ECC、看门狗、lockstep、E2E,都是在这条链上布设的“拦截点“。 ECC在Fault→Error这一步拦截:bit flip刚被读到产生错误,ECC当场纠正,错误不传播。看门狗在Error→Failure这一步拦截:程序因错误数据跑飞,看门狗在它产出错误的输出信号之前就复位了整个系统。E2E在Failure→Hazard这一步拦截:即使错误数据已经打包成CAN消息发出去了,接收端的E2E校验发现CRC异常,丢弃该帧,不让错误数据驱动物理执行器。

举个具体的转向ECU例子。T=0ms:alpha粒子击中SRAM,故障发生,转向角度的标定偏移量从+2.3°翻转为+227.3°。T=0.2ms:转向控制Task读取这个值,错误产生。T=0.5ms:Task用错误值计算出目标扭矩,40Nm而不是正常的2Nm。T=0.8ms:CAN消息打包这个扭矩值,但E2E库在打包时基于错误数据计算了一个新的CRC,这个CRC和错误数据是自洽的,所以E2E不会报错。T=1.2ms:转向执行ECU收到这条帧,E2E校验通过(CRC是自洽的),解码扭矩值为40Nm,电机输出40Nm,方向盘助力暴增。如果此时车辆正在高速行驶,危害发生。

你从这个例子里看到了什么?故障只在传播链的某些环节可以被检测到,你的安全机制布在哪一段,直接决定了你能拦截多少故障。 如果你只有锁步核和看门狗而没有ECC,alpha粒子翻转的bit可能在你读取后已经开始传播错误。如果你只有E2E没有看门狗,Task因翻转数据跑飞,跑到错误地址,E2E根本没机会打包数据。每一项安全机制只能覆盖传播链的一段,这就是为什么FMEDA必须分析故障的完整传播路径,不是只看“有多少故障“,是看“故障能不能走到危害“。能走到危害的,安全机制就必须能拦截。走不到的,你可以在论证中说“这个故障不会导致安全目标被违反“。

诊断覆盖率——不是所有的故障都能被抓住

你现在知道了,ECU上有很多安全机制。但你的安全论证不能停留在“我们有ECC“这种模糊表述。每种机制各有各的命中率,ISO 26262把这个命中率量化为诊断覆盖率(Diagnostic Coverage,DC)

诊断覆盖率 = 被安全机制检测到的故障率 ÷ 全部可能发生的故障率。标准把覆盖率分成三个等级,不是微积分算出来的精确值,而是工程实践中通过大量数据统计得出来的经验区间:

低覆盖率(Low),约60%。 典型手段:软件功能测试、基于看门狗的程序流监控。看门狗只能检测“Task没有执行“,但如果Task执行了但计算出了错误结果,看门狗发现不了。它覆盖的是“停“的故障模式,覆盖不了“错“的故障模式。程序流监控好一些,它检测Task有没有按预期的检查点序列执行,但如果Task执行的路径没变,只是某个中间变量的计算值错了,程序流监控也发现不了。所以低覆盖率主要针对的是“完全不执行“这一类故障。

中覆盖率(Medium),约90%。 典型手段:RAM/NVM的周期性自检、OS调度监控。你的MCU可能在每个Task循环的末尾加一次RAM March-C测试,向某个区域写入特定的pattern、读回比对。这可以检测大多数SRAM硬故障,比如某个bit固定卡在0或1(stuck-at fault)。但它不覆盖瞬态SEU:SEU翻了一个bit之后,在下一个March-C循环到来之前的几十毫秒里,错误已经传播出去了。所以中覆盖率适合用于潜伏故障检测(定期扫一遍,不让故障长期潜伏),但不适合用于瞬态故障的即时拦截。

高覆盖率(High),约99%。 典型手段:硬件ECC(SECDED)、lockstep比较器、硬件CRC在线校验。ECC在每次读取时检查,不是周期性的,是实时的,每次read都是一次检测。lockstep在每一个时钟周期比较,不是抽样的,是全量比较。硬件CRC在每一帧CAN消息在发送和接收时在线校验。这些硬件机制的覆盖率之所以高,是因为它们的检测窗口和故障的发生窗口高度重合,故障一出现,检测就已经就位了。硬件检测不依赖软件的执行,不受Task调度的影响。

这三个覆盖率等级直接映射到ISO 26262-5的核心硬件架构度量指标:

SPFM(Single-Point Fault Metric,单点故障度量):衡量硬件体系对“一个故障就能击穿整个安全系统“的防护能力。ASIL D要求SPFM ≥ 99%。这意味着在所有可预见的硬件单点故障中,不管故障发生在SRAM、Flash、ALU还是CAN控制器,至少99%都要被安全机制检测到或覆盖。最多允许1%的故障“穿透“所有安全机制的拦截。你要在你的FMEDA里把每一个硬件器件、每一种故障模式、对应的安全机制覆盖率算清楚,然后加总,证明SPFM ≥ 99%。

LFM(Latent Fault Metric,潜伏故障度量):衡量硬件体系对“两个故障组合才能击穿“的防护能力。有些故障本身不会直接导致失效,但它们会让安全机制失效。比如看门狗自身的时钟源出现漂移,看门狗超时阈值从40ms变成了400ms,看门狗仍然“活着“,但已经不能有效保护系统。这是一个潜伏故障。如果此时第二个故障发生(程序真正跑飞),看门狗不再能及时复位。ASIL D要求LFM ≥ 90%,即至少90%的潜伏故障在合理的“诊断测试间隔“内被检测到,不给第二个故障留下可利用的潜伏窗口。

你在安全论证里,不能只说“我们有ECC“。你必须拿出MCU供应商提供的FMEDA数据:对于SRAM阵列,永久故障(stuck-at)的诊断覆盖率是99.X%,瞬态SEU的诊断覆盖率是99.Y%。这个“百分号数字“是你的安全论证的“可信度单位“,它不是模糊的“应该够安全“,是可计算的、可追溯的、可被独立评审师验算的数值。

为什么两个一样的核还不够——共因失效的深层追问

前面提到lockstep的致命弱点:共因失效(Common Cause Failure,CCF)。两个核在同一个晶片上、同一个电源域里、同一个时钟树下,同一个物理事件可能同时击穿两者。这不仅仅是“电源坏了两个都坏“那么简单。

ISO 26262-9(ASIL分解与共因分析)对共因失效给出了系统性的分类:耦合因子(Coupling Factor),把“两个核共享什么东西“拆成了十个维度。你的共因分析必须逐条论证每一个维度的依赖性和残余风险:

硬件耦合:共享晶片和封装。 两个锁步核在同一片硅晶圆上、在同一个树脂封装里。晶圆级缺陷(如金属层微裂纹)可能同时影响两个核的同一功能单元。封装内的湿气侵入、焊点疲劳,一个机械应力作用于整个封装。当你的FMEDA里写“两个核的失效是独立的“,你必须论证硅片级的物理隔离是否足够(比如两个核是否在晶片上的不同电压岛、是否使用了物理层间的隔离)。

供电耦合:共享电压调节器。 两个核由同一片PMIC(电源管理芯片)的同一个LDO供电。电压跌落、过压、纹波,两个核看到的是同一个畸变的供电波形。lockstep比较器此时无法区分“两个核因为电压不对都算错了“和“两个核都算对了“,因为两个结果仍然一致。你的论证需要有独立电压监控(比如独立的过压/欠压检测电路,不经过PMIC的反馈回路)来打断供电耦合。

时钟耦合:共享PLL/晶振。 两个核由同一个PLL驱动同一个时钟树。时钟抖动、频率偏移、占空比畸变,同时影响两个核的建立/保持时间。如果时钟的建立时间违例导致某个触发器采样到了亚稳态,两个核在同一个触发器位置可能采样到同样的错误值。打破时钟耦合需要独立的时钟源,即主核和监控核由不同的晶振或RC振荡器驱动。

环境耦合:共享温度场和EMI环境。 整颗芯片在同一个结温下运行,温度梯度导致的时序偏移是全局的。同一电磁干扰(如电机驱动的大电流PWM谐波)同时作用于两个核的IO和内部逻辑。封装内部的alpha粒子,同一颗粒子可以穿过两个核的相邻逻辑单元,在28nm制程下这已经是一个实际的失效模式。

开发耦合:共享RTL设计团队和验证流程。 两个核的RTL由同一个设计团队设计、用同一套约束文件综合、由同一个验证团队用同一套testbench验证。如果RTL里有一条设计缺陷(比如流水线在某个特定指令序列组合下产生错误的旁路结果),两个核都会犯同样的错误。lockstep比较器看到的仍然是一致,一致地错。

这五类耦合因子(硬件、供电、时钟、环境、开发)是十类耦合因子中最关键的五个。他们解释了为什么ASIL D系统需要异构冗余:同构冗余(lockstep)解决的是随机硬件瞬态故障,异构冗余解决的是系统级和开发级的共因。 主处理器用Infineon AURIX TriCore,独立安全监控MCU用Renesas RH850或TI Hercules,不同RTL设计团队、不同晶片、不同时钟架构、不同电源轨。只有打破了所有关键耦合因子,你才能论证“两个通道的失效在概率上是独立的“,独立到可以直接用乘法原理:主通道失效概率 × 监控通道失效概率 = 双通道同时失效的概率。

你在共因分析报告里要做的不是一句话“我们采用了异构冗余“。你要逐条、逐类论证十个耦合因子中每一项的独立性和可接受残差。每一项如果做不到完全独立,你就要计算残余耦合的保守概率,并证明这个残余耦合概率不影响整体的PMHF计算。这不是形式主义的表格填充, 这是系统级安全的深层根基:你能把系统级的残余失效风险压到10 FIT以内,是因为你有底气说这两个安全通道不是“同一枚硬币的正反面“,它们是“两枚不同的硬币“,被不同的造币厂、用不同的模具、在不同的时间铸造的。

本篇小结

  1. SRAM的bit flip不是软件bug:alpha粒子从封装材料射出、穿过6T单元的电离轨迹,导致了物理层面的逻辑翻转。
  2. ECC和lockstep不是在对抗软件,是在对抗物理。ECC纠正存储翻转,lockstep检测处理器计算不一致。
  3. 共因失效是冗余体系的天敌:两个核共享同一电源域/时钟源,同一个物理事件就能同时击穿两者。ASIL D用异构冗余打破共因。
  4. PMHF是功能安全的最后一把尺:它不要求零故障,而是要求“残余故障概率小于社会可接受的时间尺度“。

【下集预告】: 下一节思想实验:你是一个ASIL-D制动系统软件工程师。64KB SRAM,300MHz Cortex-R5 lockstep,18个月开发周期。怎么证明你的代码不会让方向盘失效?把前五节的哲学线索收拢成一条完整的工程推理链。