CANFD协议
概述: 通过MCU-STM32H743自带CANFD的收发进行了学习记录。
CAN是Controller Area Network的缩写,是ISO国际标准化的串行通信协议在当前的汽车产业中,出于对安全性、舒适性、方便性、低公害、低成本的要求,各种各样的电子控制系统被开发了出来,传统CAN总线最高传输速率为1Mbit/s,车载领域实际使用速率最高却仅为500Kbit/s,已然满足不了越来越高的数据吞吐量需求,因而CAN方案的瓶颈逐步凸显,尤其未来更多的ECU搭载终会导致总线负载率持续增加导网络拥堵。进而衍生出了CANFD协议,继承了CAN总线的主要特性。CAN总线采用双线串行通信协议,基于非破坏性仲裁技术,分布式实时控制,可靠的错误处理和检测机制,但CAN总线带宽和数据长度却受到制约,CANFD总线弥补了CAN总线带宽和数据场的制约。
如下为车载构想示意图:
要了解CANFD协议就要先了解CAN协议遵循的电平标准。
差分信号:
CAN总线上传输的信号为差分信号,所谓差分信号区别于传统的一根信号线一根地线的做法,差分传输在两根线上传输信号,这两个信号的振幅相同,相位相反。
CAN信号的差分信号线为CAN_H与CAN_L,传输一帧数据CAN_H与CAN_L信号线上的波形如下图所示:
CAN_H: 通道一(黄色)
CAN_L: 通道二(蓝色)
显性电平与隐形电平:
总线上的电平有显性电平和隐性电平两种,CAN收发器根据总线(CAN_High 和CAN_Low)的电位差来判断总线的电平。
总线上执行逻辑上的线“与”时,显性电平的逻辑值为“0”,隐性电平为“1”。如下图所示:
“显性”具有“优先”的意味,只要有一个单元输出显性电平,总线上即为显性电平。并且,“隐性”具有“包容”的意味,只有所有的单元都输出隐性电平,总线上才为隐性电平。 (显性电平比隐性电平更强。)
为什么CAN总线默认电平不是0V?查看ISO11898标准:
显性电平(逻辑0): CAN_H为3.5V,CAN_L为1.5V
隐性电平(逻辑1): CAN_H为2.5V,CAN_L为2.5V
实测一帧数据:
CAN_H:
CAN_L:
●可变位速率
CAN-FD采用了两种位速率:从控制场中的BRS位到ACK场之前(含CRC分界符)为可变速率,其余部分为原CAN总线用的速率。.两种速率各有一套位时间定义寄存器,它们除了采用不同的位时间单位TQ外,位时间各段的分配比例也可不同。.
●新的数据场长度
CAN-FD对数据场的长度作了很大的扩充,DLC最大支持64个字节,在DLC小于等于8时与原CAN总线是一样的,大于8时有一一个非线性的增长,在无位填充的情况下,最大数据传输效率为91.59%(512/559)。
表示数据帧开始的段,1个位的显性位。
所谓1个位的显性(下图是CANFD的波形,只是为了表明一个显性位):
表示该帧优先级的段,标准格式和扩展格式在此的构成有所不同。
标准格式的ID有11位。从ID28到ID18被依次发送,禁止高7位都为隐形(禁止设定:ID=1111111XXXX)。
扩展格式的ID有29位。基本ID从ID28到ID18,扩展ID由ID17到ID0表示。基本ID和标准格式的ID相同。禁止高7位都为隐形(禁止设定:ID=1111111XXXX)。
表示数据的字节数以及保留位的段,有6个位组成,标准格式和扩展格式在此的构成有所不同。
保留位(r0、r1):
保留位必须全部以显性电平发送。但接收方可以接收显性、隐形以及任意组合的电平。
数据长度码(DLC):
数据的字节数必须为0-8字节。但接收方对DLC=9-15的情况并不视为错误。数据长度码与数据的字节数的对应表如下所示:
数据的内容,可以发送0-8字节的数据,从MSB(最高位)开始输出。
检查帧的传输错误的段,由15个位的CRC顺序和1个位的CRC界定符(用于分隔的位)构成。
CRC顺序:
CRC顺序是根据多项式生成的CRC值,CRC的计算范围包括帧起始、仲裁段、控制段。接收方以同样的算法计算CRC值并进行比较,不一致时会通报错误。
表示确认正常接收的段,由ACK槽(ACK Slot)和ACK界定符2个位构成。
发送单元的ACK段:
发送单元在ACK段发送2个位的隐形位。
接收单元的ACK段:
接收到正确消息的单元在ACK槽(ACK Slot)发送显性位,通知发送单元正常接收结束。
➢EDL位: ( Extended Data Length)原CAN数据帧中的保留位r,该位功能为:
隐性:表示CAN-FD报文
显性:表示CAN报文
➢BRS位: ( Bit Rate Switch)该位功能为:
隐性:表示转换可变速率
显性:表示不转换速率
➢ESI位: ( Error State Indicator),该位的功能为:
隐性:表示发送节点处于被动错误状态( Error Passive)
显性:.表示发送节点处于主动错误状态( Error Active)
CANFD一帧最多可以传输64字节,DLC重新定义如下:
CANFD数据帧采用新的DLC编码方式,在数据场长度为0-8字节时,采用线性规则,数据场长度为12-64字节时,使用非线性编码。
CANFD采用新的CRC算法(CRC场扩展到了21位):
根据数据场的长度,采用不同的CRC,如CRC_17(0-16Bytes),CRC21(17-64Bytes)。
STM32FH743自带的是 FDCAN 它支持 CAN协议 2.0A、 2.0B和 CAN FD V1.0。它的设计目标是,以最小的 CPU负荷来高效处理大量收到的报文。它也支持报文发送的优先级要求 (优先级特性可软件配置 )。对于安全紧要的应用, FDCAN1提供所有支持时间触发通信模式所需的硬件功能 。
STM32FH743的 FDCAN的主要特点有:
⚫ 支持 CAN协议 2.0A、 2.0B和 CAN FD V1.0。
⚫ CAN FD模式下 波特率 >5Mbps
⚫ 支持时间触发通信 ,仅 FDCAN1支持
⚫ CAN FD模式下一帧数据最高可达 64个字节。
⚫ 支持 AUTOSAR和 J1939
⚫ 两个可配置的接收 FIFO
⚫ 64个专用接收 buffer。
⚫ 32个专用发送 buffer。
CANFD框图如下所示:
①、双中断线
从图中可以看出, FDCAN提供了两个中断线: fdcan_intr0_it和 fdcan_intr1_it。可以通过寄
存器 FDCAN_ILE的 EINT0和 EINT1这两个位来使能或者关闭这两个中断。
② 、 CAN内核
CAN Core包含协议控制器和收发移位寄存器,它支持 ISO 11898 1:2015的所有协议功能,支持 11位和 29位 ID。
③、同步
Sync同步单元用于同步 APB时钟信号和 CAN内核时钟。
④ 、 发送 处理
TX Handler负责将消息 RAM中的数据发送到 CAN内核,最多可以给发送单元配置 32个发送 buffer。
⑥ 、接收处理
RX Handler负责将 CAN内核的数据传输到外部消息 RAM中, RX Handler支持两个接收FIFO,每FIFO可以配置 64个专用的 buffer。
⑦ 、 APB接口
连接 FDCAN到 APB总线上。
⑧ 、消息 RAM接口
STM32H743的 FDCAN在消息 RAM实现了过滤器、接收 FIFO、接收 buffer、 发送事件 FIFO和发送 buffer。 消息 RAM是 FDCAN1和 FDCAN2共享的,是一段10KB的内存, 消息RAM的存分配如图:
消息RAM中一个元素的大小为32位(4字节)。因此10KB的RAM一共有10×1024/4=2560个元素。图中左侧是为RAM分配的区域,来看一下这个区域是怎么分配的:
SIDFC.FLSSA :这个区域用来存放11位过滤ID,此区域占用128个字(1个字=4字节)。
XIDFC.FLESA:这个区域用来存放29位过滤ID,此区域用了64字,一共有128字。
RXF0C.F0SA:接收 FIFO0 这个区域用了 64个字,一共有 1152个字。
RXF1C.F1SA:接收 FIFO1,这个区域用了 64个字,一共有 1152个字。
RXBC.RBSA:接收 buffer,这个区域用了 64个字,一共有 1152个字。
这三个分别为 Rx FIFO0、 Rx FIFO1和 Rx buffer,这三个的 bit含义都是一样的,见图:
TXEFC.EFSA :发送事件 FIFO,这个区域用了 32个字,一共有 64个字。
TXBC.TBSA :发送 buffer,这个区域用了 32个字,一共有 576个字。
TMC.TMSA :触发内存,这个区域用了 64个字,一共有 128个字。
由发送单元在非同步的情况下发送的每秒钟的位数称为位速率。一个位可分为 4 段。
⚫ 同步段(SS)
⚫ 传播时间段( PTS)
⚫ 相位缓冲段 1( PBS1)
⚫ 相位缓冲段 2 (PBS2)
这些段又由可称为Time Quantum(Tq)的最小时间单位构成。
1 位分为 4 个段,每个段又由若干个 Tq 构成,这称为位时序。
1 位由多少个 Tq 构成、每个段又由多少个 Tq 构成等,可以任意设定位时序。通过设定位时序,多个单元可同时采样,也可任意设定采样点。各段的作用和Tq 数:
1个位的构成如下图组成:
采样点:是指读取总线电平,并将读到的电平作为位值的点,位置在PBS1结束处,通过这个时序可以计算出具体的采样点和CAN通信的波特率。
在STM32H743中CANFD的波特率是通过位时间来设置的。STM32H743的CANFD位时间有 3段:同步段(SYNC_SEG)、时间段1 (BS1)和时间段 2 (BS2)。 STM32H743的同步段长度为 1个时间单元 tq BS1段可以设置为 1-16个时间单元 tq ,BS2段可以设置 1~8个时间单元 tq。
STM32H743中CANFD波特率及采样点计算如下:
CANFD_Baudrate=Clk /(Pres *(Seg1 +Seg2 +1))
Sampling_Point=1-(Seg2/(Seg1+Seg2+1))
其中:
Clk: 系统时钟
Pres: 分频系数
Seg1: 寄存器seg1的值
Seg2: 寄存器segd2的值
CANFD速率1M-5M代码配置(CANFD时钟频率配置的是80M):
hfdcan1.Init.NominalPrescaler = 1; //仲裁场-分频系数
hfdcan1.Init.NominalSyncJumpWidth = 12; //仲裁场-SJW
hfdcan1.Init.NominalTimeSeg1 = 67; //仲裁场-Seg1
hfdcan1.Init.NominalTimeSeg2 = 12; //仲裁场-Seg2
hfdcan1.Init.DataPrescaler = 1; //数据场-分频系数
hfdcan1.Init.DataSyncJumpWidth = 4; //数据场-SJW
hfdcan1.Init.DataTimeSeg1 = 11; //数据场-Seg1
hfdcan1.Init.DataTimeSeg2 = 4; //数据场-Seg2
仲裁场速率: CANFD_Baudrate=80/(67+12+1)=1M
仲裁场采样点: 1-(12/(12+67+1))=85%
数据场速率为: CANFD_Baudrate=80/(11+4+1)=5M
数据场采样点: 1-(4/(4+11+1))=75%
FDCAN提供了过滤器设置, 通过过滤器可以设置允许接收哪些 ID的消息。前面讲解消息
RAM的时候详细的讲过 SIDFC.FLSSA和 XIDFC.FLESA这两个域,分别为标准 ID过滤器和扩展 ID过滤器。标准 ID过滤器有三种过滤模式:
通过 SIDFC.FLSSA的 SFID1和 SFID2来设置需要过滤的 ID范围, 其中 SFID2的值要大于 SFID1,这样只有 ID值在 SFID1-SFID2之内的消息才能被接收到。 比如我们现在要设置 只接收 ID在 0X123-0X321范围内的消息,使用标准滤波器 n, SIDFC.FLSSAn (n=0~128)的各个位设置如下:
SIDFC.FLSSAn.SFT=0 //范围滤波
SDIFC.FLSSAn.SFEC=1 //如果滤波匹配成功的话将消息保存到 Rx FIFO中
SDIFC.FLSSAn.SFID1=0x123 //ID1
SDIFC.FLSSAn.SFID2=0X321 //ID2
我们也可以设置只接收指定的一个或者两个 ID的消息,如果只接收指定的一个 ID消息的
话 SFID1=SFID2。比如我 们要设置只接收 ID为 0X123的消息,设置如下:
SIDFC.FLSSAn.SFT=1 //指定 ID过滤
SDIFC.FLSSAn.SFEC=1 //如果滤波匹配成功的话将消息保存到 Rx FIFO中
SDIFC.FLSSAn.SFID1=0x123 //ID1
SDIFC.FLSSAn.SFID2=0X123 //ID2
第三种过滤模式就是以前STM32的 CAN上存在的位过滤模式, 在屏蔽位模式下,过滤消
息 ID和过滤掩码一起工作决定接收哪些消息,其中 SFID1为过滤的消息 ID SFID2为过滤掩
码。举个简单的例子,我们设置过滤器
SIDFC.FLSSAn工作在:传统位过滤模式,然后设置如下:
SIDFC.FLSSAn.SFT=2 //传统位过滤
SDIFC.FLSSAn.SFEC=1 //如果滤波匹配成功的话将消息保存到 Rx FIFO中
SDIFC.FLSSAn.SFID1=0XFF00 //ID1
SDIFC.FLSSAn.SFID2=0XF000 //掩码
其中 SFID1是我们期望接收到的消息 ID,我 们希望最好接收到 ID=0XFF00的消息。 SFID2的 0XF000规定了我们必须关心的 ID,也就是接收到的消息 ID其位 [15:12]必须和 SFID1中的
位 [15:12]完全一样,其他的位不关心。也即是说接收到的消息 ID必须是 0XFFxx这样的才算正
确 (x表示不关心 )。
STM32H743ID完整ID过滤代码:
//配置FDCAN1 RX滤波器
FDCAN1_RXFilter.IdType=FDCAN_EXTENDED_ID; //扩展 ID
FDCAN1_RXFilter.FilterIndex=0; //滤波器索引
FDCAN1_RXFilter.FilterType=FDCAN_FILTER_DUAL; //滤波器类型(包含以上所说的三种)
FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0; //过滤器0关联到FIFO0
FDCAN1_RXFilter.FilterID1=0x1182000; //
FDCAN1_RXFilter.FilterID2=0x1182000; //如果FDCAN配置为MASK的话,这里是29位掩码
HAL_FDCAN_ConfigFilter(&hfdcan1,&FDCAN1_RXFilter);//滤波器初始化
HAL_FDCAN_ConfigGlobalFilter(&hfdcan1,FDCAN_REJECT, FDCAN_REJECT, DISABLE, DISABLE);//FDCAN_ACCEPT_IN_RX_FIFO0 全局滤波器设置
HAL_FDCAN_Start(&hfdcan1); //开启FDCAN 配置完RX FLITER之后开始CANFD1
HAL_FDCAN_ActivateNotification(&hfdcan1,FDCAN_IT_RX_FIFO0_NEW_MESSAGE,0);
待更…