CanNm 从休眠唤醒后重复消息报文的周期与数量分析
现象
调试 CAN 网络管理状态机时,观察到两种唤醒方式进入重复消息模式后的 NM 报文表现不同:
| 唤醒方式 | 观察到的报文 | 周期 |
|---|---|---|
| 休眠后由 CAN 网络管理报文唤醒 | 4 帧 | 约 500 ms |
| KL15 唤醒 | 5 帧 | 约 20 ms |
抓包使用周立功设备,且只连接了这一条 CAN 总线。因此分析仪显示的 Rx 是分析仪接收到总线报文的方向;这些帧可按 ECU 发到总线上的报文进行分析。
原始抓包截图:

两种唤醒路径的区别
CAN 网络报文唤醒:按普通 NM 周期发送
CAN 网络报文唤醒属于网络侧唤醒。ECU 从休眠相关状态被唤醒后进入重复消息状态,NM 报文按普通消息周期发送。
若普通周期配置为 500 ms,重复消息状态持续约 1.6 s,那么在这个时间窗口内看到约 4 帧是合理的:首帧及后续周期帧受状态切换时刻、定时器调度和抓包窗口边界影响,实际帧数不一定简单等于 1.6 s / 0.5 s 的整数结果。
KL15 唤醒:启动快速发送
KL15 唤醒是本节点主动唤醒网络。项目启用了 CanNm 的快速 NM 发送功能,配置的快速发送次数为 5、周期为 20 ms,因此抓到 5 帧、间隔约 20 ms,与这组参数相符。
在 CanNm 实现中,进入重复消息状态时会检查节点是否主动请求网络;满足条件时设置快速发送计数并启动发送。后续每次成功发送都会递减计数,计数结束后恢复普通消息周期。因此,快速发送次数和重复消息状态的持续时间是两个不同概念:前者控制唤醒后的快速帧数,后者控制重复消息状态持续多久。
原理示意图
#mermaid-svg-BrV5Nm4xibcABqBK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-BrV5Nm4xibcABqBK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-BrV5Nm4xibcABqBK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-BrV5Nm4xibcABqBK .error-icon{fill:#552222;}#mermaid-svg-BrV5Nm4xibcABqBK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-BrV5Nm4xibcABqBK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-BrV5Nm4xibcABqBK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BrV5Nm4xibcABqBK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BrV5Nm4xibcABqBK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-BrV5Nm4xibcABqBK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BrV5Nm4xibcABqBK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BrV5Nm4xibcABqBK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-BrV5Nm4xibcABqBK .marker.cross{stroke:#333333;}#mermaid-svg-BrV5Nm4xibcABqBK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-BrV5Nm4xibcABqBK p{margin:0;}#mermaid-svg-BrV5Nm4xibcABqBK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-BrV5Nm4xibcABqBK .cluster-label text{fill:#333;}#mermaid-svg-BrV5Nm4xibcABqBK .cluster-label span{color:#333;}#mermaid-svg-BrV5Nm4xibcABqBK .cluster-label span p{background-color:transparent;}#mermaid-svg-BrV5Nm4xibcABqBK .label text,#mermaid-svg-BrV5Nm4xibcABqBK span{fill:#333;color:#333;}#mermaid-svg-BrV5Nm4xibcABqBK .node rect,#mermaid-svg-BrV5Nm4xibcABqBK .node circle,#mermaid-svg-BrV5Nm4xibcABqBK .node ellipse,#mermaid-svg-BrV5Nm4xibcABqBK .node polygon,#mermaid-svg-BrV5Nm4xibcABqBK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-BrV5Nm4xibcABqBK .rough-node .label text,#mermaid-svg-BrV5Nm4xibcABqBK .node .label text,#mermaid-svg-BrV5Nm4xibcABqBK .image-shape .label,#mermaid-svg-BrV5Nm4xibcABqBK .icon-shape .label{text-anchor:middle;}#mermaid-svg-BrV5Nm4xibcABqBK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-BrV5Nm4xibcABqBK .rough-node .label,#mermaid-svg-BrV5Nm4xibcABqBK .node .label,#mermaid-svg-BrV5Nm4xibcABqBK .image-shape .label,#mermaid-svg-BrV5Nm4xibcABqBK .icon-shape .label{text-align:center;}#mermaid-svg-BrV5Nm4xibcABqBK .node.clickable{cursor:pointer;}#mermaid-svg-BrV5Nm4xibcABqBK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-BrV5Nm4xibcABqBK .arrowheadPath{fill:#333333;}#mermaid-svg-BrV5Nm4xibcABqBK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-BrV5Nm4xibcABqBK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-BrV5Nm4xibcABqBK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BrV5Nm4xibcABqBK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-BrV5Nm4xibcABqBK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BrV5Nm4xibcABqBK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-BrV5Nm4xibcABqBK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-BrV5Nm4xibcABqBK .cluster text{fill:#333;}#mermaid-svg-BrV5Nm4xibcABqBK .cluster span{color:#333;}#mermaid-svg-BrV5Nm4xibcABqBK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-BrV5Nm4xibcABqBK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-BrV5Nm4xibcABqBK rect.text{fill:none;stroke-width:0;}#mermaid-svg-BrV5Nm4xibcABqBK .icon-shape,#mermaid-svg-BrV5Nm4xibcABqBK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BrV5Nm4xibcABqBK .icon-shape p,#mermaid-svg-BrV5Nm4xibcABqBK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-BrV5Nm4xibcABqBK .icon-shape .label rect,#mermaid-svg-BrV5Nm4xibcABqBK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BrV5Nm4xibcABqBK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-BrV5Nm4xibcABqBK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-BrV5Nm4xibcABqBK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 收到 CAN NM 报文
KL15 置位
否:被动网络唤醒
是:KL15 主动唤醒
否
是
休眠相关状态
唤醒来源
网络报文唤醒
本节点主动请求网络
进入 Repeat Message
是否为主动网络请求
按普通 MsgCycleTime 发送
RepeatMessageTime 到期
装载快速发送计数 5
按 ImmediateNmCycleTime 发送
快速发送计数归零?
恢复普通 MsgCycleTime
text
网络报文唤醒: NM ──500 ms── NM ──500 ms── NM ──500 ms── NM ...
普通 MsgCycleTime;Repeat Message 状态到期后退出
KL15 唤醒: NM ─20 ms─ NM ─20 ms─ NM ─20 ms─ NM ─20 ms─ NM
快速发送 5 帧;快速计数结束后恢复普通周期
上图表达的是发送机制。抓包帧数还会受首帧触发时刻、定时器调度和测量窗口边界影响;排查时应结合 ECU 实际加载的配置和完整抓包窗口判断。
在代码中的对应逻辑
项目 CanNm 实现位于:
Proj_Code/_01_BSW/Src/CanNm/CanNm.cCanNm_TransitionToRepeatMessage():进入重复消息状态时启动 Repeat Message 定时器;若节点主动请求网络且快速发送功能启用,则设置快速发送计数并启动发送。- 消息定时器处理逻辑:快速发送计数大于零时,按快速周期发送;快速计数结束后切换到普通
MsgCycleTime。
KL15 唤醒来源标记和 NM 用户数据更新位于 Proj_Code/_02_CDD/NmCdd/NmCdd.c。状态切换回调会根据 KL15 标记区分唤醒来源,并更新 NM 用户数据中的唤醒原因和重复消息标志。
排查时发现:ECUC 与生成代码参数不一致
对比 ECUC 配置和当前生成代码,发现参数值存在差异:
| 参数 | ECUC 配置 TC27x_CanNm_ecuc.arxml |
当前生成代码 CanNm_Cfg.c |
|---|---|---|
CanNmMsgCycleTime 普通 NM 周期 |
500 ms | 100 ms |
CanNmImmediateNmCycleTime 快速发送周期 |
20 ms | 4 ms |
CanNmRepeatMessageTime 重复消息状态时间 |
1.6 s | 320 ms |
CanNmImmediateNmTransmissions 快速发送次数 |
5 | 5 |
因此,虽然抓包中的 500 ms 和 20 ms 与 ECUC 配置吻合,但当前仓库的生成文件仍是另一组旧参数。可能原因包括:生成代码未重新生成、编译时使用了不同的生成目录,或烧录固件并非由当前这份生成代码构建。
建议的核对步骤
- 确认实际构建使用的
GENDATA_DIR,以及编译输入的CanNm_Cfg.c路径。 - 从当前 ECUC 配置重新生成 CanNm 配置代码,确认生成文件中的普通周期、快速周期和重复消息时间分别为 500 ms、20 ms 和 1.6 s。
- 完整编译并烧录后重新抓包,核对两种唤醒路径的报文周期和数量。
- 记录固件版本或构建产物,确保抓包结果能对应到实际烧录的配置。
结论
两种唤醒方式进入重复消息模式后,报文表现不同,主要是因为它们触发了不同的发送节奏:网络报文唤醒走普通 NM 周期;KL15 主动唤醒触发配置的快速发送序列。当前应优先解决 ECUC 与 CanNm 生成代码参数不一致的问题,并确认实际编译和烧录使用的配置。