面灵AI→

法雷奥嵌入式软件开发一面:AUTOSAR 分层、刷写掉电与 UDS 诊断

轮次
一面
时间
2026-10
来源
牛客网

《面试题目》

  1. 先做个自我介绍,最近这段经历里你最想展开的是哪个项目?
  2. 你这个控制器项目用的是哪颗 MCU?代码实际落在 AUTOSAR 的哪一层?
  3. 远程刷写过程中突然掉电,怎么保证下次上电能回到能用的版本?
  4. 应用正在跑,诊断仪要求刷写,怎样从 App 进到 Bootloader?
  5. 诊断仪发会话控制,想从默认会话切到编程会话,ECU 侧怎么处理?
  6. 用读取 DTC 的服务把当前故障列表拿出来,请求和响应怎么走?

《参考解析》

AUTOSAR 分层与「你的代码在哪一层」怎么答

分层的标准答法是自下而上:MCAL 直接操作寄存器与外设(Mcu、Port、Dio、Can、Adc、Spi 等驱动),ECU 抽象层对上层屏蔽具体硬件的差异(IoHwAb、CanIf),服务层提供通信、诊断、存储、OS 等基础服务(Com、PduR、CanTp、CanNm,Dcm、Dem、Fim,NvM,Os,EcuM/BswM),RTE 负责应用 SWC 与基础软件之间的接口绑定与调度,最上面是应用层 SWC(ASW)。能报出层次只是及格,面试官追问的是「你到底动了哪一层、改了什么」。

所以回答时要给具体动作和一条真实的调用路径:诊断报文从 CAN 控制器收上来,依次经过 CanDrv、CanIf、CanTp(多帧的拆装)、PduR 到 Dcm,Dcm 判断服务与会话、必要时调 Dem 读故障、调 NvM 读写、调 BswM 或 EcuM 处理状态切换与复位;应用报文走 CanIf、PduR、Com,再经 RTE 交给 SWC。另一个加分点是配置与代码的关系:AUTOSAR 项目里大量行为是由配置工具(如 DaVinci、EB tresos)生成代码的,改的是配置而不是手改生成物,能说清「哪些行为由配置决定、生成代码为什么不手改、配置变更怎么评审」会显得真的做过项目。如果被问 MCU 型号,就照实报(S32K、TC3xx、GD32 这类),并补一句板级信息(外部晶振、CAN 收发器、Flash 与 RAM 容量),因为这直接关系到性能和刷写方案的可行性。

刷写掉电保护:运行的镜像永远不被写

核心原则一句话:任何时刻都要有一个校验通过的可用镜像,写新镜像的过程绝不能破坏它。方案上有三种常见形态——A/B 双分区交替(当前运行的区不动,新镜像写另一个区)、Boot + App + Backup(App 异常时由 Backup 兜底)、外挂 Flash 先缓存新镜像再搬运。流程是固定的:新镜像先写入非运行区,整包写完做 CRC32 或哈希校验(有安全要求再加签名验证防篡改),校验通过后才更新启动标志,复位后由 Boot 依据标志决定跳哪个区。掉电会发生在任何一步,保护靠两点:一是标志只在镜像完整校验通过后才改,所以「写到一半掉电」只会让新镜像作废,旧镜像仍然有效;二是启动标志放在独立的元数据区,写入顺序设计成抗掉电——先擦再写、写后回读校验,通常还存两份带序号或反码的标志做原子提交,避免标志本身半写入导致 Boot 无法判断。

新版本首次启动还要有试运行机制:应用起来后自检通过才写「确认」标志,Boot 统计启动次数,超时未确认就回滚到旧分区。这一套的边界条件要讲全:如果标志非法或两个区都校验不过,Boot 不能直接停住,应该按优先级回退到最近一个 CRC 正确的区并记录失败原因(写 DTC 或 NvM 供诊断读取),同时停在刷写会话里等待重新下载。实际刷写失败的原因往往不在协议层,而在供电与 Flash 操作——电压不足导致擦写失败、扇区边界与解锁序列写错、写保护位没处理、刷写期间还有任务在访问 Flash、看门狗没人喂导致中途复位。所以进刷写前要停掉会碰 Flash 的任务、关闭或托管看门狗、确认电压与整车状态(行驶中不允许刷写)。能把这一层说出来,说明你处理过真实的刷写失败,而不只是背了 A/B 分区这个词。

从 App 跳进 Bootloader:两条路与各自的前提

第一条是软件复位法,车载项目里更常见:应用收到诊断请求并通过安全访问之后,把「请求进入编程会话」的标志写入 NvM,回复正响应,然后触发看门狗复位或调用内核复位;复位后 Boot 先读这个标志,合法就留在刷写会话等待下载,不合法就跳应用。它的好处是状态干净——走的是和上电一样的初始化路径,外设、时钟、中断都是确定的状态,不容易被应用残留的配置坑到。第二条是直接跳转:关中断、停 DMA 与外设、关闭或重配看门狗,从目标镜像的向量表取出初始栈指针与复位向量并做合法性校验(栈顶落在 RAM 区间、复位向量落在对应 Flash 区间),设置 MSP、重定位 VTOR,再跳到 Reset_Handler。这条路快,但要求你明确处理所有会干扰新镜像初始化的状态,工程上更容易出问题,所以更多用在 Boot 跳 App 而不是反过来。

不管走哪条,跳转前的条件判断都不能省:诊断会话与安全等级是否满足、整车电压与车速是否允许、应用是否已停止非诊断通信(用 0x28 通信控制让总线安静下来)、有没有未完成的写入任务。还要能回答一个追问:为什么不能直接在 App 里擦写自己所在的 Flash——因为擦写期间从同一块 Flash 取指会失败,所以刷写程序必须运行在与被写区域不同的存储上,这也是 Bootloader 必须独立存在的根本原因;有些方案会把 Flash 驱动下载到 RAM 里执行来绕开这一点,但启动与回滚逻辑仍然要留在 Boot。

UDS 会话控制 0x10 与读取 DTC 0x19 的完整流程

0x10 的请求格式是服务号加子功能,子功能 0x01 默认会话、0x02 编程会话、0x03 扩展会话,正响应是 0x50 加子功能,如果 ECU 返回时序参数则带上 P2Server 与 P2*Server(子功能最高位置 1 表示抑制正响应)。ECU 侧的处理顺序是层层设卡:先校验长度与子功能是否支持(不满足回 0x13 长度错、0x12 子功能不支持),再校验当前会话是否允许这个切换、安全访问等级、电压与预编程条件(不满足回 0x22 conditionsNotCorrect,安全等级不够回 0x33 securityAccessDenied),全部通过后才真正切会话、刷新 S3 超时(默认几秒,超时无诊断请求就回落到默认会话)、并按新会话开关服务——很多服务只在扩展或编程会话下可用,否则回 0x7F serviceNotSupportedInActiveSession。进入编程会话通常还伴随停掉应用、关闭普通通信、准备刷写资源这些动作,所以它不是一个单纯的状态位,而是一串前置条件的门。

0x19 读取 DTC 的常用子功能是 0x01(按状态掩码报数量)和 0x02(按状态掩码报列表)。请求形如 19 02 FF,经 CAN 传输层组帧(长报文走首帧、流控帧、连续帧)交给 Dcm,Dcm 校验会话与长度后调用 Dem;Dem 按状态掩码过滤,每个 DTC 的状态字节是 8 个 bit,常见的包括 testFailed、pendingDTC、confirmedDTC、testNotCompletedSinceLastClear、warningIndicatorRequested 等,故障要满足去抖计数条件才会被置为 confirmed。响应方面,19 02 的正响应是 59 02 加上 DTC 状态可用性掩码,随后是若干「3 字节 DTC + 1 字节状态」的记录。追问点通常在工程细节上:去抖与确认策略怎么定(避免瞬时抖动报码)、清码走 0x14 需要满足的时序与条件、快照与扩展数据(0x04、0x06)怎么按 DTC 号取、以及 Dem 事件与功能抑制(FIM)的关系——某个故障被抑制时,上层功能可能被限制,这在诊断与整车策略之间是很关键的一环。答这题时按「服务号—子功能—经过哪几层—响应格式」的顺序说,比只报数字更清楚。