首页/新闻资讯/正文详情

UDS刷写0x36服务NRC排查:0x73与0x72根因分析及实战方法

发布时间:2026/9/24 2:09:57 来源:云帆数科 栏目:资讯中心
UDS刷写0x36服务NRC排查:0x73与0x72根因分析及实战方法
去年年底在一家Tier1的台架上调UDS刷写遇到一个特别磨人的问题0x36传输数据跑了大半突然连续返回NRC 0x73重启上位机再刷又是同样的位置挂掉。一开始我怀疑是ECU的Flash驱动有缺陷后来把总线抓包文件和上位机日志逐帧比对才发现问题根本不在ECU侧而是上位机的超时重传逻辑出了bug——重传时块序列计数器没有回到出错前的位置。这个坑让我整整折腾了一天。后来我把0x36服务相关的NRC尤其是0x73、0x72彻底梳理了一遍又翻了不少协议栈源码和诊断规范发现刷写阶段的大多数问题其实都有规律可循排查思路也完全可以系统化。这篇文章就把这些经验整理出来围绕0x36服务的报文格式、NRC触发机制、常见根因和排查方法展开适合ECU诊断开发、刷写工具开发、诊断测试工程师以及刚接触UDS协议栈的朋友参考。1. 刷写链路中的0x36服务先看清它在整盘棋里的位置1.1 从0x34到0x37的完整时序很多人一上来就盯着0x36的NRC看却忽略了0x36在整个刷写流程中的位置。实际上0x36TransferData数据传输只是刷写链路中的一环它的前后都有严格的前置条件和后续动作任何一个环节没走对0x36都可能报错。一次典型的UDS刷写流程是这样的首先通过10 02进入编程会话然后通过27 01/02完成安全解锁随后执行31 01例程控制做编程预条件检查和Flash擦除接着发0x34RequestDownload请求下载告诉ECU“我要往哪个地址写多少数据”ECU回正响应后上位机才开始用0x36逐块搬运数据全部搬完后发0x37RequestTransferExit请求退出传输结束下载最后再来一轮例程控制做编程依赖检查最后11 01复位ECU。这个顺序不是随便定的。0x34的作用是让ECU做好接收数据的准备包括校验地址范围、分配缓冲区、初始化Flash编程状态0x36则是真正的“搬砖”环节把固件数据一块一块送进ECU0x37告诉ECU“数据发完了你校验一下整体完整性”。如果0x34没成功或者安全等级不够0x36就会直接报错——这也是很多人排查0x36故障时容易忽略的盲区。1.2 0x36的报文格式与块序列计数器的设计意图0x36的请求帧格式很简洁第一个字节是SID 0x36第二个字节是块序列计数器blockSequenceCounter从第三个字节开始才是真正的传输数据。响应帧则是0x76加相同的块序列计数器表示ECU确认收到了这一块数据。请求36 | blockSequenceCounter | data[0...n] 响应76 | blockSequenceCounter这个块序列计数器是理解0x73的关键。它从0x01开始每成功接收一块数据就加1到0xFF后回绕到0x00继续递增。计数器存在的意义是让ECU能识别数据块的顺序——因为底层传输可能有重传、丢帧等异常情况ECU需要通过计数器判断当前收到的数据块是不是自己期望的那一块防止数据错位写入Flash。这里有一个容易踩的坑0x34的正响应SID是0x74而NRC 0x74也是“请求序列错误”。在抓包日志里看到0x74先确认它是正响应的SID还是负响应码别一上来就以为ECU报了请求序列错误。这种细节在协议栈源码调试和日志分析中很容易把人带偏。2. 0x73错误块序列计数最常见的刷写中断元凶2.1 ECU侧对块序列计数器的校验逻辑按ISO 14229-1的规定ECU内部会维护一个期望接收的块序列计数器值。每收到一个合法的0x36请求ECU会把请求中的计数器和自己期望的值比较一致则处理数据、计数器加1、返回正响应不一致则返回NRC 0x73wrongBlockSequenceCounter。这里有个值得注意的细节ECU收到一个计数器不匹配的0x36请求后它内部的期望计数器是否改变标准没有强制规定由实现决定。我实际接触过的ECU中有些在收到错误的计数器后保持原状态上位机只要重新发送正确的块序号就能继续有些则会中止当前的下载会话后续所有0x36都会返回0x73或0x74必须重新执行0x34甚至重新解锁才能恢复。所以遇到0x73先查清楚你的ECU属于哪种行为模式否则排查方向很容易跑偏。另外0x73和超时是两个层面的问题。如果底层传输丢帧导致ECU的TP层根本没收到完整的0x36请求上位机侧表现为超时而不是收到0x73只有当请求完整到达ECU应用层但计数器和期望值不一致时才会看到0x73。区分这两者能帮你快速判断问题出在传输层还是应用层。2.2 导致0x73的四类根因场景根据我这些年的经验0x73的根因可以归为四类第一类是上位机重传逻辑bug。这是最常见的。典型表现是上位机发送块N后超时实际上ECU可能已经收到并处理了只是正响应帧丢了上位机决定重传但重传时计数器已经递增到N1于是ECU期望N却收到N1直接报0x73。更麻烦的是有些自研刷写工具在超时后会“重新开始传输”但计数器没有重置为0x01导致错位一直延续。第二类是分包大小不一致。应用层定义一个数据块是4096字节底层CAN FD单帧只能传64字节需要把一个大块拆成多个CAN帧经TP层传输。如果上位机的TP层分段逻辑有bug或者ECU侧接收缓冲区大小不匹配可能出现上一块的尾部数据残留在TP层缓冲中被当成下一块的头部数据导致ECU应用层拿到的数据块边界和上位机不一致计数器自然就对不上了。第三类是传输层丢帧或乱序。CAN总线负载过高、错误帧重试、总线关闭等情况都可能导致TP层丢帧。ECU的TP层收不到完整消息就不会向应用层提交上位机发了一个块但ECU完全没收到双方计数器就不同步了。这种场景下上位机看到的往往是超时之后又收到0x73很迷惑。第四类是软件工程问题——多线程竞争。自研刷写工具中发送线程和维护计数器的线程不是同一个或者多个任务共享一个全局计数器变量没有加锁保护就可能在某个瞬间把错误的计数器值发出去。这类问题随机性强复现困难但一旦出现就是疑难杂症。2.3 定位0x73的排查清单与实测经验面对0x73我建议按以下清单逐项排查导出完整的抓包文件把出错前后各20帧的0x36请求和响应全部列出来核对计数器的递增序列。检查ECU返回0x73后自己的期望计数器值是多少——可以通过重新执行0x34后再试观察是否恢复正常来间接判断。核对0x34正响应中的maxNumberOfBlockLength确认你的实际块大小是否在ECU允许的范围内。检查传输层是否有重传、错误帧、总线关闭等异常记录。如果是自研上位机重点审计超时重传分支和计数器管理的代码。实测下来0x73有六成以上是上位机逻辑问题三成是传输层问题真正ECU侧自己出问题的不到一成。所以遇到0x73先别急着怀疑ECU的协议栈实现先从自己这一侧找原因往往更快。3. 0x72一般编程失败看似笼统实则信息量很大3.1 0x72的触发层次从应用层到驱动层NRC 0x72generalProgrammingFailure翻译过来是“一般编程失败”单看这个名字非常笼统好像什么都没说。但如果结合0x72出现的位置和上下文它其实能告诉我们很多信息。0x72通常出现在两种场景中一种是0x36传输数据的过程中ECU尝试把数据写入Flash时失败另一种是0x31例程控制执行擦除操作时失败。和0x73不同的是0x73说明ECU认为你的计数器不对属于时序问题0x72则说明时序没问题、数据块序号也对但ECU在执行编程操作时物理层面或者驱动层面出了岔子。所以看到0x72第一反应不应该是“ECU在说什么”而是“ECU在哪个环节失败的”。这个环节可以粗略分为应用层状态检查失败、驱动层擦写操作失败、数据完整性校验失败三个层次排查方向完全不同。3.2 Flash操作失败、地址校验失败、数据完整性校验失败按我的经验0x72背后最常见的具体原因有几种一是Flash擦写操作失败。Bootloader里的Flash驱动依赖底层库函数如果驱动代码本身有bug或者擦写时电压不稳定、Flash器件异常就会返回失败。这类问题通常在固定地址或固定数据块附近复现因为某些Flash扇区本身就有坏块或擦写寿命耗尽。二是地址校验失败。0x34请求下载时指定的内存地址范围和0x36实际写入数据跨越的地址范围不一致。比如0x34里给的memorySize比固件文件实际大小少了一个块最后一个0x36的数据就超出了ECU允许写入的Flash区域ECU在做地址边界检查时直接返回0x72。这类问题定位起来相对容易把0x34的参数和固件文件大小对着算一遍就能发现。三是数据完整性校验失败。有些ECU在0x36传输过程中就会对已收到的数据做校验和或CRC累计计算如果发现累计值不对立即返回0x72。这种机制下0x72出现的位置往往是最后一个0x36块但具体原因可能是上位机读取固件文件时读错了字节、传输过程中数据被破坏或者数据块顺序错乱导致累计校验值对不上。四是一次性写入缓冲区溢出。某些ECU的Flash编程驱动要求一次性写入的数据长度不能超过内部缓冲区大小如果上位机某个块的data字段长度超过了缓冲区也会触发0x72。3.3 利用DID和例程控制进一步定位0x72的排查不能只靠看NRC本身还得借助其他诊断服务来获取更多上下文信息。首先通过读取DID比如0xF1 00当前会话状态、0xF1 80软件版本号等确认ECU当前是否还在编程会话、安全等级是否维持解锁状态。有些ECU在0x36传输过程中如果长时间没有请求交互安全状态会自动降级后续0x36就会报0x72或0x33。其次重新执行例程控制检查编程预条件。部分ECU实现中0x31 01 FF 00检查编程预条件的结果会带一个子错误码或状态字节能精确告诉你是电压问题、温度问题、点火信号问题还是其他外部条件不满足。我见过一个案例ECU在0x72之后通过读取一个OEM自定义DID直接读出了“目标扇区擦除超时”的具体错误问题瞬间定位。再有就是读取DTC。很多ECU在Flash编程失败时会记录诊断故障码通过19 02读取相关DTC能确认是否是Flash硬件故障导致的0x72。如果以上手段都用了还是定位不了就用最小复现法把传输块大小调小换一块已知没问题的Flash区域写入逐步逼近问题边界。这个方法虽然朴素但在驱动类问题上非常有效。4. 其他高频NRC0x74、0x22、0x31、0x70同样值得关注4.1 0x74请求序列错误顺序错了全盘皆输0x74requestSequenceError和0x73不一样它不是说“你这块序号不对”而是说“你压根就不该在这个时候发0x36”。最常见的触发场景有三种。第一种是跳过了0x34直接发0x36。ECU根本还没建立下载会话你上来就传数据它只能回0x74。这种情况通常是上位机逻辑漏了0x34或者0x34发送失败后没有正确处理、继续往下走了。第二种是安全解锁没完成就发0x36。部分ECU在0x34之后、0x36之前还会校验安全等级如果当前处于锁定状态直接返回0x74或0x33。注意这两个NRC在诊断规范中都可能出现在这个场景具体返回哪个取决于ECU的安全等级检查在哪个环节实现。第三种是0x36和0x37之间插入了不该有的服务或者0x37之后又发0x36。有些ECU对下载会话的边界管理非常严格0x37结束后的第一个0x36立刻返回0x74。演示一下典型错误时序10 02 - 50 02 27 01 11 22 33 - 67 01 44 55 66 34 ... - 74 ... # 正响应SID是74 36 01 ... - 7F 36 74 # 还没解锁报序列错误注意这里的0x74既是0x34正响应的SID也是NRC。在代码里做日志解析时一定要区分帧的上下文否则会把正响应误判成负响应。这个坑我在自研解析脚本时踩过特此提醒。4.2 0x22条件不满足与0x31请求超出范围0x22conditionsNotCorrect和0x74有点像都是说“当前条件不对”但0x22更偏向外部的环境条件而不是协议时序条件。刷写场景中0x22常见于ECU检测到外部条件不满足时拒绝0x36。比如某些OEM要求刷写时点火信号必须处于ON状态、蓄电池电压必须在一定范围内、挡位必须在P挡等。如果这些硬线信号条件不满足ECU在收到0x36后会以0x22拒绝。0x31requestOutOfRange则在参数层面做文章。0x36请求中如果出现非法的计数器值比如0x00、数据长度超过0x34协商的块长度、或者传输的数据量超过了0x34声明的memorySize都可能触发0x31。这个NRC的出现通常意味着上位机的参数计算有误属于逻辑bug排查时对照0x34的请求参数逐一核对即可。4.3 0x70上传下载未接受0x70uploadDownloadNotAccepted在0x36阶段相对少见但偶尔会遇到。它表示ECU当前不接受上传或下载操作常常出现在0x34阶段但如果ECU在下载会话过程中状态被重置比如发生了软件复位后续的0x36可能返回0x70而不是0x74。如果遇到0x70优先检查ECU是否还在编程会话中——通过发送10 02重新进入会话并重新执行安全解锁和0x34一般就能恢复。另外需要确认ECU是否处于某种保护状态比如下载会话被某个例程锁定、或者软件擦除后进入了一种“只能写固定区域”的特殊模式。这种特殊模式在部分Bootloader实现中存在需要参考具体OEM的诊断规范确认。还有0x33securityAccessDenied也值得顺带提一下。如果安全解锁后过了一段时间再发0x36部分ECU的安全状态会超时锁定这时0x36会返回0x33需要重新执行27 01/02解锁。刷写工具的超时设置如果比ECU的安全锁定时间还长就很容易踩到这个。5. 实战排查方法论从现象到根因的完整链路5.1 必备的排查工具与日志记录习惯刷写问题排查工具链和日志习惯决定了效率。我个人常用的工具组合分三层。第一层是总线抓包工具。CANoe/CANalyzer是行业主流功能强大但价格不菲预算有限时PCAN-Explorer、周立功CANTest、同星TSMaster都是不错的替代。抓包时要开启时间戳精确到微秒级并且同时记录CAN错误帧和总线统计数据这对判断传输层问题至关重要。第二层是诊断交互日志。如果上位机用的是UDS诊断库比如python的udsoncan、C的Scapy或自研协议栈要把每次请求和响应的完整报文、NRC码、块序列计数器、时间戳都记录下来。我习惯把日志格式固定成CSV或JSON方便用脚本做计数器连续性分析。第三层是应用层业务日志。记录上位机当前的刷写阶段、固件文件偏移、期望的块序号、重传计数等业务状态。排查0x73时这三层日志放在一起对照基本能把问题缩小到具体模块。我自己保存日志的规范是文件名带日期、ECU软件版本、测试用例编号比如2025-01-15_ECU_v1.2_TC07_0x73.csv。这个习惯救过我很多次——有次隔了两周客户反馈0x72我翻出当时的抓包文件一比对发现和之前修复过的bug一模一样只是换了台ECU复现。没有基线数据排查真的得从零开始。5.2 两个典型故障案例拆解分享两个我实际处理过的案例能代表0x73和0x72常见的排查路径。案例一0x73反复出现在第128块附近。抓包发现第127块的0x36请求发了两次——第一次ECU处理完毕但正响应丢失上位机超时后重发ECU收到重复的块序号后返回0x73。但问题不止于此上位机重发后并没有把当前块的计数器恢复到127而是接着递增到128发送ECU期望128却收到了129于是连续报错。修复方案很简单超时重传时先从日志中还原最后一次ECU确认过的计数器值从这个值继续发。这个修复看似容易但在多线程架构的上位机里要保证计数器全局唯一且线程安全还是需要动点脑筋的。案例二0x72在最后一个数据块出现而且每次都是最后一个块。排查时把0x34的参数打出来一看发现memorySize固件实际大小-4096也就是少了一个块的大小。上位机传完最后一个合法块后还有4096字节的数据“无处安放”ECU在地址边界检查时直接报0x72。根因是0x34参数计算时用了旧的固件文件大小而实际发送的是新固件两者差了刚好一个块。定位这个问题的关键就是核对0x34参数和固件文件实际大小这个核对步骤应该做成刷写工具的自动校验而不是靠人工排查。5.3 一套可以复用的排查顺序最后给出一套我在项目中沉淀下来的排查顺序适用于0x36相关的绝大多数NRC问题。第一步确认上下文状态。检查当前会话是否编程会话10 02成功、安全等级是否解锁、0x34是否成功。这三个前置条件任何一个不满足后续0x36的任何NRC都不能直接当作0x36本身的问题来分析。第二步抓包看完整时序。从10 02到NRC出现的完整交互序列逐帧列出0x36请求的块序号和ECU响应。这一步能排除掉大量低级问题。第三步核对0x34参数。把0x34里的memoryAddress、memorySize、addressAndLengthFormatIdentifier解析出来和固件文件的实际大小、起始地址做比对。这一步专治0x72和0x31。第四步检查传输层。看总线统计里有没有错误帧、重试记录、总线关闭确认TP层是否丢帧。这一步专治0x73和超时问题。第五步检查ECU侧状态信息。读DID、读DTC、重新执行例程控制检查获取ECU内部的错误上下文。第六步用最小复现用例验证。如果以上都查不出问题就写一个最简脚本只做“0x34单个0x36块”逐步增加复杂度直到复现问题。这个过程往往能把疑似ECU的问题转化成确定的上位机问题。最后说一个我自己的体会0x36的NRC排查本质上是一种“分层归因”的过程。先从协议时序层找问题再从参数计算层找问题然后从传输层找问题最后才怀疑ECU实现。严格按照这个顺序大多数刷写故障都能在半小时内定位到根因而不是靠猜和试。希望这篇文章能帮你少踩几个我当年踩过的坑。

相关推荐

帕尔贴温控系统全链路设计:从PID到H桥的工业级实践
帕尔贴温控系统全链路设计:从PID到H桥的工业级实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 2:09:51

开源AI打码工具全解析:本地处理敏感信息,边缘羽化更自然
开源AI打码工具全解析:本地处理敏感信息,边缘羽化更自然

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 2:09:45

FineReport迁移实战:从选型到校验的完整避坑指南
FineReport迁移实战:从选型到校验的完整避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 2:09:39

AI正在拆掉传统界面:从表单到对话,人机交互的范式转移
AI正在拆掉传统界面:从表单到对话,人机交互的范式转移

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 2:57:29

Mosquitto 1.4.2 版本剖析:Broker 与客户端库关键缺陷修复详解
Mosquitto 1.4.2 版本剖析:Broker 与客户端库关键缺陷修复详解

后端消息队列消息路由 【免费下载链接】mosquitto Eclipse Mosquitto - An open source MQTT broker 项目地址: https://gitcode.com/gh_mirrors/mos/mosquitto 点击查看 免费下载 Mosquitto 1.4.2 是 Eclipse Mosquitto 在 2015 年 5 月发布的一个纯缺陷修复&… · 2026/9/24 2:57:23

Vue-ECharts 运行时更新机制深度解析:从快照规划、图形稀疏提交到主题边界的工程实现
Vue-ECharts 运行时更新机制深度解析:从快照规划、图形稀疏提交到主题边界的工程实现

前端图表库数据可视化 【免费下载链接】vue-echarts Vue.js component for Apache ECharts™. 项目地址: https://gitcode.com/gh_mirrors/vu/vue-echarts 点击查看 免费下载 本篇文章基于 Vue-ECharts 官方设计文档 docs/runtime-updates.md 及其源码实现&#xf… · 2026/9/24 2:57:17

Kornia RandomTransplantation 的 MPS 后端空轴过滤 Bug 修复解析(4160)
Kornia RandomTransplantation 的 MPS 后端空轴过滤 Bug 修复解析(4160)

计算机视觉人工智能深度学习图像处理 【免费下载链接】kornia 🐍 Geometric Computer Vision Library for Spatial AI 项目地址: https://gitcode.com/gh_mirrors/ko/kornia 点击查看 免费下载 导读 本文围绕 Kornia 版本迁移记录 changelog.d/migrati… · 2026/9/24 2:57:17

虚拟机USB加密狗直连难题:USB Network Gate实战指南
虚拟机USB加密狗直连难题:USB Network Gate实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 2:57:11

2025 geo搜索优化入门教程:助您轻松提升本地搜索排名【新手必看】
2025 geo搜索优化入门教程:助您轻松提升本地搜索排名【新手必看】

2025 geo搜索优化入门教程:助您轻松提升本地搜索排名【新手必看】您是否在为如何在激烈的市场竞争中脱颖而出而烦恼?在数字时代,geo搜索优化已成为企业,尤其是本地企业吸引目标客户的关键。本文将为您提供一份详尽的geo搜索优化入… · 2026/9/24 2:56:34

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码