ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

AUTOSAR网络管理CanNm实战:报文解析、状态机与休眠唤醒排查

AUTOSAR网络管理CanNm实战:报文解析、状态机与休眠唤醒排查 1. 从一个实际场景说起为什么网络管理报文值得单独拎出来学如果你做过车身控制器、网关或者电池管理系统的开发大概率遇到过这样的问题整车下电之后某些ECU的电流迟迟降不下来静态电流超标第二天早上车主打不着火。排查一圈硬件没毛病最后发现是某个节点的网络管理报文没停总线一直被唤醒。这类问题在分布式电子电气架构里非常典型而解决它的核心机制就是AUTOSAR网络管理也就是大家常说的CanNm。我接触AUTOSAR网络管理大概是在做第一个量产网关项目的时候。当时对NM的理解停留在“周期性发报文”这个层面觉得无非就是定时器加发送能有多复杂。结果第一次做网络休眠测试就翻车了总线上所有节点都进入Prepare Bus-Sleep模式之后有一个节点因为收到了一帧残留的应用报文又跳回了Repeat Message状态整个网络被重新唤醒。那次之后我才认真把CanNm的状态机、定时器参数、报文格式从头到尾捋了一遍。这篇笔记就是把这些年踩过的坑、调过的参数、看过的Trace整理出来。内容会覆盖CanNm的报文结构、状态机运转逻辑、定时器参数怎么算、DaVinci Configurator里怎么配、CANoe里怎么抓和分析、以及实际项目中常见的休眠异常怎么排查。适合刚接触AUTOSAR网络管理的朋友也适合已经上手但被休眠唤醒问题折磨过的同行。核心关键词就几个AUTOSAR、网络管理、报文、NM、CanNm全文围绕这几个词展开不跑偏。2. AUTOSAR网络管理的整体设计思路拆解2.1 网络管理到底管的是什么很多人第一次听到“网络管理”这个词会以为是管理网络拓扑或者路由。其实在AUTOSAR语境下网络管理管的核心只有一件事协调总线上所有节点同步进入休眠或者同步保持唤醒。它不负责路由不负责诊断也不负责应用数据的传输。它的存在意义是让整车的静态电流可控同时保证需要通信的时候网络能快速被唤醒。你可以把它想象成一个办公室的熄灯规则。下班时间到了不能某个人说走就走直接关灯因为可能还有人要加班。得有一套机制想走的人先举手大家都举手了再统一熄灯。如果有人还在干活灯就得继续亮着。CanNm就是这套“举手—确认—熄灯”的规则在CAN总线上的实现。AUTOSAR网络管理有两种主要形态直接网络管理和间接网络管理。直接网络管理就是每个节点都主动发送NM报文通过NM报文来协调状态CanNm、FrNm、UdpNm都属于这一类。间接网络管理则是通过监控应用报文的活跃度来判断网络是否需要保持唤醒节点本身不额外发NM报文。乘用车里CanNm用得最多因为CAN总线成本低、节点多直接网络管理的协调性更好。2.2 为什么选CanNm而不是OSEK NM稍微老一点的平台可能用的是OSEK网络管理。OSEK NM和AUTOSAR CanNm解决的是同一个问题但机制差别不小。OSEK NM的报文里带一个逻辑环节点按顺序传递令牌谁拿到令牌谁发言机制相对复杂而且节点增减对逻辑环影响大。AUTOSAR CanNm简化了这个模型不再搞逻辑环而是用基于标识符的NM报文加上状态机来协调。具体来说CanNm的NM报文使用固定的CAN ID所有节点的NM报文都发到同一个ID上通过报文里的源节点标识来区分是谁发的。这样做的好处是节点增减不影响机制运转新节点上线只要开始发NM报文就行不需要重新编排逻辑环。对于现在动辄几十个节点的域控架构来说这个简化非常关键。另外AUTOSAR CanNm和COM、PDU Router、CanIf这些模块的耦合方式也更清晰。NM报文本质上是一个PDU走的是标准的AUTOSAR通信栈配置起来比OSEK NM更规范。所以新项目基本都选CanNmOSEK NM只在一些老平台或者特定商用车上还能见到。2.3 CanNm在AUTOSAR架构里的位置从分层角度看CanNm位于服务层它下面依赖CanIf和Can驱动上面通过Nm模块和ComM、BswM、EcuM这些模块交互。具体链路是这样的CanNm负责NM报文的收发和状态机运转Nm模块做统一封装ComM根据Nm的状态来请求通信模式BswM做模式仲裁EcuM最终决定ECU能不能休眠。这里有个容易混淆的点CanNm不直接控制ECU休眠。它只负责告诉Nm模块“我现在处于什么状态”Nm再告诉ComM“网络能不能释放”ComM再通过BswM和EcuM去走休眠流程。所以如果你发现ECU不休眠不能只盯着CanNm看得顺着这条链路往上查。理解这个链路很重要因为实际排查休眠问题时很多时候CanNm状态是对的但ComM没释放或者BswM仲裁没通过最后EcuM不执行休眠。只懂CanNm不够得知道它在整个模式管理链路里的位置。3. CanNm报文格式与核心字段逐字节解析3.1 NM PDU的标准结构CanNm的报文格式在AUTOSAR规范里有明确定义。一个标准的NM PDU包含以下部分字段长度说明Source Node Identifier1字节源节点标识标识是谁发的NM报文Control Bit Vector1字节控制位向量携带状态信息User Data0-6字节用户数据可选Padding可变填充字节补齐到8字节Source Node Identifier是每个节点唯一的配置在CanNm模块里。接收方通过这个字段知道是谁在发NM报文。Control Bit Vector里比较重要的位包括Repeat Message Request位、Active Wakeup位、NM Coordinator Sleep Ready位等。这些位在状态机运转和休眠协调里起关键作用。User Data是可选的有些项目会用它传一些自定义信息比如节点健康状态或者唤醒原因。但大多数项目不用User Data直接填0或者Padding。Padding的作用是让报文长度固定为8字节避免DLC不一致导致的问题。3.2 Control Bit Vector里每个位的含义Control Bit Vector是NM报文里信息密度最高的一个字节。我按位拆开说Bit 0Repeat Message Request。这个位置1表示发送方请求总线上的其他节点进入Repeat Message状态。通常在新节点上线或者网络需要重新同步时使用。Bit 1NM Coordinator Sleep Ready。这个位和网络协调有关主协调节点用它来通知从节点可以准备休眠了。Bit 2Active Wakeup。这个位置1表示这个节点是主动唤醒网络的不是被其他节点唤醒的。排查唤醒源的时候这个位很有用。Bit 3NM Coordinator Sleep Ready的补充位具体含义看项目配置。Bit 4-7保留位一般填0。实际抓报文的时候你可以通过Control Bit Vector快速判断当前网络的状态。比如看到某个节点的Repeat Message Request置1就知道网络正在重新同步。看到Active Wakeup置1就知道这个节点是唤醒源。3.3 报文发送周期与DLC的注意事项CanNm报文的发送周期由NmMsgCycleTime参数决定典型值是100ms、200ms或者500ms。这个周期不是随便定的它和NmMsgCycleOffset、NmTimeoutTime这些参数一起决定了网络的响应速度和总线负载。DLC方面标准NM报文是8字节。但有些项目为了省总线负载会把DLC配成更小的值。这里有个坑如果DLC配得不一致接收方可能直接丢弃报文。CanIf层有DLC检查DLC不匹配的报文会被当成无效报文丢掉。所以配置的时候一定要确认所有节点的NM报文DLC一致。另外NM报文的CAN ID通常是固定的比如0x500或者0x600这种。这个ID在CanIf的RxPdu和TxPdu里配置和CanNm的配置要对应上。ID配错了报文发不出去或者收不到状态机就转不起来。4. CanNm状态机运转逻辑与定时器参数计算4.1 三个核心状态Bus-Sleep、Prepare Bus-Sleep、Network ModeCanNm的状态机可以分成两大块Bus-Sleep Mode和Network Mode。Network Mode里面又细分为三个子状态Repeat Message State、Normal Operation State、Ready Sleep State。加上Prepare Bus-Sleep State一共是五个状态。Bus-Sleep Mode是最终状态进入这个状态后NM报文停发ECU可以走休眠流程。Prepare Bus-Sleep State是一个过渡状态进入这个状态后NM报文还会发一段时间等总线上的报文都发完了再进Bus-Sleep。这个过渡状态的存在是为了避免最后一帧NM报文还没发完就断电导致总线异常。Network Mode里的三个子状态各有分工。Repeat Message State是网络刚唤醒或者需要重新同步时进入的状态这个状态下NM报文会以较快的周期发送确保总线上所有节点都能收到。Normal Operation State是正常工作状态NM报文按正常周期发送。Ready Sleep State是准备休眠状态这个状态下NM报文停发但节点还在监听总线如果收到其他节点的NM报文会跳回Normal Operation State。4.2 状态迁移的触发条件状态迁移的触发条件主要有几个NM报文收发、定时器超时、上层请求。从Bus-Sleep到Network Mode的迁移通常由唤醒事件触发。唤醒事件可以是总线唤醒也可以是本地唤醒。总线唤醒就是总线上有报文活动CanIf检测到之后通知CanNm。本地唤醒就是ECU自己的唤醒源比如KL15电、传感器触发等。从Network Mode到Prepare Bus-Sleep的迁移条件是所有节点都进入Ready Sleep State并且NmTimeoutTime超时。这里的关键是“所有节点都Ready Sleep”。只要有一个节点还在发NM报文其他节点就会保持在Network Mode。从Prepare Bus-Sleep到Bus-Sleep的迁移条件是NmWaitBusSleepTime超时。这个定时器保证总线上的报文都发完了再进休眠。4.3 定时器参数的计算过程CanNm的定时器参数是配置的重点也是容易出错的地方。主要参数有四个NmMsgCycleTimeNM报文的发送周期典型值100ms-500ms。NmTimeoutTimeNM报文接收超时时间超过这个时间没收到NM报文就认为网络可以休眠。NmWaitBusSleepTimePrepare Bus-Sleep状态的等待时间。NmRepeatMessageTimeRepeat Message状态的持续时间。这些参数的计算逻辑是这样的NmTimeoutTime必须大于NmMsgCycleTime通常取NmMsgCycleTime的2-3倍。比如NmMsgCycleTime是500msNmTimeoutTime可以取1500ms或者2000ms。这样做的原因是如果某个节点偶尔丢了一帧NM报文不至于立刻触发超时避免误判。NmWaitBusSleepTime通常取100ms-500ms保证最后一帧NM报文发完。NmRepeatMessageTime通常取NmMsgCycleTime的几倍确保所有节点都能收到Repeat Message Request。这里有个实际项目中的经验NmTimeoutTime不能设得太小。我见过一个项目把NmTimeoutTime设成NmMsgCycleTime的1.5倍结果总线负载一高NM报文偶尔延迟就频繁触发超时网络状态来回跳Trace上看非常乱。后来改成3倍就稳定了。5. DaVinci Configurator里CanNm的配置实操5.1 模块依赖与配置顺序在DaVinci Configurator里配CanNm不能只配CanNm一个模块。它依赖CanIf、Can、Nm、ComM、BswM、EcuM这些模块。配置顺序建议是先配Can和CanIf再配CanNm和Nm最后配ComM、BswM、EcuM。CanIf里要配NM报文的RxPdu和TxPdu指定CAN ID和DLC。CanNm里要配Source Node Identifier、定时器参数、Control Bit Vector的默认值。Nm里要配Nm通道和CanNm的绑定关系。ComM里要配通信模式把Nm通道和ComM通道关联起来。这个顺序不是随便定的。CanIf是CanNm的下层下层没配好上层配了也跑不起来。ComM和BswM是CanNm的上层上层要根据下层的状态来仲裁所以放在后面配。5.2 关键参数配置与避坑点在CanNm的配置界面里有几个参数需要特别注意Source Node Identifier每个节点的值必须唯一。我见过两个节点配了同一个值结果Trace上分不清是谁发的NM报文排查问题的时候非常痛苦。建议在项目初期就做好节点标识分配表避免冲突。NmMsgCycleTime这个参数的单位是毫秒。配置的时候要注意和ComM的MainFunction周期匹配。如果ComM的周期是10msNmMsgCycleTime是100ms那CanNm的主函数每10ms跑一次累计10次发一帧NM报文。如果周期不匹配发送时机可能会有偏差。CanNmPnEnabled这个参数控制是否启用Partial Networking。如果项目不用PN一定要把这个参数关掉。开着PN但没配PN信息NM报文里会多出PN相关的字节接收方可能解析异常。CanNmActiveWakeupBitEnabled这个参数控制是否在Control Bit Vector里使用Active Wakeup位。如果项目需要区分主动唤醒和被动唤醒就打开。不需要的话关掉简化逻辑。5.3 配置完成后的检查清单配完CanNm之后建议按这个清单检查一遍Source Node Identifier是否唯一是否和项目节点标识表一致。NmMsgCycleTime、NmTimeoutTime、NmWaitBusSleepTime、NmRepeatMessageTime是否满足计算关系。CanIf里的RxPdu和TxPdu的CAN ID、DLC是否和CanNm配置一致。ComM通道是否和Nm通道正确关联。BswM的仲裁规则是否覆盖了NM状态迁移的场景。EcuM的休眠流程是否在NM进入Bus-Sleep后能正常执行。这个清单看着简单但实际项目里经常有遗漏。尤其是第4和第5条ComM和BswM的配置容易被忽略导致NM状态对了但ECU不休眠。6. CANoe抓取与分析NM报文的实操方法6.1 抓包环境搭建与过滤设置用CANoe抓NM报文第一步是配好硬件通道和波特率。CAN通道的波特率和总线上其他节点一致否则报文会报错。配好之后在Trace窗口里加过滤条件只显示NM报文的CAN ID。这样Trace会干净很多不会被应用报文淹没。如果项目用了CAN FD要注意NM报文是CAN还是CAN FD。CanNm本身不限制是CAN还是CAN FD但配置的时候要确认CanIf里的PDU类型。CAN FD的NM报文DLC可以更大但标准NM报文还是8字节。过滤条件可以用CANoe的Filter功能按ID过滤。也可以写CAPL脚本在on message事件里判断ID只记录NM报文。CAPL脚本的好处是可以同时记录时间戳和Control Bit Vector的值方便后续分析。6.2 用Trace窗口观察状态迁移Trace窗口是分析NM状态迁移最直观的工具。把NM报文的Source Node Identifier和Control Bit Vector加到列显示里就能看到每个节点在什么时间发了什么NM报文Control Bit Vector的值是多少。观察状态迁移的时候重点看几个时间点网络唤醒的时间点、第一个NM报文出现的时间点、Repeat Message Request置1的时间点、NM报文停发的时间点、总线彻底安静的时间点。这几个时间点对应了状态机的关键迁移。我一般会在Trace里加几个Marker标记这些关键时间点。然后对照CanNm的状态机图看实际迁移是否符合预期。如果某个迁移提前或者延迟了就去查对应的定时器参数。6.3 用CAPL脚本自动记录NM状态手动看Trace效率低尤其是网络节点多的时候。我习惯写一个CAPL脚本自动记录每个节点的NM状态变化。脚本逻辑大概是这样的variables { msTimer tCheck; int nodeState[10]; } on message 0x500 { int srcId; srcId this.byte(0); if (this.byte(1) 0x01) { write(Node %d requests Repeat Message at %d, srcId, timeNow()); } nodeState[srcId] 1; } on timer tCheck { int i; for (i 0; i 10; i) { if (nodeState[i] 1) { write(Node %d is active, i); } } setTimer(tCheck, 1000); }这个脚本只是示例实际项目里可以根据需要扩展。比如记录每个节点的NM报文发送间隔判断是否有节点发送异常。或者记录Control Bit Vector的变化分析网络协调过程。7. 常见休眠唤醒问题与排查技巧实录7.1 网络无法休眠的典型原因网络无法休眠是最常见的问题。表现是所有应用报文都停了但NM报文还在发总线一直不安静。原因通常有几个某个节点一直在发NM报文。可能是这个节点的应用层还在请求通信ComM没有释放。也可能是这个节点的NM状态机卡在Normal Operation State没有进入Ready Sleep State。排查方法是看Trace找出哪个节点的NM报文一直在发然后查这个节点的ComM请求源。NmTimeoutTime设得太大。如果NmTimeoutTime设得很大即使所有节点都停了NM报文也要等很久才能进Prepare Bus-Sleep。这个参数要根据项目需求平衡不能太大也不能太小。BswM仲裁没通过。NM状态对了但BswM因为其他原因比如诊断还在进行、应用还在请求没有释放通信EcuM就不休眠。这种情况要看BswM的仲裁日志。7.2 网络频繁唤醒的排查思路网络频繁唤醒比无法休眠更麻烦因为它会导致静态电流反复波动。表现是网络刚休眠不久又被唤醒然后再次休眠如此反复。原因通常是残留报文触发唤醒。总线上有节点在休眠后还在发报文或者有干扰导致总线活动CanIf检测到之后触发唤醒。排查方法是看唤醒时间点附近的Trace找出是哪帧报文触发了唤醒。唤醒源配置错误。有些ECU的唤醒源配置了多个比如KL15、CAN、LIN都配了唤醒。如果KL15有抖动就会频繁触发唤醒。排查方法是查EcuM的唤醒源配置确认每个唤醒源的触发条件。NM报文发送时机不对。如果某个节点的NM报文在Prepare Bus-Sleep阶段还在发就会把其他节点重新拉回Network Mode。这种情况要检查NmWaitBusSleepTime是否足够长确保最后一帧NM报文发完再进Bus-Sleep。7.3 常见问题速查表问题现象可能原因排查方法网络无法休眠某节点NM报文持续发送看Trace找发送节点查ComM请求源网络频繁唤醒残留报文或唤醒源抖动看唤醒时间点Trace查EcuM唤醒源配置NM报文收不到CAN ID或DLC配置错误查CanIf的RxPdu配置对比发送方配置状态机不迁移定时器参数不满足关系检查NmTimeoutTime和NmMsgCycleTime的关系ECU不休眠BswM仲裁未通过查BswM仲裁日志确认仲裁条件Repeat Message不生效Control Bit Vector配置错误查CanNm的Control Bit Vector默认值配置这个表是我在实际项目中总结的覆盖了大部分常见问题。遇到新问题的时候先对照这个表排查能省不少时间。7.4 几个容易被忽略的细节NM报文和应用报文的发送顺序。网络唤醒后通常是先发NM报文再发应用报文。如果应用报文先发接收方可能还没准备好导致报文丢失。这个顺序由ComM和BswM控制配置的时候要注意。NM报文和诊断报文的优先级。诊断报文通常优先级更高如果诊断在进行NM报文可能会被延迟。这种情况要确认CanIf的发送队列配置避免NM报文被诊断报文堵住。多通道NM的协调。如果ECU同时挂在多个CAN通道上每个通道都有自己的CanNm实例。多通道之间的协调由Nm模块处理配置的时候要确认Nm通道的绑定关系避免通道之间互相干扰。8. 我个人在实际项目中的几点体会CanNm这个东西看规范觉得简单实际调起来坑不少。我最大的体会是不要只盯着CanNm看。休眠唤醒问题往往是整条链路的问题CanNm只是其中一环。ComM、BswM、EcuM的配置同样重要有时候问题出在上层但表现却在CanNm上。另一个体会是Trace是最好的老师。规范再熟不如实际抓一次报文看状态迁移。我习惯在项目初期就把CANoe的Trace配好把NM报文的关键字段都显示出来。这样每次调网络管理都能快速定位问题。最后分享一个小技巧在项目里建一个NM参数对照表。把每个节点的Source Node Identifier、NmMsgCycleTime、NmTimeoutTime这些参数都列出来配置的时候对照检查。这个表看着简单但能避免很多配置不一致的问题。尤其是节点多的项目没有这个表很容易配错。这个内容后续还可以扩展的方向包括CanNm和Partial Networking的结合使用、多通道NM的协调机制、NM和诊断的交互场景。这些在实际项目中都会遇到有机会再单独整理。
RELATED READING

延伸阅读

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