MCAL - CAN(NXP - S32K14x)
- 配置工具:EB Tresos Studio
- 芯片类型:S32K146
1. 概述
S32K146内部FlexCan模块结构如上图所示,各模块功能介绍如下:
-
Bus Interface Unit:总线接口,建立与其他模块之间的访问(DMA/中断/时钟…)
-
Controller Host Interface:
- Tx Arbitration:发送仲裁
- Rx Matching:接收匹配
-
Message Buffers:数据缓存区
-
Protocol Engine:
- CAN FD监测
- 错误处理
- 接收验证
- 请求RAM访问以接收和发送数据帧
1.1 邮箱
1.1.1 邮箱资源
S32K14x系列FlexCan资源如上图所示,S32K146有三个FlexCAN模块且有2个支持CAN FD功能,其中FlexCAN0和FlexCAN1拥有32个邮箱,FlexCAN2拥有16个邮箱,以上邮箱个数是基于数据长度为8Byte
时的邮箱个数,长度为16/32/64Byte
时邮箱个数如下图所示:
1.1.2 邮箱构成
邮箱结构
如上图所示,前8个字节包含了报文的基本信息,后面是报文的数据,最多可以存放64个字节,各字段功能如下:
- EDL:CAN / CAN FD
- BRS:CAN FD帧格式的速率切换
- ESI:标识发送节点是错误主动还是错误被动
- CODE:邮箱当前状态(具体请参考 S32K-RM:Table 55-11)
- SRR:保证数据帧格式优先于扩展帧(因此设置为扩展帧时此位置1)
- IDE:标准帧 / 扩展帧
- RTR:数据帧 / 远程帧
- DLC:数据长度
- TIME STAMP:时间戳(任何帧的标识符的第二位出现在总线上时,Free Running Timer (TIMER)值被捕获,当传输/接收结束时该值被写入TIME STAMP)
- PRIO:优先级用于邮箱的发送仲裁
- ID:报文ID
DLC长度对照表:
1.2 发送流程
用户将数据填充至发送邮箱,注意:CODE字段最后写入,当写入CODE字段后会激活邮箱并加入仲裁机制
,仲裁胜出的邮箱内容将被拷贝到隐藏邮箱(SMB),SMB中的数据将被protocol engine
遵循can协议规则发送至can总线。
1.2.1 发送仲裁
- 编号越小优先级越高:LUBF寄存器置1
- 比特序列仲裁:CAN总线仲裁机制
- 优先级仲裁:邮箱中设置的优先级将被增加到仲裁机制当中,PRIO值越低优先级越高
1.3 接收流程
protocol engine从can总线接收到报文后存入隐藏邮箱(SMB),recive process(接收进程)将SMB中的ID与接收邮箱中的ID进行匹配,匹配成功后将数据存入邮箱。
1.4 波特率计算方式
1.4.1 位时序概述
CAN通信的每一位数据位是由4个段组成,如下图所示:
- SYNC_SEG:同步段
- PROP_SEG:传播时间段
- PHASE_SEG1:相位缓冲段 1
- PHASE_SEG2:相位缓冲段 2
- SJW:重新同步跳跃宽度(用于采样点容差)
这些段的作用是为了同步节点之间的数据传输,保证采样点的一致性,在同一个CAN网络中,所有节点根据MCU频率、采样点都会指定位时序的参数,例如我是零部件供应商,那么我会根据主机厂给定的CAN开发协议来设定这些值。
采样点计算公式:SP = (SYNC_SEG + PROP_SEG + PHASE_SEG1)/ (SYNC_SEG + PROP_SEG + PHASE_SEG1 + PHASE_SEG2)
SJW:重同步,用于延长或缩短PTS1和PTS2以补偿采样点的偏差。(1-4TQ,并且不能超过PHASE_SEG1和PHASE_SEG2)。例如SJW=1TQ,总TQ数为20,那么容差就是1 / 20 = 5%。如果采样点设置的是80%,那么容差就是75% - 80%。
第二采样点计算公式:SSP = OFFSET * DIV / Bit Time + 5%
注意:
1. OFFSET * DIV :取决于芯片类型,有些要求使用分频前的时钟进行计算,有些需要使用分频后的时钟进行计算
2. 5%:偏差值,需要根据不同芯片实际测量值所得
TDCO = Propagation Delay+Transceiver Delay+Node Processing Delay
1.4.2 波特率计算公式
PE Clock:
CAN模块的报文发送与接收都是由PE Engine
控制,它的时钟频率决定波特率。
如下图所示,PE Clock
的时钟源有两个选择,外设时钟频率和晶振时钟频率,如果对于通信时序公差比较严格,则建议使用晶振时钟频率(防抖效果更好)。
CAN通讯中,一个数据位由4各段组成,每个段由多个Tq组成,一个数据位则由多个Tq组成,最终波特率计算公式如下所示:
① Tq = (PRESDIV + 1) / fcanclk
② CAN Bit Time = (Number of Time Quanta in 1 bit time) * Tq
③ Bit Rate = 1 / CAN Bit Time
例:CAN波特率为500kHz,输入时钟选择外设时钟(SYS_CLK:80MHz):
① CAN Bit Time = 1 / Bit Rate = 1 / 500kHz = 0.000002s
② 0.000002 = Num * (PresDiv + 1)/ 80MHz
③ Num * (PresDiv + 1)= 160
Num:8 ~ 25
PresDiv:0 ~ 255
因此我们可以配置PresDiv:7,Num:20
④ Num分配的依照产品开发的CAN协议手册规约,每个产品开发的时候都有严格的约束。
2. API
函数 | 描述 |
---|---|
Can_Init | CAN模块初始化 |
Can_ChangeBaudrate | 修改波特率 |
Can_CheckBaudrate | 检查波特率 |
Can_SetControllerMode | 设置CAN控制器模式 |
Can_DisableControllerInterrupts | 禁用CAN中断 |
Can_EnableControllerInterrupts | 使能CAN中断 |
Can_Write | CAN信号发送 |
Can_MainFunction_Write | 发送确认(轮询函数) |
Can_MainFunction_Read | 接收确认(轮询函数) |
Can_MainFunction_BusOff | BussOff确认(轮询函数) |
Can_MainFunction_Mode | 模式确认(轮询函数) |
3. 配置介绍
3.1 General
Can Main Function Busoff Period:
Can_MainFunction_BusOff函数的调用周期(CAN驱动中不使用,应在上层SchM模块使用)
Can Main Function Mode Period:
Can_MainFunction_Mode函数的调用周期(CAN驱动中不使用,应在上层SchM模块使用)
Can Multiplexed Transmission:
多路传输,启用后,如果目标MB处于Busy状态,则寻找其他空闲的且Object ID
相同的邮箱进行发送
Can Maximum Message Buffers:
最大邮箱个数
CanLPduReceiveCalloutFunction:
LPDU(Id/Data/Length)接收回调函数
Can define loop as cycle:
不使用OS的情况下勾选,不勾选则会引入"Os.h"
Can Timeout Duration (in Number of loops) :
超时时间,各个循环中的超时计数
Can Extended ID Support:
ID数据类型(true:uint32 false:uint16)
Can MB Count Extension Support:
邮箱数据类型(true:uint16 false:uint8),如果定义的邮箱个数超过255,则必须开启
Message buffer data size:
数据域大小(在控制器的波特率界面开启CAN FD后生效)
3.2 CanController
3.2.1 General
Can Hardware Channel:
CAN硬件通道选择
Can Controller Activation:
勾选后此通道的配置信息才会生效,否则生成的配置信息都是空的
Can Rx Processing Type:
中断/轮询确认接收数据
Can Tx Processing Type:
中断/轮询确认发送数据
Can BusOff Processing Type:
中断/轮询确认BussOff
以上三者相同,选择触发事件后是通过轮询的方式还是中断的方式获取通知信息
Can Listen Only Mode:
只收不发模式
Can Loop Back Mode:
自发自收模式
Can Lowest Buffer Transmit First:
仲裁机制(邮箱编号越低优先级越高)
Can Local Priority Enable:
仲裁机制(本地优先级 - 参考仲裁机制部分)
Can Clock from Bus:
PE时钟选择(true:系统时钟 false:外设时钟)
Can Controller Default Baudrate:
波特率
Can CPU Reference Clock:
参考时钟
3.2.1 CanControllerBaudrateConfig
3.2.1.1 General
Can Time Segments Checking:
位序列检查
Can Tx ArbitrationStart Delay:
仲裁启动延迟
Can Controller Prescaller:
时钟分频(生成的配置自动-1)
Can Controller BaudRate:
波特率
Can Propagation Segment:
传播时间段(生成的配置自动-1,范围1~8)
Can Phase Segment 1:
相位缓冲段1(生成的配置自动-1,范围1~8)
Can Phase Segment 2:
相位缓冲段2(生成的配置自动-1,范围2~8)
Can Resynch Jump Width:
跳转宽度(范围1~4)
3.2.1.2 CanControllerFdBaudrateConfig
Can FD Controller BaudRate (dynamic range):
波特率
Can FD Propagation Segment:
传播时间段
Can FD Phase Segment 1:
相位缓冲段1
Can FD Phase Segment 2:
相位缓冲段2
Can FD Resynch Jump Width:
相位缓冲段2
CanControllerTxBitRateSwitch:
速率切换
CanControllerFdIsoCANFD:
使能CAN FD
CanControllerFdPrExcEn:
CanControllerFdEdgeFilterDis:
3.3 CanHardwareObject
FD padding value:
CAN FD填充数据(使能CAN FD后开启)
Can Implementation Type:
Basic / Full
Can ID Message Type:
报文类型(标准 / 扩展 / Mixed)
Can ID Bits Local Priority:
本地优先级,用于发送时邮箱仲裁机制(范围:0~7)
Can Object ID:
HOH句柄
Can MB Type:
邮箱类型(发送 / 接收)
CanTriggerTransmitEnable:
Can Controller Reference:
控制器选择
Can MainFunction RW Period Reference:
读写轮询周期选择
Can Hw Filter Code:
匹配码
Can Hw Filter Mask:
掩码
3.4 CanMainFunctionRWPeriods
生成如下宏定义供上层使用,CAN驱动自己不使用:
#define CAN_MAINFUNCTION_PERIOD (0.001F)
#define CAN_MAINFUNCTION_PERIOD_READ (0.001F)
#define CAN_MAINFUNCTION_PERIOD_WRITE (0.001F)
4. 配置介绍扩展
4.1 HwFilterCode / HwFilterMask
- Can Hw Filter Code:匹配码的作用是用于和接收到的报文做比较
- Can Hw Filter Mask:掩码的作用是决定比较ID的哪几个Bit
如下图所示,掩码置1的位置,报文ID和匹配码必须一致,否则将被过滤,掩码置0的位置忽略比较。
掩码计算方式如下所示:
static void MaskCalcTest()
{
uint code = 0x15F;
uint mask = 0x7FF;
uint[] id = { 0x188, 0x198, 0x257};
foreach (var item in id)
{
mask &= ~(code ^ item);
}
Console.WriteLine(mask);
}
4.2 Basic / Full
-
Basic:该邮箱允许接收一组报文
现象:接收由
Can Hw Filter Code
和Can Hw Filter Mask
划定范围的报文。原理:
Can Hw Filter Code
被设置到邮箱的ID字段,Can Hw Filter Mask
被设置到该邮箱对应的RXIMR
寄存器。 -
Full:该邮箱只接收一个报文
现象:只接收与
Can Hw Filter Code
一致的报文。原理:
Can Hw Filter Code
被设置到邮箱的ID字段,RXIMR
寄存器设置为0xFFFFFFFF(所有位都匹配)。
4.3 Can ID Message Type(Mixed)
- 接收配置成Mixed相当于配置成扩展帧
- 发送的时候不关心此配置,根据报文ID的IDE位判断是否是扩展帧
#if (CAN_EXTENDEDID == STD_ON)
if ( (u32MbMessageId & FLEXCAN_MBC_ID_IDE_U32) != (uint32)0U)
{
/* Set the IDE bit in the MBCS register of the MB */
u32MbConfig |= FLEXCAN_MBCS_IDE_U32;
/* Clear the MSB bit of the id - this is used for sending embedded information by CanIf to Can to say if it is an extended or standard message type. */
u32MbMessageId &= (~FLEXCAN_MBC_ID_IDE_U32);
}
else
{
#endif /* (CAN_EXTENDEDID == STD_ON) */
/* Standard ID - need to shift left 18 bits. */
u32MbMessageId <<= FLEXCAN_STANDARD_ID_SHIFT_U32;
#if (CAN_EXTENDEDID == STD_ON)
}
#endif /* (CAN_EXTENDEDID == STD_ON) */
参考资料:
S32K-RM.pdf - NXP
AUTOSAR_MCAL_CAN_UM[1].pdf - NXP