2、安全生命周期:概念阶段、系统级开发、硬件级开发、软件级开发、生产与运维

各位工程师朋友,咱们今天聊聊安全生命周期。

说实话,这个概念刚入行时我觉得挺虚的。不就是画几个阶段、写几份文档吗?直到我在一个车载项目中吃了大亏——概念阶段没想清楚安全目标,结果开发到一半发现ASIL等级定低了,整个系统推倒重来。嗯,从那以后,我再也不敢小看这个生命周期了。

2.1 概念阶段:别急着写代码

我个人习惯,拿到一个新项目,先别急着打开IDE。概念阶段要做的事,说白了就是搞清楚三件事:

  • 这个系统是干什么的?——功能定义
  • 出问题了会怎样?——危害分析与风险评估(HARA)
  • 我们要做到多安全?——安全目标与ASIL等级

你想想看,如果连系统可能出什么故障都没想清楚,后面开发得再漂亮也是白搭。我在一个ADAS项目中就遇到过,客户说“做个自动紧急刹车”,结果概念阶段没做HARA,直接按ASIL B开发。后来才发现,这玩意儿失效可能导致人身伤亡,至少得ASIL D。改?成本翻三倍。

概念阶段核心产出:

  • 项目定义(Item Definition)
  • 危害分析与风险评估(HARA)
  • 安全目标(Safety Goals)
  • 功能安全概念(Functional Safety Concept)

我的小技巧:做HARA时,别光坐在办公室想。我建议拉着系统工程师、硬件工程师、软件工程师一起头脑风暴。不同视角能发现你一个人想不到的故障模式。

2.2 系统级开发:把安全目标落地

概念阶段定好了安全目标,接下来就是系统级开发。这一步,说白了就是把“我们要多安全”翻译成“系统该怎么设计”。

我记得第一次做系统级安全设计时,犯了个低级错误——安全机制和技术方案脱节。比如安全目标要求“检测传感器故障”,我设计的技术方案却是“每100ms检查一次”。后来评审时被老工程师一句话点醒:“你检查频率够吗?故障发生后100ms,车都撞上了。”

系统级开发主要做这些事:

  • 技术安全概念(TSC)——把安全目标分解到系统架构中
  • 系统架构设计——考虑冗余、故障容错、诊断覆盖
  • 安全机制分配——哪些功能由硬件实现,哪些由软件实现
  • 系统级FMEA/FTA——验证安全机制是否足够

避坑指南:我曾经在一个项目中,系统级设计时没考虑硬件和软件的接口时序。结果软件那边说“我1ms能响应”,硬件那边说“我10ms才能给出信号”。两边一对接,安全机制根本来不及触发。所以,接口时序一定要在系统级就定死。

2.3 硬件级开发:别让芯片拖后腿

硬件级开发,很多人觉得就是画原理图、做PCB。但在功能安全里,硬件开发的核心是——证明硬件不会失效,或者失效了能被检测到

为什么这么说?你想想看,软件出bug可以OTA升级,硬件出问题呢?只能召回。所以硬件级的安全开发,重点在于:

  • 硬件架构设计——单点故障、潜伏故障、诊断覆盖率
  • 硬件安全需求——比如“电源监控必须在2ms内检测到欠压”
  • 硬件FMEDA——计算失效率、SPFM、LFM、PMHF
  • 硬件集成测试——验证安全机制是否正常工作

我个人习惯,做硬件FMEDA时,一定要拿到芯片原厂的Safety Manual。没有?那就自己测。我在一个项目中用过一颗国产MCU,原厂说“支持功能安全”,结果Safety Manual里连故障模式都没列全。最后我们自己做了加速老化测试,才把数据补上。

硬件级关键指标(ISO 26262-5):

指标 ASIL B ASIL D
SPFM(单点故障度量) ≥90% ≥99%
LFM(潜伏故障度量) ≥60% ≥90%
PMHF(随机硬件失效率) <100 FIT <10 FIT

2.4 软件级开发:代码里的安全细节

软件级开发,这是咱们嵌入式工程师的主战场。功能安全对软件的要求,说白了就一句话:代码不能乱跑,数据不能乱改,时序不能乱跳

我记得刚接触功能安全时,觉得“软件安全需求”就是加几个断言、做点边界检查。后来发现完全不是那么回事。真正的软件级安全开发,要覆盖:

  • 软件安全需求——从技术安全概念分解下来
  • 软件架构设计——分层、模块化、错误隔离
  • 编码规范——MISRA C/C++、代码静态分析
  • 软件单元测试——语句覆盖、分支覆盖、MC/DC覆盖
  • 软件集成测试——验证安全机制在软件层面的交互

我的经验:做软件单元测试时,别只盯着正常路径。我曾经测试一个看门狗喂狗函数,正常路径跑得飞起,结果一测异常路径——喂狗函数里有个死循环,看门狗永远喂不上。这种bug,不测异常路径根本发现不了。

这里给个简单的代码示例,展示一个安全相关的软件实现:

/* 安全关键:ADC采样值校验 */
uint16_t safe_adc_read(void) {
    uint16_t raw_value;
    uint16_t check_value;
    
    /* 第一次采样 */
    raw_value = adc_read_channel(ADC_CH_TEMP);
    
    /* 第二次采样(用于校验) */
    check_value = adc_read_channel(ADC_CH_TEMP);
    
    /* 比较两次采样值 */
    if (abs(raw_value - check_value) > ADC_TOLERANCE) {
        /* 采样不一致,触发安全机制 */
        safety_error_handler(SAFE_ERR_ADC_FAULT);
        return 0xFFFF; /* 返回错误标志 */
    }
    
    /* 范围检查 */
    if (raw_value > ADC_MAX_VALID) {
        safety_error_handler(SAFE_ERR_ADC_OUT_OF_RANGE);
        return 0xFFFF;
    }
    
    return raw_value;
}

注意:这个示例里我用了两次采样做校验。为什么?因为单次采样可能受噪声干扰。但要注意,两次采样之间不能有太长的延迟,否则采到的可能不是同一个信号。我曾经在项目中设了10ms间隔,结果电机转速变化太快,两次采的值根本对不上。后来改成1ms间隔,问题解决。

2.5 生产与运维:安全不是交付就结束

很多人觉得,产品交付了,功能安全的工作就结束了。错!生产与运维阶段,才是真正检验安全设计是否靠谱的时候。

生产阶段要关注:

  • 生产过程的安全验证——比如焊接质量、装配工艺
  • 出厂测试——每个产品都要跑安全自检
  • 生产数据追溯——哪个批次、哪个工位、哪个操作员

运维阶段要关注:

  • 现场故障反馈——用户报修、售后数据
  • 安全事件分析——出了事故,要能追溯到根因
  • 软件OTA升级——升级过程本身也要安全

我记得有个项目,产品交付后半年,售后反馈说“偶尔死机”。我们查了三个月,最后发现是生产环节中,某个批次的晶振焊接不良,导致时钟抖动。如果生产阶段做了更严格的测试,这个问题根本不会流到客户手里。

总结一下:安全生命周期不是走流程,而是每个阶段都要扎扎实实地做。概念阶段想清楚“要什么”,系统级设计好“怎么做”,硬件和软件分别实现“能多可靠”,生产和运维验证“确实做到了”。少一步,都可能埋下隐患。

好了,这一章就聊到这儿。下一章咱们深入讲讲概念阶段的核心——HARA怎么做,以及如何避免我当年犯的那些低级错误。