ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Autosar诊断通信管理DCM入门:从UDS指令到Vector配置

Autosar诊断通信管理DCM入门:从UDS指令到Vector配置 说实话我第一次接触 Autosar 里的诊断通信管理DCM时内心是崩溃的。你明明只是想“读个故障码”“写个 VIN 号”结果要面对一长串缩写UDS、DID、DTC、Dcm、Dem、Nvm、PduR、CanTp……每个模块好像都跟诊断沾点边但你根本不知道到底谁在真正干活。这篇“Autosar 入门_诊断_诊断通信管理(DCM)_1”就是写给当初那个我以及现在正准备入门 Autosar 诊断、却对着 Vector 工程一头雾水的你。这篇不讲虚的我会从“一条诊断指令在 ECU 里到底怎么走”说起把 DCM 的职责边界、内部结构DSL/DSD/DSP、会话与安全访问机制、以及基于 Vector 工具链的实际配置流程逐步拆开。内容尽量说人话该给结论给结论该给配置步骤给配置步骤保证你读完能把 DCM 这个模块的骨架立起来。1. 从一条诊断指令看 DCM 的职责1.1 诊断链路里的“前台接待”先想象一个场景维修车间里师傅把诊断仪插到 OBD 口上点了一下“读取版本信息”。屏幕转了两圈VIN、软件版本号、硬件版本号全出来了。整个过程看起来很简单但这条请求从诊断仪出发到 ECU 返回数据中间经过了一整条协议栈。这条链路大致是诊断仪 - CAN 物理层 - 收发器 - CAN 控制器 - CanIfCAN 接口层- CanTpCAN 传输层- PduRPDU 路由层- DCM。注意DCM 在链路最末端它接收到的已经是被 CanTp 组包、被 PduR 路由过来的完整诊断请求。也就是说DCM 根本不用关心数据是怎么分帧、怎么重组、走的是 CAN 还是 CAN FD 还是以太网 DoIP这些脏活累活都被下面的模块包掉了。DCM 只负责一件事“拿到一条完整的诊断请求判断它合不合法然后让应用层把数据填好再组装一条响应发回去。”我习惯把 DCM 类比成公司前台。客户诊断仪来了前台先看你要找谁服务ID再看你有没有预约会话状态还要确认你有没有门禁卡安全等级。都通过了才把你带到对应部门的同事应用层面前。DCM 就是那个前台它自己不干活但它决定你能不能见到干活的人。1.2 DCM 不负责的事同样重要学 DCM 最容易犯的错是以为 DCM 什么都管。实际上很多“跟诊断相关”的功能根本不在 DCM 里。故障码DTC的存储和状态管理属于 DEMDiagnostic Event Manager诊断事件管理。DCM 收到 0x19 读 DTC 信息的请求后自己并不生成 DTC 列表而是去找 DEM 要数据。反过来应用层通过 DEM 上报故障事件二者是协作关系。数据的非易失性存储属于 NVM非易失性存储器管理。比如你通过 0x2E 写入了一个 DIDDCM 只是把数据从诊断请求里解析出来交给应用层真正负责把数据写进 Flash 或 EEPROM 的是 NVM 模块链路上的那些模块。底层通信适配属于 CanTp、CanIf、PduR 这些模块。DCM 不关心底层是 CAN、CAN FD、LIN 还是 DoIP它只管拿到的是“已经完整到达的请求消息”。打个比方DCM 是餐厅服务员DEM 是后厨NVM 是仓库。客人点菜诊断请求找服务员服务员把菜单传到后厨DEM/应用需要特殊食材时后厨去仓库NVM取。你不能让服务员既当传菜员又当仓库管理员那样系统就乱了。理解 DCM 的职责边界是你后面配置它、排查问题的第一块基石。很多新手排查诊断无响应时一上来就盯 DCM结果 DCM 配置没问题实际上是下面的 CanTp 的接收 ID 配错了这种坑我踩过不止一次。2. 核心概念会话、安全等级与 DID 访问权限2.1 会话模式诊断的“门禁系统”在车上如果你一插上诊断仪就能执行任何诊断服务、修改任何参数那也太危险了。比如车辆高速行驶时你通过诊断命令把 ABS 模块重新刷写一遍这车还怎么开所以 Autosar DCM 引入了“会话Session”的概念。常见的会话有默认会话Default Session、编程会话Programming Session、扩展会话Extended Session。ECU 上电后默认处于默认会话这个会话里一般只允许读 DTC、读基本 DID 这类不影响安全的功能。要执行写入操作、刷写、执行例程Routine通常需要切到扩展会话或编程会话。会话切换通过 UDS 服务 0x10 完成。比如诊断仪发02 10 03 00 00 00 00 007 字节 CAN 帧格式其中第一个 0x02 表示后面有效数据长度为 2 字节服务 ID 是 0x10子功能是 0x03如果 ECU 同意会回06 50 03 00 32 01 F4这样的响应其中 0x50 是肯定响应0x03 表示进入了扩展会话后面还带 P2 和 P2* 定时器的值。配置 DCM 时每个诊断服务或每个 DID 都可以指定允许的会话范围。比如某个写入车辆配置参数的 DID你把它绑定到“仅扩展会话”那在默认会话下发 0x2E 写入请求DCM 会直接回否定响应码 0x7F 0x2E 0x7FsubFunctionNotSupported或 0x22conditionsNotCorrect具体回哪个码取决于你配置的否定响应策略。这里有个关键参数叫 S3Server 定时器它控制会话超时时间。如果诊断仪在设定时间内没有任何新请求ECU 会自动从扩展会话退回默认会话。这个特性是为了防止诊断仪拔了之后 ECU 还留在高权限状态。实际项目里 S3Server 一般配 3000 到 5000 毫秒太短可能导致调试时频繁被“踢回”默认会话太长又会有安全隐患需要平衡。2.2 安全访问解锁诊断的“钥匙”会话只是第一道门第二道门是安全访问Security Access对应 UDS 服务 0x27。为什么要安全访问因为扩展会话是所有诊断仪都能进的如果你在扩展会话里就能随便写校准数据那路边随便一个拿着山寨诊断仪的人都能把你的 ECU 改坏。所以对于一些敏感服务写入 DID、执行特定例程、下载等DCM 会要求先完成安全解锁。0x27 服务的流程是诊断仪发送“请求种子”子功能比如 0x01ECU 返回一个随机种子Seed诊断仪用固定算法对种子做计算得到密钥Key发送“发送密钥”子功能比如 0x02ECU 用自己的密钥算法若计算出的结果一致则返回肯定响应解锁成功否则返回 0x35invalidKey。这里的关键是密钥算法在 ECU 端不放在 DCM 里而是由应用层实现。DCM 只负责把收到的种子、密钥通过接口交给应用层或 Crypto 模块去比对。你在配置工具里需要做的是把 0x27 服务使能配置种子/密钥的字节长度比如 4 字节种子对应 4 字节密钥以及配置密钥比对失败后允许重试的次数和延时。安全等级也是可以配的。你可以定义多个安全等级Security Level不同 DID 或服务需要不同的安全等级才能访问。比如等级 1 只能读等级 2 才能写。这跟后面的 DID 权限矩阵配合使用。我在实际项目里遇到过一个问题有时安全访问明明成功了但马上执行 0x2E 写入还是返回 0x31requestOutOfRange。后来查配置才发现那个 DID 的访问权限里只勾选了扩展会话却忘了勾选“解锁后允许访问”的选项。DCM 的权限检查是“会话 安全等级”联合判断的少配一个条件就多一个坑。2.3 DID 数据通路与读写实现DIDData Identifier数据标识符是 UDS 诊断里最常见的“数据容器”。它用 16 位 ID 标识比如 0xF190 可能代表 VIN 号0xF18C 可能代表 ECU 软件版本号。读 DID 用 0x22 服务写 DID 用 0x2E 服务。在 DCM 配置里每一个 DID 对应一个配置条目你需要告诉 DCM 这个 DID 的编号是多少、数据长度是多少、在哪些会话下可用、是否需要安全访问、数据从哪里来或往哪里去。DID 数据来源通常是应用层软件。配置工具生成代码后会为每个 DID 生成一个回调接口比如读取 0xF190 时 DCM 会调用Dcm_ReadDidF190()之类的函数你在这个函数里把 VIN 数据拷贝到 DCM 指定的缓冲区里并返回长度DCM 再把这段数据打包成 0x62 响应发出去。写 DID 的过程类似DCM 解析 0x2E 请求里的数据调用你实现的应用层接口由你把数据更新到 RAM、NVM 或外部 EEPROM然后返回 0x6E 肯定响应。这里有个实用技巧DID 配置里的“数据长度”一定要跟实际应用层提供的数据长度一致。如果配置了 17 字节实际只返回了 10 字节DCM 要么报错要么填充垃圾数据诊断仪那边解析就会错位。VIN 号标准长度是 17 字节很多人配 DID 时把年份、校验位算漏结果读出来长度不对排查半天。3. DCM 内部解剖DSL、DSD、DSP3.1 DSL会话状态与定时器管理DCM 内部并不是一个黑盒它分成三个子模块DSLDiagnostic Session Layer诊断会话层、DSDDiagnostic Service Dispatcher诊断服务调度层、DSPDiagnostic Service Processing诊断服务处理层。这个划分是 Autosar 标准设计好的也是你分析 DCM 问题时的基本地图。先看 DSL。DSL 主要负责“状态”和“时序”。状态方面DSL 管理整个 DCM 的状态机比如当前处于哪个会话、是否处于安全解锁状态、是否正在等待应用层处理某个请求。会话超时S3Server的计时、安全访问解锁后的持续状态都由 DSL 维护。时序方面DSL 负责管理两个关键定时器P2 和 P2*。P2 是 ECU 对诊断请求的“正常响应时间”UDS 标准规定默认 P2 为 50 毫秒可配置。如果 DCM 在 P2 时间内回复不了响应就必须先回复一个 NRC 0x78responsePending即“我还没死在处理呢别急”然后 ECU 进入 P2* 模式P2* 一般配置为 5000 毫秒在这个时间内应用层可以慢慢处理但 DCM 需要周期性地发 0x78 维持连接。为什么要这么设计因为有些诊断操作耗时很长比如写 Flash、执行某个自检程序可能要好几百毫秒甚至几秒。诊断仪那边有自己的超时机制如果 ECU 一直不回任何数据诊断仪会认为通信断了直接报错。0x78 就像你打电话时说“稍等我查一下”防止对面挂断。配置 DSL 时P2 和 P2* 的定时值通常在 DCM 模块配置里明确指定。P2 建议保持标准 50msP2* 则看项目需求。注意DCM 回复 0x78 之后如果应用层处理失败或异常DCM 会在 P2* 超时前返回最终否定响应所以一定要确保应用层接口能及时返回状态无限期挂起会导致诊断仪侧超时。3.2 DSD请求解析与路由DSD 的职责是“判断该找谁处理”。当一个诊断请求通过 PduR 送到 DCM 后DSD 先做最基本的格式检查请求里有没有服务 ID服务 ID 是否被使能请求长度是否合法子功能是否支持如果这些基础检查不通过DSD 会直接生成否定响应比如 0x11serviceNotSupported、0x12subFunctionNotSupported、0x13incorrectMessageLengthOrInvalidFormat根本不会往下走。通过基础检查后DSD 会根据服务 ID 把请求路由到 DSP 里对应的处理单元。比如 0x22 路由到 DSP 的 DID 处理子模块0x2E 路由到 DID 写入处理子模块0x10 路由到会话控制子模块。在 Autosar 标准里DSP 按照功能分组比如 DcmDspSession、DcmDspDid、DcmDspRoutine、DcmDspDtc 等。这里我想强调一点DSD 不是只处理肯定响应。它还负责检查“当前状态下这个服务是否允许执行”。比如在默认会话下收到 0x2E 写入请求DSD 会查配置表发现该服务没有允许在默认会话下执行于是返回 0x7F 否定响应。所以很多服务层面被拒的否定响应码其实是在 DSD 阶段就产生的。如果你在排查“为什么服务返回 0x22/0x31”这类问题时建议先确认请求是否通过了 DSD 的基础检查和权限检查。这一步没通过的话问题根本不在应用层你再怎么调应用代码都白搭。3.3 DSP各服务具体实现DSP 是 DCM 里“干活”最多的地方它实现了每个诊断服务的具体逻辑。以常见的 UDS 服务为例0x10会话控制DSP 切换当前会话状态启动/停止 S3Server 定时器返回新的 P2/P2* 值。0x27安全访问DSP 根据子功能进入种子/密钥流程调用应用层接口进行密钥比较。0x22读 DIDDSP 根据 DID 查表调用对应的读回调把数据封装为 0x62 响应。0x2E写 DIDDSP 校验 DID 数据长度和访问权限调用写回调返回 0x6E。0x19读 DTC 信息DSP 不直接存 DTC而是通过 DEM 的接口获取 DTC 状态和快照信息。0x14清 DTCDSP 调用 DEM 清除故障码。0x28通信控制DSP 控制某路通信的收发状态比如关闭/开启应用报文而不影响诊断报文。0x85控制 DTC 设置DSP 调用 DEM 开启/关闭 DTC 记录功能常用于工厂模式下屏蔽故障记录。从这些服务可以看出DSP 是 DCM 与应用层、DEM、NVM 交互的“真正接口人”。配置 DCM 时你要明确使能哪些服务、每个服务的子功能、以及各服务在各会话下的允许范围。一个项目里如果不需要 0x85直接在配置里把服务关掉还能省一点代码空间和 RAM。为了方便理解我把 DCM 三个子模块的分工做个简单类比DSL 是前台签到本记录状态和超时DSD 是前台分诊台判断请求该不该进、找谁DSP 是各个科室医生真正执行服务逻辑。排查诊断问题时先想清楚问题是出在签到本、分诊台还是医生这边能省大量瞎试的时间。4. 实操基于 Vector 工具链配置 DCM4.1 准备工作工具链和最小工程现在聊点能落地的东西。很多 Autosar 开发用的都是 Vector 的工具链比如 DaVinci Configurator Pro 做 ECU 配置、DaVinci Developer 做 SWC 设计、CANoe 做仿真测试。下面我以 Vector 工具链为例讲 DCM 的配置流程和联调方法。在开始之前确保你有一个能编译的 Autosar 基础工程至少包含通信栈Can、CanIf、CanTp、PduR、Dcm以及系统服务相关的 EcuM、ComM、NvM如果涉及存储。如果你用的不是 Vector而是 EB tresos 等工具配置界面和参数名会有差异但底层逻辑类似可以对照理解。另外准备一个 CANoe 工程配置好 CAN 通道和诊断功能。在 CANoe 里可以添加 Diagnostic Console诊断控制台通过它直接发送 UDS 请求比你自己拼报文高效得多。没有 CANoe 的话用 PCAN 配合上位机也能凑合但体验差不少。4.2 配置核心步骤第一步在 DaVinci Configurator 里找到 Dcm 模块的配置界面。你需要新建或者检查一个 DcmConfigSet在这里使能你需要的诊断服务。默认情况下 DCM 可能只使能了 0x10、0x22、0x2E 这些基础服务其他服务需要手动勾选。第二步配置 P2 和 P2*。找到 DcmDsl 相关的配置项设置 P2 为 50msP2* 为 5000ms。如果后期遇到 0x78 频发的情况可以适当增加 P2 到 100ms 甚至 200ms让应用层能更快响应减少 0x78 的发送次数。第三步配置 DID。在 DcmDspDid 里新建一个 DID填入你要支持的 DID 号比如 0xF190数据长度填 17然后配置“读取权限”和“写入权限”。权限设置里要指定允许的会话默认会话/扩展会话/编程会话和安全等级是否需要解锁。配置工具会有下拉框或勾选界面比较直观。第四步为 DID 关联应用接口。Vector 生成代码时通常会在 Dcm_Cfg.c 或类似文件里为每个 DID 生成回调表。遇到具体 DID 时你需要在应用层实现读取/写入函数并把函数名填到配置里或者直接在生成代码的模板中修改。我的项目习惯是DID 的读写统一封装在一个 DcmApp_Did.h/.c 文件里方便维护。第五步检查 PduR 路由配置。DCM 接收诊断请求和发送诊断响应都需要通过 PduR 进行路由。需要确认诊断 PDUR 的配置是否正确接收路径上CanTp 把数据送到 PduRPduR 再送到 Dcm发送路径相反。如果这一步配置错误即使 DCM 配置得再好诊断报文也进不来。4.3 用 CANoe 做最小验证配置完成、编译通过、刷写进 ECU 后就该上 CANoe 联调了。第一步建立 CANoe 工程选择正确的 CAN 通道和波特率常见车用 CAN 是 500kbpsCAN FD 要额外配置仲裁段和数据段速率。硬件连接方式以 Vector 的 VN1640 或 VN7610 为例把通道 1 接到 ECU 的 CAN 总线上。第二步在 CANoe 里添加 Diagnostic Console选择诊断通道。如果你用 CAN 而不是 DoIP在 Diagnostic/ISO TP 配置里需要设置诊断请求的物理寻址和功能寻址 ID。物理寻址一般用“请求 ID ECU 地址 0x0800”的规则具体看项目定义响应 ID ECU 地址。第三步发送第一个请求。在 Diagnostic Console 的发送窗口输入22 F1 90读 DID 0xF190即读 VIN。如果一切正常你会看到类似62 F1 90 31 32 33 34...的响应数据就是配置好的 VIN 号。第四步切换会话并验证权限。先输入10 03切换扩展会话看响应是否正确再尝试在默认会话下用 0x2E 写入一个只有扩展会话才有权限写的 DID确认会收到否定响应码。这一步能帮你验证会话权限配置有没有生效。第五步启用 Trace 窗口查看报文时序。重点看请求/响应的时间间隔是否出现 0x78 响应以及 P2* 超时等问题。如果报文时间间隔总是超过 50ms 并且频繁出现 0x78就要考虑精简诊断响应路径或者调大 P2 值。这套流程跑通后DCM 的基本链路就算打通了。后续再逐个增加 DID、例程、DTC 服务都是同样的套路。5. 常见问题与排查技巧实录5.1 诊断仪插上没任何响应先查链路别慌这是我被问得最多的一个问题。插上诊断仪发请求ECU 完全没有响应Trace 里什么也看不到。排查思路不要一上来就扎进 DCM而是从下往上查。先用万用表或示波器确认总线上有没有信号、收发器是否正常供电。再看到没看到 CAN 报文如果能看到 ECU 发出其他应用报文、但诊断请求进不去多半是 CanTp 的接收 ID 配置不对或者 PduR 路由没有打通。确认了CanTp 收到数据后再看 DCM 有没有使能对应的服务。这几个层面里DCM 出问题的可能性反而是最小的。我自己的排查习惯是先在 CANoe 里用“发送 CAN 报文”的方式手动向诊断物理寻址 ID 发一条02 10 03 00 00 00 00 007 字节实际发送 02 10 03 然后填充看 ECU 是否回应。如果手动发都没有响应说明底层通信栈就没通如果手动发有响应但 Diagnostic Console 发没响应那就是诊断工具配置问题。5.2 0x22 请求返回 0x31但 DID 明明配置了0x31requestOutOfRange是 DCM 里非常常见的否定响应码上下文不同含义也完全不同。对于读 DID 场景0x31 通常意味着“当前状态下这个 DID 不可访问”。这个时候你首先检查 DID 的会话权限。很多工程师把 DID 配置为“仅扩展会话”但忘了在测试前先发 0x10 03 切换会话。其次检查安全等级。DID 要求解锁后才能访问你没有发 0x27 安全访问流程DCM 当然拒绝。再次检查 DID 编号是否配错比如配置的是 0xF190你请求发的是 0xF191那肯定访问不到。还有一种常见情况是DID 的回调函数里数据处理异常。比如读取函数返回的长度为 0或者返回了错误码DCM 底层也可能按 0x31 响应处理。如果权限检查都通过了就在回调函数里打断点、加 trace看数据到底有没有被正确拷贝出来。5.3 会话切过去就被弹回或者一直停在默认会话这可能有两种原因。一种是 S3Server 定时器配得特别短比如 1000ms你如果发送下一个请求的间隔稍长一点ECU 就回到默认会话了。另一种是诊断仪那边有周期性的“心跳”请求但这个请求的会话权限没配对反而把会话打断了。另外要留意的坑是0x10 服务切换会话成功后DSL 会重新计算 S3Server 超时。如果你的总线负载很高、诊断请求被延迟调度也会出现看起来“莫名其妙回到默认会话”的情况。调试阶段建议把 S3Server 暂时调到 10 秒以上等基本功能稳定了再改回目标值。5.4 下电时 DCM 相关的 NVM 数据丢失这个话题在 Autosar 里更贴近 NVM但很多项目里写入 DID 后遇到下电丢失问题源头恰恰在诊断链路。场景是这样的测试人员通过诊断仪执行 0x2E 写入一个配置 DIDDCM 返回了肯定响应。但整车下电再上电之后写入的数据丢失回到了旧值。排查后发现应用层的写回调只是把数据写到了 RAM并没有触发 NVM 的写操作或者 NVM 的写请求被延后下电流程先于 NVM 写完成发生了。DCM 和 NVM 的正确交互链路应该是应用层在 DCM 写回调中收到新数据后立即调用 NvM 的写块服务比如NvM_WriteBlock()并处理好 NvM 内部的“写请求挂起”状态保证在 EcuM 执行下电序列前已经写入了非易失存储。如果你在项目里遇到“写完就没电”的问题先别怀疑 DCM重点查 NVM 块配置的写保护、写校验和以及 EcuM 的下电时序。5.5 一个容易忽略的小彩蛋功能寻址和物理寻址诊断请求有两种寻址方式物理寻址点对点和功能寻址一对多。功能寻址请求比如 0x7DF是发到总线上所有 ECU 的每个 ECU 的 DCM 都会收到并处理。物理寻址是发给特定 ECU 的只有地址匹配的那个 ECU 会响应。DCM 配置里通常要区分“功能寻址允许的服务”和“物理寻址允许的服务”。比如功能寻址下可能只允许 0x10 会话切换和 0x3E 待机握手其他服务一律忽略。而 0x22、0x2E 这类需要返回数据的服务只能用物理寻址。很多测试人员发现“我用功能寻址发 0x22 没反应”就以为 ECU 坏了其实这是配置故意限制的避免多个 ECU 同时回大量数据造成总线拥塞。所以在排查诊断报文时先确认用的寻址方式对不对。Diagnostic Console 里一般会有物理寻址/功能寻址的切换选项选错了现象完全不同。写在后面这篇文章从职责边界、内部结构、核心概念一路写到 Vector 工具链配置和典型问题排查算是给 DCM 画了一张入门地图。我个人在实际项目里的体会是DCM 这个模块的难点不在“代码怎么写”而在“配置和链路怎么串”。你只要把“会话 - 安全 - 权限 - 数据回调”这条主线理清楚绝大多数问题都能快速定位。下一篇我们继续往诊断深处走重点讲 DTC 与 DEM 的配合以及 0x19 服务的各种子功能。到时候你会看到 DCM 和 DEM 这对“前台与后厨”是怎么把故障码这桌菜端上来的。
返回列表