多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

UDS时间参数详解:P2/P2*、S3与网络层N_*配置实战

UDS时间参数详解:P2/P2*、S3与网络层N_*配置实战 做UDS诊断开发的人大概都经历过这种时刻测试工程师跑过来说“诊断仪报超时了”你打开CANoe的Trace一看ECU明明回了报文但距离请求晚了那么几十毫秒或者是刷写的时候上位机报了个网络层超时错误可数据明明一直在发还有一种更隐蔽的车停在某个非默认会话里不动了过一会儿再去看ECU自己退回了默认会话导致后面一连串诊断流程全部乱掉。这些问题的根源十有八九都出在UDS的时间参数上。标题虽然写的是“网络层时间参数”但实际联调的时候你会发现UDS的时间参数分布在诊断通信的三个层面上应用层、会话层、网络层传输层。ISO 14229-1管的是应用层和会话层的P2、P2*、S3ISO 15765-2管的是CAN网络层的N_As、N_Bs、N_Cs这一族。真正排查问题的时候三层参数都得心里有数否则就是盲人摸象。这篇文章我打算把UDS时间参数这块一次讲透从标准定义到实际配置从刷写到排障把我这些年踩过的坑和积累的经验都放进来。适合刚接触诊断协议栈开发的工程师也适合被超时问题折磨到头秃的集成测试人员。1. 先说清楚UDS里的时间参数到底管什么1.1 诊断通信的三层模型时间参数藏在哪一层UDSUnified Diagnostic Services统一诊断服务跑在车载网络上最常见的是CAN/CAN FD也有DoIP、LIN等。为了把问题分析清楚业内一般把诊断通信拆成三层应用层、会话层、网络层传输层。应用层处理的是“服务语义”比如0x22读数据、0x2E写数据、0x31例程控制、0x34/36/37刷写。这一层关心的时间参数主要是P2和P2*也就是ECU处理一个服务请求所允许的最大时间。会话层管理诊断会话的建立和维持核心参数是S3Server和S3Client决定了非默认会话能“挂机”多久。网络层在CAN上对应ISO 15765-2也就是常说的CAN TP负责把上层的一大包数据拆成单帧、多帧发送和重组。这一层的时间参数是一堆N_开头的计时器外加STmin和BlockSize。DoIP对应的则是ISO 13400-2但这里先以CAN为主。把这层搞清楚了80%的“响应超时”问题都能定位。很多人一说“网络层时间参数”第一反应就是把ISO 15765-2里的N_*背一遍。但我建议先反过来想这些时间参数本质上是给通信双方约定了一套“等待耐心”。每一方都觉得自己等得太久就会主动放弃、报错或者重传。搞清楚了谁在等谁、等了多久、等不到会干什么比死记硬背参数名有用得多。1.2 三个逃不掉的时间参数P2、P2*、S3先讲三个“出场率”最高的因为它们几乎出现在每一份UDS需求文档和每一轮联调问题单里。P2Server_max标准默认值50ms。这是ECU从收到请求到发出首帧响应正响应或负响应的最大时间。不要把它理解成“ECU处理一个服务要50ms”它只是给诊断仪的等待设了一个上限——你ECU处理得快慢是你的本事但超过50ms还没把响应发出来就要走P2*的通道了。P2Server_max标准默认值5000ms。当ECU在50ms内给不了一个完整的响应时它先回一个NRC 0x78responsePending告诉诊断仪“还在忙”然后被允许用最多5000ms来完成后继响应。比如0x31例程控制中的擦除Flash操作或者0x27安全解锁中某些慢速算法都会用到P2。S3Server默认5000ms。它不是针对单个服务的而是针对整个诊断会话的。只要ECU在非默认会话里并且在S3Server时间内没有收到任何诊断请求它就会自动退回默认会话。这里的“任何诊断请求”包括3E 10这样的会话保持报文。车载以太网和CAN都适用这个逻辑。这三个参数一个管单次响应的快慢一个管慢响应的宽限一个管会话的存续。实际配置和联调中它们之间的配合远比单个参数本身复杂。下面我分别展开。2. 会话层时间参数P2与P2*超时问题的头号背锅侠2.1 P2和P2*的标准定义与真实逻辑ISO 14229-1里对P2Server和P2Server的描述读起来有点绕但翻译成人话就是诊断仪发出请求后开始计时ECU必须在P2Server时间内回一个响应帧如果ECU判断自己做不到必须快速回一个NRC 0x78之后ECU在P2Server时间内给出最终响应。这个“先发0x78再干正事”的机制是UDS里很经典的一种异步处理模式。有一个细节特别容易踩P2Server计时的是“收到请求帧”到“发出响应帧首帧”的时间不是“完成服务处理”的时间。如果服务的结果数据很长响应是多帧报文那么只要第一帧FF或SF发出去了P2计时就算过关。剩下的多帧传输由网络层的N_*参数来管。联调时如果看到ECU处理很慢但响应第一帧发得很快多半就是代码里先把首帧发出去了再把剩余数据慢慢补上。这种方式合法但会给测试方造成一种“ECU响应挺快”的假象实际吞吐量可能不高。P2的触发逻辑也一样。很多ECU实现里只要在P2Server超时阈值附近还没有完成数据处理就会无条件先发0x78。于是你会在Trace里看到请求-0x78-大量时间间隔-最终响应。这个间隔的允许上限就是P2Server_max。如果P2*也超了诊断仪就会直接报超时或者显示“ECU无响应”而ECU这边可能还在闷头处理最后发现自己发出去一个响应但诊断仪已经不听了这就是典型的“单方面通信”。2.2 诊断仪侧的时间参数怎么配才不会误判ECU侧的P2Server/P2Server是ECU须满足的指标诊断仪侧也有对应的P2Client/P2Client。很多联调问题恰恰出在这里ECU厂商说P2Server_max50ms但诊断仪侧把P2Client也配成了50ms两边几乎一样稍有抖动就会误判。我的建议是诊断仪侧的P2Client必须大于ECU侧的P2Server留出报文传输和处理余量。行业里常见的做法是P2Client设成55~60msP2*Client设成5100~5200ms。这样既不会放过真实的超时也不会因为微小的总线延迟误杀正常响应。另外要注意P2Server/P2Server并不是一个全局固定值。ECU在不同的诊断会话、不同的服务下完全可以有不同的P2阈值。比如默认会话下0x22读数据很快P2用50ms没压力但进入编程会话后0x34请求下载可能涉及擦写操作P2就得放宽到几秒甚至更长。CANdelaStudio里就能按会话和按服务配置这些时间值刷写流程中常见的“P2*拉长到2000ms、3000ms”就是这么来的。联调时先确认当前会话和时间参数配置再去查响应超时顺序千万别反了。2.3 应用层S3Server和S3Client的配合S3Server这个参数功能上像一个“保活倒计时”。ECU处于非默认会话时持续接收请求就会重置这个倒计时一旦倒计时归零ECU自动退回默认会话并且会中止一些正在进行的操作比如未完成的安全解锁。这样做是出于安全考虑——如果诊断仪异常掉线ECU不能一直停留在高权限的会话里。实际项目中S3Server默认配5000ms但也见过配2000ms、10000ms的。配短了联调时稍微停顿一下就掉会话体验很差配长了万一诊断仪掉线ECU长时间暴露在高权限会话里有安全风险。所以没有绝对的好坏看项目需求。S3Client是诊断仪侧的会话超时判断值它必须小于S3Server。为什么因为诊断仪需要比ECU更早地意识到“会话可能断了”然后主动发3E 10保活这样才能确保会话不中断。如果S3Client等于甚至大于S3ServerECU可能已经退回默认会话了诊断仪还傻乎乎地在非默认会话里继续发请求然后收到一堆NRC 0x7F服务不支持或子功能不支持排查起来相当迷惑。一般来说S3Client配S3Server的70%~80%比较稳妥比如S3Server5000msS3Client就配4000ms。3E 10的发送周期则要明显小于S3Client常见做法是2000ms发一次留足余量。3. 网络层传输层时间参数ISO 15765-2的N_*家族3.1 N_As、N_Ar、N_Bs、N_Br、N_Cs、N_Cr分别管什么当消息超过单帧容量CAN经典帧单帧最多7字节数据CAN FD是64字节就要走多帧传输。ISO 15765-2定义了一套完整的状态机和计时器用来保证多帧传输不卡死、不丢包。这一族参数就是“网络层时间参数”的本体。N_As从上层把数据交给网络层到网络层把这一帧报文成功发到CAN总线上的最大时间。它涵盖排队、组帧、发送。如果总线忙或者被大量报文阻塞N_As就容易超时。标准默认值通常是1000ms高优先级消息可以配250ms。N_Ar发送方等待接收方确认接收的时间本质上也是1000ms级别。在CAN这种广播式总线上发送方发完一帧后能从CAN控制器的发送确认里知道自己发出去了N_Ar更多用在对端确认的场景。N_Bs发送方发出首帧FF之后等待接收方回复流控帧FC的最大时间。这是多帧传输里最容易出问题的地方如果ECU的接收缓冲区没有准备好或者接收方上层软件处理慢FC就会迟迟不来发送方等到N_Bs超时后直接中止传输并报错。N_Br接收方收到首帧后发送流控帧之前允许消耗的时间。它和N_Bs是一对一个站在发送方视角一个站在接收方视角。正常情况下BS块大小决定发多少帧等一次流控STmin决定连续帧之间的最小间隔这两个参数配合起来接收方完全可以通过流控帧控制发送节奏。N_Cs连续帧之间的时间间隔。N_Csmin就是STmin由发送方在流控帧里指定N_Csmax是连续帧之间的最大允许间隔默认也是1000ms级别。如果发送方发连续帧发得太慢超过N_Csmax接收方会判定传输超时。N_Cr接收方等待下一帧连续帧的最大时间。发送方长时间不发接收方就会N_Cr超时丢弃整个多帧消息。说白了这一族参数就是给多帧传输的每个环节都设了一道“等待截止时间”。任何一环超时整个诊断消息都会被判定失败。3.2 多帧传输中的STmin和BlockSize才是真主角N_*参数一般是协议栈的兜底超时正常通信时很少触发。真正影响通信节奏、也最值得手动调整的是流控帧里的STminSeparation Time minimum和BlockSizeBS。STmin决定了发送方连续两帧之间的最小间隔。它是一个字节的十六进制值0x00~0x7F表示0~127ms0xF1~0xF9表示100us~900us0x80~0xF0是保留值。比如STmin0x10表示连续帧之间至少间隔16ms0xF4表示400us。对于CAN FD的快速传输工程师经常配0xF1~0xF9把间隔压到微秒级就是为了追求吞吐量。BlockSize表示允许发送方连续发送的连续帧数量上限发满这个数量后必须等接收方再发一个流控帧才能继续。BS0表示不限制发送方可以一直发。BS4就是发4帧等一次流控。BS的主要作用是给接收方一个“喘口气”的机会——如果接收方处理速度跟不上通过较小的BS就能把节奏放慢避免缓冲区溢出。联调时遇到“高负载下丢帧”“刷写速度上不去”这些问题不要一上来就怀疑硬件或驱动。先看Trace里连续帧之间有没有正常的STmin间隔再看BS有没有频繁触发多余的流控帧。很多时候只要调整一个STmin或BS问题就解决了。3.3 网络层参数在不同协议栈中的映射还有一个很容易让人困惑的点ISO 15765-2里的N_*参数到了不同协议栈、不同工具里名字会变。比如AUTOSAR的CanTp模块里对应N_As/N_Ar的参数叫Ns、NrN_Bs/N_Br叫Nbs、Nbr配置起来一堆缩写看起来很像但又不完全一样。Vector的工具链里CANoe的CAN TP配置界面叫法又不同。所以看协议栈配置文件时先对照标准把每个参数确认清楚别凭感觉填。顺便说一个搜索热词“P4.2网络层”。在我接触过的一些诊断工具链和网联设备配置里P4这个名称并不是ISO标准术语更像是某些工程团队内部对“增强超时”或“网络层等待时间”的称呼。具体到某个设备说明书里P4.2可能指代的是某个固定超时值或一组参数。遇到这种标准之外的名字最好的办法是回到协议层的三个层面问清楚它映射的是会话层的P2*、应用层的S3还是网络层的N_*然后再对号入座去配置。4. 典型诊断场景下的时间参数实战4.1 刷写流程中的时间参数配置刷写Flash Programming大概是时间参数表现最极端的场景。刷写流程里典型用到0x10编程会话、0x27安全解锁、0x31例程控制擦除、0x34请求下载、0x36传输数据、0x37退出传输最后还可能做0x11复位。编程会话下0x31例程擦除Flash时ECU可能要几十毫秒甚至几百毫秒才能完成。如果P2Server还按50ms来配ECU必然回0x78然后占用P2*。但如果P2只给了5000ms碰上大扇区擦除依然可能不够。所以很多ECU在编程会话里会把0x31的P2大幅拉长比如配到10000ms甚至更高同时P2保持50ms不变。这样设计的好处是快操作还是50ms内快速响应慢操作则通过0x78机制慢慢来最终在P2*的宽限内完成。0x36传输数据阶段考验的是网络层参数。假设每包数据是64字节CAN FDECU接收后还要写入Flash写入时间通常在几毫秒到几十毫秒。如果上位机一股脑把连续帧发完ECU的接收缓冲区会溢出。这时候就需要ECU在流控帧里设置合适的BS和STmin比如BS8STmin0x50约80ms让上位机每发8帧就等一次流控ECU借机会把数据从缓冲区落盘到Flash。我见过很多刷写失败的案例原因就是ECU把STmin设成了0BS也设成了0结果在Flash写入期间缓冲区爆掉N_Cr或者N_Bs超时刷写到一半中断。退一步说如果上位机软件比较老不太会处理复杂的流控帧组合ECU的流控参数设计得越保守越稳定。刷写不像通信性能竞赛稳定不出错才是第一位。4.2 19服务多帧响应的时间考验0x19服务读取DTC信息是另一个典型的多帧场景。读取所有DTC快照时ECU可能返回几十甚至上百KB的响应数据单帧肯定装不下需要拆成大量连续帧。这时候网络层时间参数对用户体验的影响非常直接。假设ECU把STmin配得很小比如0xF1100us连续帧以极快速度发出但诊断仪那边接收缓冲区不够大处理不过来就会出现接收方N_Br超时或直接丢帧。反过来如果STmin配得太大读大容量DTC信息时会明显感觉卡顿。所以合理的做法是STmin根据诊断仪能力来权衡一般建议不低于0x055ms左右同时把BS设成一个大点的值让发送方能够持续发送减少不必要的流控帧往返。另外19服务的响应时间同样受P2/P2约束。如果ECU收集DTC快照需要较长时间就必须在P2Server内先回NRC 0x78再在P2Server时间内把多帧响应发完。有些ECU为了省事干脆不做异步处理直接把所有数据都准备好了才会发首帧导致首帧都要好几百毫秒这在实际项目中会引发诊断仪超时。做ECU软件的同学这里可以自查一下协议栈有没有用异步响应机制。4.3 用CANoe实测时间参数的方法排查时间参数问题最实用的工具还是CANoe。我常用的方法是在Trace窗口里加上“Timestamps”列每个报文的时间戳精确到微秒级。然后人为触发一个诊断请求在Trace里选中请求报文和响应报文看两者时间戳的差值就能大致估算P2响应时间。但有一点要注意Trace窗口显示的是报文在CANoe这个节点上收发的时刻它和ECU实际收到/发出报文的时刻之间有总线传输延迟在CAN上这个延迟是微秒级一般可以忽略如果是CAN FD或者车载以太网延迟略大但通常也不至于影响P2的判断。所以用CANoe测出来的时间拿来评估是否超时是足够的。更精确的测量方法是写一段CAPL脚本用on message事件和timer来做计时。我习惯在脚本里维护一个请求序号收到诊断请求时启动一个ms定时器收到响应时停止然后打印出精确的响应时间。这样批量测试时能自动记录每个服务的响应时间方便输出测试报告。如果项目里用了Vector的Diagnostic Console也可以直接在“Diagnostic Request”和“Diagnostic Response”视图里看到响应时间栏省去自己写脚本的工夫。5. 常见问题与踩坑实录5.1 问题速查表这些年我接触过不少诊断联调问题很多都和本文讲的时间参数有关。这里整理成一张速查表方便大家排查时对照。现象可能原因排查方向诊断仪报“请求超时”ECU明明回了NRC 0x78P2*Client配置小于ECU实际处理时间检查诊断仪侧P2*Client值和ECU侧最长响应时间收到0x78后再无响应诊断仪超时P2*Server超时ECU处理逻辑卡死或耗时过长查ECU侧慢处理任务的调度与优先级非默认会话莫名退回默认会话S3Server超时诊断仪保活报文发送周期太长检查3E 10发送周期和S3Client/S3Server配置多帧传输卡住发送方报N_Bs超时接收方未及时回复流控帧查接收方CAN TP接收缓冲区和上层处理速度刷写过程中频繁中断流控帧BS/STmin配置不合理缓冲区溢出查看流控帧参数和实际连续帧发送间隔连续帧间隔不稳定偶发丢帧STmin过小接收方来不及处理适当加大STmin或减小BS高总线负载下诊断超时N_As/N_Ar设置偏小报文仲裁延迟查看总线负载率适当放宽N_*参数这个表只能作为排查起点。真实项目中一个现象背后往往嵌套了多个问题尤其是涉及Bootloader和APP通信、CANoe仿真节点共存时需要逐层看Trace确认。5.2 我踩过的几个坑第一个坑是P2被配置成和P2一样的值。早年我调试一个ECU时供应商代码里P2Server和P2Server都写的50ms结果所有稍慢的服务全部超时。因为ECU发完0x78之后诊断仪按照P2Client5100ms在等按理说没问题但ECU侧协议栈自己内部在P2Server超时后主动丢弃了响应导致诊断仪什么都没等到。所以ECU侧P2*Server一定要比P2Server大得多否则0x78机制形同虚设。第二个坑是3E 10保活报文和服务响应时间打架。有段时间我发现ECU总是莫名其妙从扩展会话退回默认会话查了很久才发现是诊断仪发送3E 10的周期虽然是2000ms但测试人员在做某些长时间例程测试时上位机主线程被阻塞3E报文延迟了好几秒超过了S3Server。这属于应用层调度问题不是参数配置问题但表现上非常像参数配错了。排查时记得把测试工具侧的调度延迟也考虑进去。第三个坑是Bootloader刷写时网络层参数和APP不一样。有些ECU在APP里把STmin配得比较小追求快速诊断到了Bootloader里Flash驱动占资源处理速度下降但参数没改结果刷写时连续帧发太快缓冲区溢出刷写成功率很低。后来我把Bootloader里的STmin调大到5msBS调到4刷写就稳定了。同一个ECU在不同模式下完全可以有不同的网络层参数不要想当然沿用一套配置走天下。5.3 参数设置的个人心得做诊断时间参数配置我最大的体会是留余量、分层看、先跑通再优化。留余量是指所有时间参数都不要贴着极限值配。比如ECU最快处理速度是20ms那就不要把P2Server配成20ms。因为总线抖动、负载波动、温度变化都可能让处理时间变长。一般建议至少留出30%~50%的余量或者直接采用标准的50ms和5000ms除非有明确的性能指标压力。分层看是指发生超时问题后按应用层-会话层-网络层一层层排查。先确认是P2/P2*问题还是S3问题再确认是不是多帧传输的STmin/BS问题不要一上来就调N_As/N_Bs。很多时候问题根本不在网络层却被当成网络层参数调了半天浪费时间。先跑通再优化是刷写这类功能的基本策略。第一次联调时把BS设小一点STmin设大一点优先保证每一次刷写都能成功完整地跑完。然后记录整包数据的传输总时间作为基线再逐步调小STmin、调大BS观察刷写时间和成功率的变化找到一个安全的最优值。回到开头那些“玄学”超时问题其实一点都不玄。时间参数的本质是通信双方对“等待耐心”的约定只要把每一层是谁在等谁、等多久、等不到怎么办这三个问题理清大部分问题都能在几分钟内定位。希望这篇文章能帮你在下一次面对“诊断仪超时”的时候少走点弯路。
返回列表