一、CAN诊断网络分层
CAN诊断的网络分层参考OSI模型,该模型定义了网络互联的7层架构(物理层、数据链路层、网络层、传输层、会话层、表示层和应用层)。
CAN诊断通信包含了诊断应用层(ISO 15765-3/ISO14229)、网络层(ISO 15765-2)、数据链路层(ISO 11898-1)和物理层。应用层、表示层、会话层在DCM模块实现;传输层、网络层在CanTP模块实现
当前随着统一诊断(UDS)服务发展,诊断应用层已经基本使用ISO14229标准。我们今天CanTp模块就属于网络传输层,就是使用ISO15765-2标准。注意,这里可以把传输层和网络层放一起,都是由CanTp模块实现。
CanTp属于Can通信协议栈中的网络传输层,目前基本使用在诊断报文中,最终的AutoSAR规范中,CanTp也会适配通信报文,CanTp处于CanIf和PduR层之间,主要起到以下几个作用:
1)发送诊断报文的时候,把大于8byte的数据分段发出
2)接收诊断报文的时候,识别各帧是否是同一个诊断请求,并把同一个诊断请求的各帧的8个byte的数据重组起来,给到DCM
3)控制数据流(流控帧)
4)分段会话中的错误检测
5)发送取消
6)接收取消
下图是CanTP在Can网络协议栈中的位置,诊断报文会通过CanTp层,通信报文则直接通过CanIf给到PduR层:

二、SDU和PDU的区别
在诊断通信中,SDU(Service Data Unit,服务数据单元) 和 PDU(Protocol Data Unit,协议数据单元) 是两个核心概念,用于描述数据在通信协议栈不同层级间的传递与封装过程。它们的区别主要体现在内容构成、层级角色和功能用途上。
SDU(服务数据单元):是从上层协议传递下来的原始业务数据,不包含当前层的任何控制信息。代表当前层需要为上层提供的"服务内容",即纯用户数据。例如:在诊断通信中,SDU 可能是一个来自应用层的诊断请求(如 UDS 服务 $19 Read DTC Information)。
PDU(协议数据单元):是当前层在 SDU 基础上添加了本层协议控制信息(PCI)后形成的完整传输单元。包含 PCI(Protocol Control Information) + SDU,即:
PDU = PCI + SDU。用于对等实体(如发送方与接收方的同一协议层)之间的通信。
在诊断通信中的典型场景(以 AUTOSAR / CAN 为例)
Step1:应用层生成诊断请求(如 UDS 服务)→ 此为 SDU(无协议头)。
Step2:诊断传输层(CanTp) 将该 SDU 分段(若过大),并添加 N-PDU 头部(含地址、序列号等)→ 形成 N-PDU。
Step3:网络层/数据链路层 将 N-PDU 封装为 L-PDU(如 CAN 帧格式),添加 CAN ID、DLC、CRC 等 → 最终通过总线发送。
Step4:接收端逐层解封装:移除 PCI,还原出原始 SDU,交付上层处理。
注意:在分段传输(如 ISO-TP,ISO 15765-2)中,一个长 SDU 可能被拆分为多个 N-PDU;反之,多个短 SDU 也可能被拼接成一个 PDU 以提高效率。
三、CanTp组帧和拆帧过程
CAN诊断由发送端的请求与接收端的响应构成,诊断即为发送端与接收端数据往来。有的诊断一条消息完成,有的诊断需要多条消息完成,毕竟在诊断中,一条CAN消息只包含8个字节长度。对于一条CAN诊断消息的分段发送问题,即为网络层需要讨论的内容。
CanTp层传输的报文分为SF(单帧)、FF(首帧)、CF(连续帧)、FC(流控帧)4类。

PCI(Protocol Control Information)协议控制信息,包含了PDU单元类型和消息字节长度。

单帧传输
只传输一帧CAN报文(一帧N-PDU),称为SF,传输7byte(在正常地址情况下)数据字节的消息,byte0作为PCI使用。
SF(单帧):在发送端到接收端的请求仅为一条消息时,即为单帧(Single Frame),单帧数据格式如图,单帧第一个字节byte0为PCI,PCI的高4位为0,PCI的低4位为接下来准备传输的数据长度,从第二个字节byte1起为传输的数据(SID也作为数据)。从单帧的数据格式可以看出,真正的数据部分最多为Byte1~Byte7共7个字节长度,即CAN诊断数据发送长度得小于等于7个字节

单帧的报文发出去之后,接收端接收到这帧报文,会把这帧报文给到CanTP模块,CanTP模块会去解析PCI,看第一个字节的高4位为0,CanTP就知道这帧报文是单帧传输,不需要后面的连续帧,然后解析PCI的低4位的这个长度,比如说这个长度是3,表示单帧传输有效的数据只占3个byte,CanTP就取这三个Byte给到DCM

多帧传输
需要传输的数据比较多,就需要多帧来传输,发送过程中需要把N-SDU分割成多帧N-PDU来发送。接收过程中把多帧N-PDU重组发给上层。多帧传输分为首帧和续帧。
FF(首帧)
在多帧传输中,包括了首帧(FF)和连续帧(CF),接收端需要在收到首帧后回复流控帧(FC)。CAN诊断在传输多帧消息格式如下:

首帧格式如图所示,首帧第一个字节PCI的高四位为1,PCI低四位与第二个字节合起来为接下来传输的数据长度LEN,从第三个字节byte2起为传输数据。最大多帧长度为4095个字节

CF(连续帧)
连续帧格式如图所示,连续帧第一个字节PCI的高四位为2,PCI的低四位为帧计数器,第二个字节byte1起为剩余传出的数据。例如首帧已经传输了Data0,Data1...至Data5,则第一个连续帧接着传输Data6,Data7...至Data12,第二个连续帧接着传输Data13,Data14...,以此类推直至所有数据传输结束。
续帧SN从1开始,到15之后又返回1开始。(注意:FF发完后的第一个CF的SN为1)

FC(流控帧)
接收端在收到首帧后,会发出一个流控帧(不是诊断应答),第一个字节PCI的高四位为3,低四位为FS(FlowStatus),FS可以为0代表ContinueToSend(CTS),1代表Wait(WT),2代表Overflow(OVFLW),3-F为预留,通常我们遇到的值为0。

流控帧的作用在于接收端告知发送端接收能力,包含BlockSize(BS)和SeparationTimeMin(STmin)两个参数。
BS表示接收端允许发送端连续发送的最大连续N_PDU帧数,BS为0的时候告诉发送端可以发完剩余的全部N-PDU,BS为01-0xFF时,表示发送端可以发的连续帧最大帧数。STmin表示发送端发送连续帧的最小间隔时间

发送端收到接收端反馈的流控帧后,发送端会按照流控帧给出的接收能力进行发送连续帧,即连续传输的连续帧不超过BS,连续帧的发送间隔时间大于等于STmin。若接收端已经收满BS数量的数据,且与首帧中包含的数据长度对比发现数据还没接收满,则会继续发送流控帧,发送端会接着发送连续帧,以此类推,直至所有数据发送完成。
例1:用诊断仪读取某节点ECU的DID 0xF280,诊断仪需要发送0x22 0xF2 0x80 3个字节数据,多余数据用0xAA填充,写出诊断仪的请求数据
【分析】:该例子只需要发送3个字节数据,小于7个字节,所以单帧发送即可,单帧byte0高4位为0,低4位len=3,后面跟着发送的数据0x22 0xF2 0x80,其他数据使用0xAA填充
【答】诊断仪:0x03 0x22 0xF2 0x80 0xAA 0xAA 0xAA 0xAA
例2:用诊断仪写入某节点ECU的DID 0xF190(DID唯一指定一段内存),诊断仪需要发送0x2E 0xF1 0x90 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10共20个字节长度的数据,多余字节用0xAA填充,请写出诊断仪请求过程中与ECU之间的交互数据
【分析】:该例子需要发送20个字节长度数据,大于7个字节,所以需要利用多帧格式,首帧byte0的高4位为1,低4位与byte1为数据长度20,即0x10 0x14,后面再跟6个字节0x2E 0xF1 0x90 0x00 0x01 0x02;诊断仪发完首帧后,ECU端需要返回流控帧,byte0的高4位为3;第一个连续帧为byte0的高4位为2,低4位为1,后面跟7个字节0x03 0x04 0x05 0x06 0x07 0x08 0x09;第二个连续帧为byte0的高4位为2,低4位为2,后面跟7个字节0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10;
【答】:
诊断仪:0x10 0x14 0x2E 0xF1 0x90 0x00 0x01 0x02
ECU:0x30 BS STmin 0xAA 0xAA 0xAA 0xAA 0Xaa
诊断仪:0x21 0x03 0x04 0x05 0x06 0x07 0x08 0x09
诊断仪:0x22 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10