ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

ISO 26262功能安全实战:ASIL定级、安全机制与软件架构设计

ISO 26262功能安全实战:ASIL定级、安全机制与软件架构设计

1. 从一次ECU死机说起:功能安全到底在防什么

前两年跟一个做域控制器的朋友吃饭,他跟我吐槽:他们一款车身控制器在整车路试的时候,偶尔会出现车窗升降失灵,重启就好,复现概率大概千分之三。当时项目已经接近SOP,硬件改不了,软件查了两周也没定位到根因。最后只能加了个看门狗兜底,把故障率压到可接受范围,但整个团队心里都清楚——这东西没根治。

这件事特别典型。汽车嵌入式开发和消费电子开发最大的区别就在这儿:手机死机了用户骂两句重启就完事,车上的控制器死机,轻则功能失效,重则涉及人身安全。ISO 26262这套标准存在的意义,就是逼着你在设计阶段就把"万一出问题怎么办"想清楚,而不是等路试出问题了再打补丁。

很多人对 ISO 26262 有个误解,觉得它就是一堆文档模板和审核清单,是给认证机构看的。我接触过不少团队,做功能安全就是找咨询公司要一套模板,然后往里填内容,填完交差。这种做法能过审核,但过不了真实的路试。因为标准的核心不是文档,而是一套从危害分析倒推出来的开发约束——它要求你先想清楚"这个功能失效会怎样",再决定"用什么手段把风险降到可接受"。

这篇文章我想聊的是实操层面的东西:ASIL 等级怎么定、安全机制怎么选、软件架构怎么搭、测试怎么做到覆盖、以及那些审核员不会明说但实际会卡你的细节。适合正在做或准备做功能安全项目的嵌入式工程师、系统架构师和测试负责人。如果你手上正好有个项目要过 ASIL B 或 ASIL D,这里面的经验应该能帮你少走几个月弯路。

2. ASIL等级不是拍脑袋定的:危害分析与风险评估的实操逻辑

2.1 HARA的三要素:严重度、暴露率、可控性怎么打分

ASIL 等级是整个功能安全开发的起点,它决定了后续所有开发活动的严格程度。ASIL D 要求最严,ASIL A 最松,QM 就是普通质量管理流程。定级的方法叫HARA(Hazard Analysis and Risk Assessment,危害分析与风险评估),核心是三个维度打分:

  • Severity(严重度,S):伤害的严重程度,S0 到 S3。S0 是无伤害,S3 是致命伤害。这里要注意,评的是对人的伤害,不是对车的损坏。比如安全气囊误爆,可能造成驾驶员受伤,那就是 S2 或 S3。
  • Exposure(暴露率,E):这个工况出现的概率,E0 到 E4。E4 是几乎每次开车都会遇到(比如正常行驶),E0 是极罕见工况。注意这里评的是工况出现的频率,不是故障发生的频率,很多人会搞混。
  • Controllability(可控性,C):驾驶员或其他交通参与者能否及时避免伤害,C0 到 C3。C3 是几乎不可能控制,C0 是肯定能控制。

三个维度组合起来查表得出 ASIL 等级。我见过最常见的错误是把 E 和 C 搞反——比如"高速上刹车失灵",E 应该评 E4(高速行驶是常见工况),C 评 C3(驾驶员几乎无法控制),S 评 S3,组合出来就是 ASIL D。但有人会把"刹车失灵的概率很低"当成 E 的评分依据,这就完全错了。

提示:HARA 的评分必须由跨职能团队共同完成,包括系统、软件、硬件、测试、甚至整车集成的人。一个人拍脑袋定的 ASIL 等级,后面会被审核员反复挑战。

2.2 一个真实场景的定级推演:以电子驻车制动为例

拿电子驻车制动(EPB)来走一遍完整流程。假设场景是:车辆停在坡道上,EPB 应该保持驻车力,但如果控制器失效导致驻车力意外释放,车辆会溜坡。

先做危害识别:危害是"非预期溜车"。然后分析这个危害在什么工况下发生——坡道停车,这个工况的暴露率怎么评?大部分城市用车场景里,坡道停车不算特别常见但也不罕见,我一般会评 E3。严重度方面,溜车可能撞到后方行人或车辆,低速溜车可能造成轻伤,评 S2。可控性方面,如果驾驶员还在车内,能踩刹车控制,评 C2;如果驾驶员已经下车,那就完全不可控,评 C3。

这里有个关键点:同一个危害在不同工况下可能有不同的 ASIL 等级。驾驶员在车内和不在车内,可控性完全不同,定级结果也不同。所以 HARA 的输出不是"EPB 是 ASIL D",而是"EPB 在某某工况下的某某危害是 ASIL D"。这个粒度很重要,因为它直接决定了后续哪些功能需要做高等级的安全机制。

我个人的经验是,HARA 阶段最花时间的不是打分本身,而是把危害场景穷举清楚。一个控制器可能有几十个危害场景,每个场景的工况、严重度、可控性都要有依据。这个阶段偷懒,后面安全目标(Safety Goal)就会定得含糊,再往后所有开发活动都会跟着含糊。

2.3 从安全目标到功能安全概念:怎么把"别出事"翻译成工程语言

HARA 的输出是安全目标(Safety Goal),比如"防止 EPB 非预期释放导致车辆溜车"。但安全目标还是太抽象,没法直接指导开发。下一步要做功能安全概念(Functional Safety Concept),把安全目标拆解成具体的功能安全需求。

继续用 EPB 的例子。安全目标"防止非预期释放",拆解下来可能包括:

  1. 系统要能检测到驻车力异常释放的趋势,并在一定时间内响应。
  2. 响应措施可以是重新施加驻车力,或者发出警报提示驾驶员。
  3. 如果检测机制本身失效,要有独立的备份检测通道。

这些就是功能安全需求。注意每一条都要有可验证的指标——"一定时间内"到底是多久?这就要从危害分析里推导。比如溜车速度、坡道角度、驾驶员反应时间,综合算出来一个时间窗口,比如 200ms。这个数字不是随便定的,是要写进需求文档并且可测试的。

我见过很多团队在这一步出问题:安全目标写得很漂亮,但功能安全需求没有量化指标,导致后面测试没法验证,审核员一问"你怎么证明满足了安全目标"就答不上来。功能安全需求必须可测试、可追溯,这是铁律。

3. 安全机制怎么选:从看门狗到双核锁步的取舍

3.1 安全机制的三个层次:检测、响应、降级

功能安全需求定完之后,就要选具体的安全机制来实现。安全机制按作用可以分三层:

  • 检测层:发现故障。比如看门狗检测程序跑飞、CRC 校验检测数据损坏、电压监控检测供电异常。
  • 响应层:故障发生后采取措施。比如复位、切换到备份通道、输出安全状态。
  • 降级层:如果无法完全恢复,至少把系统带入一个安全状态。比如 EPB 检测到异常后,保持当前驻车力不释放,同时点亮故障灯。

这三层是递进关系。很多团队只做了检测层,发现故障就复位,但复位之后呢?如果故障是持续性的,复位完又故障,系统就会反复重启,这本身就是一个新的危害。所以响应和降级策略必须和检测机制一起设计,不能分开。

我一般建议在架构设计阶段就画一张表,把每个安全目标对应的检测机制、响应措施、降级策略列清楚。这张表后面会直接变成软件架构设计和测试用例的输入。

3.2 硬件层面的安全机制:锁步核、ECC、BIST到底解决什么问题

硬件安全机制是功能安全的基础,因为很多故障软件根本检测不到。常见的硬件机制包括:

安全机制检测的故障类型典型应用场景代价
双核锁步CPU 运算错误ASIL D 主控芯片面积翻倍,成本高
ECC 内存RAM/Flash 位翻转所有安全相关存储需要额外校验位,访问延迟略增
BIST 自检硬件模块潜在故障上电自检、周期自检占用启动时间,需设计自检策略
时钟监控时钟漂移或丢失所有依赖时钟的模块需要独立参考时钟
电压监控供电异常电源管理模块需要额外 ADC 和比较器

双核锁步(Lockstep)是 ASIL D 最常用的方案,两个核执行相同指令,比较器实时对比结果,不一致就报错。但它不是万能的——如果两个核同时受到同一个干扰源影响(共因失效),锁步也检测不出来。所以锁步核通常还要配合其他机制,比如不同物理布局、独立供电。

ECC 内存是另一个必选项。汽车电子里 RAM 位翻转不是小概率事件,尤其是高海拔地区,宇宙射线导致的软错误率会明显上升。ECC 能纠正单比特错误、检测双比特错误,对于安全相关数据是必须的。

注意:硬件安全机制不是越多越好。每加一个机制,就多一个可能失效的环节,也多了验证工作量。关键是覆盖 HARA 里识别出的所有故障模式,而不是堆砌机制。

3.3 软件层面的安全机制:内存保护、程序流监控、数据冗余

软件安全机制和硬件是互补的。硬件管底层物理故障,软件管逻辑故障和系统性故障。常用的软件机制包括:

内存保护(MPU):把安全相关代码和数据放在受保护区域,非安全代码不能访问。这样即使非安全模块跑飞,也不会破坏安全相关数据。MPU 的配置要在启动阶段完成,并且配置本身要经过校验。

程序流监控:在关键代码段插入检查点,按预期顺序执行才通过。如果程序跑飞跳到了错误位置,检查点会失败并触发响应。实现方式可以是计数器、状态机或者基于签名的检查。

数据冗余与交叉校验:关键数据存两份,读的时候对比。如果两份不一致,说明至少有一份损坏。这种方式对 RAM 和 Flash 都适用,代价是存储空间翻倍。

安全状态管理:系统要有一个明确的安全状态定义,以及进入安全状态的路径。比如 EPB 的安全状态是"保持当前驻车力",那么从任何异常状态进入这个安全状态的路径都要设计好并测试到。

我个人的经验是,软件安全机制的设计要和软件架构同步做。如果架构已经定了再往里塞安全机制,往往会发现没有合适的插入点,或者插入后影响实时性。安全机制应该是架构的一部分,而不是补丁。

4. 软件架构的安全设计:分区、隔离与实时性平衡

4.1 混合临界架构:QM和ASIL代码怎么共存

实际项目里很少有纯 ASIL D 的系统,通常是 QM 代码和 ASIL 代码混在一起。比如一个域控制器,安全相关的控制逻辑是 ASIL D,但诊断、通信、日志这些是 QM。这两类代码怎么共存而不互相干扰,是架构设计的核心问题。

主流方案是分区(Partitioning)。用 MPU 或 Hypervisor 把内存空间划分成不同区域,QM 代码只能访问自己的区域,ASIL 代码有独立区域。这样 QM 代码跑飞不会影响 ASIL 代码。分区的粒度可以是任务级、模块级或核级。

分区的代价是通信开销。跨分区通信不能直接读写内存,要走消息传递或共享内存加保护机制,这会增加延迟。对于实时性要求高的控制回路,这个延迟可能不可接受。所以分区方案要在安全性和实时性之间权衡。

我见过一个项目,为了过 ASIL D,把所有代码都放一个分区里,结果 QM 部分的 bug 导致整个系统复位。这就是分区没做好的典型。分区的目的是隔离故障,不是隔离代码,要按故障传播路径来划分,而不是按功能模块。

4.2 时间保护与执行监控:怎么保证安全任务不被饿死

分区解决了空间隔离,但时间维度的问题还在。如果 QM 任务占着 CPU 不放,ASIL 任务得不到调度,安全功能就失效了。所以还需要时间保护机制。

常见做法是给每个任务设执行时间预算,超时就触发异常。操作系统层面可以用时间监控单元(Timing Monitoring Unit)或者看门狗配合调度器实现。关键是超时后的响应要明确——是杀掉任务、降级还是复位,要根据安全目标来定。

另一个问题是中断延迟。安全相关的中断如果被低优先级中断阻塞太久,响应时间就保证不了。所以中断优先级的设计也要考虑功能安全,安全相关中断通常要设最高优先级,并且要测量最坏中断延迟(WCIL)来验证是否满足安全需求。

4.3 安全相关通信:E2E保护到底怎么配

ECU 之间的通信也是功能安全的重要环节。CAN、FlexRay、以太网这些总线,数据可能被干扰、丢失、重复或乱序。E2E(End-to-End)保护就是解决这个问题的。

E2E 保护通常包括:CRC 校验(检测数据损坏)、计数器(检测丢失和重复)、数据 ID(检测错误路由)、超时监控(检测通信中断)。AUTOSAR 里有标准的 E2E Profile,不同 Profile 提供不同的保护强度。

配置 E2E 的时候有几个坑:

  • CRC 多项式选择:不同 Profile 用不同多项式,检测能力不同。ASIL D 通常要求 Profile 5 或 Profile 6,检测能力更强。
  • 计数器位宽:4 位计数器只能区分 16 个周期,对于长周期通信可能不够。要根据通信周期和故障检测时间要求来选。
  • 超时时间设定:太短会误报,太长会漏报。要根据通信周期和抖动来算,通常设 2-3 个通信周期。

我一般建议在通信矩阵设计阶段就把 E2E 配置定下来,和通信周期、信号定义一起评审。后期再改 E2E 配置,往往要动很多代码和测试用例。

5. 测试与验证:怎么证明"真的安全"

5.1 故障注入测试:不是走过场,要真能触发安全机制

功能安全测试和普通功能测试最大的区别是故障注入。普通测试验证"正常情况功能对不对",功能安全测试验证"故障情况下安全机制灵不灵"。

故障注入的方法有很多:

  • 硬件故障注入:用探针短接引脚、拉低电压、注入干扰信号。这种方式最真实,但成本高、可重复性差。
  • 软件故障注入:在代码里插入故障点,模拟内存位翻转、寄存器错误、通信丢包。这种方式灵活、可重复,但可能引入非真实故障。
  • 仿真故障注入:在 SIL/HIL 环境里模拟故障。适合早期验证,但仿真模型的准确性影响结果。

我个人的经验是,软件故障注入 + HIL 验证是性价比最高的组合。软件注入负责覆盖大量故障模式,HIL 负责验证真实硬件上的响应。纯硬件注入只在关键安全机制验证时用。

故障注入测试的关键是覆盖所有安全机制的触发路径。每个检测机制都要有对应的注入用例,每个响应措施都要验证到。审核员会看你的故障注入覆盖率,如果只测了几个典型故障,是过不了的。

5.2 覆盖率指标:语句、分支、MC/DC到底要做到多少

功能安全对代码覆盖率有明确要求。ASIL D 通常要求:

  • 语句覆盖率:100%
  • 分支覆盖率:100%
  • MC/DC(修正条件/判定覆盖):100%

MC/DC 是最严格的,要求每个条件独立影响判定结果。比如if (a && b),要测到 a 真 b 假、a 假 b 真、a 真 b 真、a 假 b 假四种组合。实际项目里做到 100% MC/DC 非常费劲,尤其是复杂逻辑表达式。

有几个实操技巧:

  • 简化逻辑表达式:把复杂条件拆成多个简单判定,降低 MC/DC 难度。
  • 用工具辅助:LDRA、VectorCAST、CTC++ 这些工具能自动分析覆盖率并生成测试用例。
  • 合理使用豁免:标准允许对某些代码(如防御性代码、不可达代码)申请豁免,但要提供充分理由。

提示:覆盖率是手段不是目的。100% 覆盖率不代表没有 bug,但覆盖率不达标肯定过不了审核。建议在开发阶段就持续监控覆盖率,不要等到测试后期再补。

5.3 安全分析更新:FMEA、FTA怎么和测试闭环

功能安全开发是一个迭代过程。设计阶段做的安全分析(FMEA、FTA),在测试阶段要验证和更新。测试发现的故障模式要反馈到 FMEA 里,更新后的 FMEA 可能又引出新的测试需求。

这个闭环很多团队做得不好。常见问题是:FMEA 做完了就锁在文档里,测试用例和 FMEA 没有对应关系。审核员问"你这个故障模式的测试用例在哪",答不上来。

我的做法是建一张追溯矩阵,把安全目标、功能安全需求、安全机制、测试用例、FMEA 条目全部关联起来。任何一个环节变更,都能快速找到受影响的其他环节。这张矩阵在审核时是最有说服力的证据。

6. 那些审核员不会明说但会卡你的细节

6.1 工具链认证:你的编译器真的可信吗

功能安全开发用的工具本身也要可信。编译器、静态分析工具、测试工具,如果它们有 bug,可能引入错误代码或者漏掉真实缺陷。所以标准要求对工具进行工具置信度评估(TCL)。

TCL 的等级取决于工具对安全的影响程度。如果工具可能引入错误而检测不到,TCL 等级就高,需要做工具认证或者工具鉴定。如果工具只是辅助,TCL 等级就低。

实操中,编译器是最麻烦的。主流编译器(GCC、Tasking、IAR)都有功能安全认证版本,但认证版本贵很多。有些团队用非认证版本加额外验证来替代,这需要提供充分的论证和验证证据。

我的建议是:关键工具用认证版本,非关键工具做好使用限制和结果验证。不要为了省钱在编译器上冒险,后期审核出问题返工成本更高。

6.2 安全文档的追溯性:从危害到测试用例的完整链路

功能安全审核最看重的就是追溯性。从 HARA 的危害分析,到安全目标,到功能安全需求,到技术安全需求,到软件/硬件设计,到测试用例,整条链路要能双向追溯。

实操中,追溯性靠文档和工具维护。需求管理工具(如 DOORS、Polarion)能自动维护追溯关系,但前提是需求条目化做得好。如果需求还是 Word 文档里的段落,追溯就只能靠人工,很容易断链。

我见过最常见的追溯断点是在需求到设计这一环。需求文档写得好好的,设计文档里找不到对应实现。审核员一查就发现问题。所以设计评审时一定要对照需求逐条检查,确保每条需求都有设计实现。

6.3 安全文化:为什么"人"才是最后一道防线

最后说一个软性的东西:安全文化。标准里专门有一章讲安全文化,但很多团队觉得这是虚的,不重视。

我的体会是,安全文化决定了功能安全能不能真正落地。如果团队里每个人都觉得"功能安全是安全工程师的事",那这个项目大概率会出问题。安全文化体现在:

  • 任何人发现安全隐患都可以提出来,不会被压制。
  • 安全相关决策有记录、有评审,不是某个人说了算。
  • 出问题后复盘的是流程和机制,不是找人背锅。
  • 安全培训是持续的,不是应付审核。

我经历过一个项目,测试工程师发现了一个安全机制的边界问题,但项目经理为了赶进度想压下来。最后是安全经理坚持上报,才避免了后期更大的返工。这件事让我深刻体会到,功能安全的最后一道防线不是看门狗,是人的责任心。

7. 写在最后:功能安全是马拉松不是冲刺

做了这么多年功能安全项目,最大的感受是:这东西没有捷径。HARA 要认真做,安全机制要仔细选,测试要扎实跑,文档要老实写。任何一个环节偷懒,后面都会以某种方式还回来。

我见过太多团队在项目后期才发现 ASIL 等级定错了、安全机制覆盖不全、测试用例追溯不上,然后加班加点补。补出来的东西质量堪忧,审核也过不了。所以我的建议是:功能安全的工作要前置,在架构设计阶段就把安全需求、安全机制、测试策略想清楚,后面执行起来反而快。

另外,功能安全不是一个人的事。系统、软件、硬件、测试、质量,每个角色都要参与。安全经理可以牵头,但不能包办。团队里每个人都理解功能安全的要求,项目才能顺利推进。

最后分享一个小技巧:每次评审前,自己先当一次审核员,把追溯矩阵走一遍,看看有没有断链。这个习惯帮我提前发现过很多问题,比等审核员指出来再改要主动得多。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进