赞
踩
CAN通信比较重要性,本文是基于S32K324 RTD3.0做的一个简单调试,在两个核分别注册一路CAN,会分别介绍中断和轮询两种方式,一般而言BT用轮询,APP里面一般用中断。其次也是介绍一下CANFD和CAN,主要记录整个过程。
FlexCAN 模块是CAN协议的一个高完成度版本,带有CANFD协议和 CAN 2.0 B 版本协议,支持标准和拓展数据帧和长达 64 字节的数据传输,频率最大可达到 8Mbps。NXP的FLEXCAN个人感觉很复杂,要想全部了解就只能看芯片手册,下面只简单的介绍几个基本概念
各模块功能如下:
1.Bus Interface Unit (BIU):允许时钟、寻址、数据总线、中断、DMA和测试信号访问模块
2.Controller Host Interface (CHI):消息缓存区仲裁和匹配算法。
3.Protocol Engine (PE): 请求RAM访问、错误处理、验证接收帧、探测CAN FD帧。
一些关键功能:
1.可配置长度(0,8,16,32,64 Bytes)的邮箱
2.接收或者传输未使用的RAM可以用作通用的RAM
3.CANFD的增强型FIFO可以储存20CANFD frames以及DMA支持
4.优先级机制:最低的ID,缓存区数量最少,优先级最高
5.CAN0最大96mbs, CAN1、CAN2最大64mbs
普通CAN和CANFD的区别:
FlexCAN消息缓冲区结构
1.CAN规范(版本2.0第B部分)中使用的扩展(29位标识符)和标准(11位标识符)帧都有表示。每个单独的消息缓冲 区是16、24、40或72个字节,这取决于为消息有效载荷分配的数据字节数量:分别为8、16、32或64个数据字节。
2.存储区域80h–67Fh由消息缓冲器使用。启用CAN FD时,每个消息缓冲区的确切地址取决于其有效负载的大小
EDL:拓展数据位。用来区分是普通 CAN 帧还是 CANFD 。当 CODE 字段为 0110 时,该位不能置1
BRS:位速率选择位。该位决定在 CANFD 模式下是否切换速率
ESI:错误状态位。该位指示发送节点是主动错误还是被动错误
CODE:报文缓冲区码。该字段可以被 MCU 和 FlexCAN 模块访问(读和写),作为报文缓冲区匹配与仲裁过程的一部 分
FlexCAN具有以下功能模式:
其他的像发送过程、接收过程、仲裁过程等看芯片手册
关于MCAL的配置,其可能依赖模块包括:Port、Platform、Mcu、Mcl、Can
3.1 port
主要是配置TX和RX,下图是将PTA6和PTA7复用为CAN0的RX和TX,其主要配置如下,具体Port和platform配置可参考之前文章 S32K3学习笔记—S32K3之Gpt、Dio、Platform
3.2 paltform
如果不是用的Interupt的方式,此处可以不配置, 此处主要是使能CAN的中断。
3.3 Mcu
Mcu配置如下,具体的配置细节可以参考S32K3学习笔记—S32K3之MCU模块
此处配置两个用于不同硬件CAN的参考时钟就行。还有一点需要注意的,不要忘记在McuPeripheral中使能相应外设的时钟。
3.4 Mcl
如果我们要用的FIFO+ DMA的形式,就需要在Mcl里面配置DMA的逻辑通道相关,此处由于自己没用过这种模式,所以暂不给出配置,如果后续有用到这种模式再回来补
注意:
1.只有在使能FIFO的情况下,才能使用DMA来接收数据
2.发送是不能使用DMA的
3.5 CAN
首先先介绍一下polling或者Interuput的通用配置,相对比较简单。
1.使能支持多核
2.成功接收到L-PDU后的回调函数,看需求使能
3、4.默认使能,芯片自身特定参数
5.使能修改波特率的API
1.可以注册到两个核分区
1.Can_MainFunction_Read或Can_MainFunction_Write的周期。单位是秒。用于polling模式
1.在此处注册所需要的HRH和HOH
需要注意,此处一定是所有的receive之后才能注册transmit
1.可以存储的最大L-PDU有效负载长度,CAN-8bytes,CANFD-64bytes
2.Can实现类型:basic 、full。一般诊断和网络管理报文选择basic ,其他的选择full
3.注意:对于接收邮箱的配置,如果设置成MIXED,那么程序则会将邮箱初始化成extended。
4.选择接收还是发送
5.如果前面选择的polling模式,需要使能5,选择对应的发送/接收的周期
6.增强型FIFO需要使能
接下来就是报文ID和掩码的配置,此处有两种组合
A.固定的ID报文
1.这种ID Filter+掩码的配置,只能接收0x110和0x120两条报文
B.范围ID报文
1.只有0x110 ~ 0x11f的ID报文才会被接收
如下是CAN TX的object。对于发送的object配置相对简单,不需要配置CanHwFilter,只需要配置general
1.选择发送
2.根据模式选择,polling需要使能该选项
接下来是CAN控制器配置
1.使能CAN控制器
2、3、4.CAN rx tx busoff的方式,选择polling 或者 interrupt
5.是否在环回模式下运行,看需求
6.是否支持busoff自恢复
7.是否使用CANFD协议,如果只用普通CAN则不使能此选项
8.默认波特率配置参考,具体配置见后文
9.此路CAN注册到哪个核
10.CAN的时钟参考,在MCU模块配置,需要主要CAN0_2是一种时钟,CAN2_5是另外一种时钟
接下来就是CAN波特率的配置
1.ENHANCE_CBT:提供更高的位定时分辨率,存储在ENCBT、EDCBT和EPRS寄存器中。
2.该5位字段指示从CAN总线上的CRC字段的第一位开始,Tx仲裁过程起始点可以延迟多少CAN位,默认12
3.预分频系数
4.CAN控制器的波特率 波特率 = 时钟频率(40M) / 3 /(5 + 6 + 7 + 8) 如:500K = 40M /1/(1+47+16+16)
此外,采样点的公式 采样点 = 1 - 8 / (5 + 6 + 7 + 8) 如:采样点 = 1 - 16/(1+47+16+16)*100% = 0.8
5、6.同步段、传输段
7、8.相位段1 、相位段2
9.指定控制器的同步跳跃宽度
如果不用CANFD,此配置可以不使能,对于CANFD 波特率和采样点的公式也是一样的,CANFD的配置如下:
1.波特率 = 时钟 / 分频系数 / (2 + 3 + 4 + 5) 例如: 2000K = 40M / 1/ (1 + 7 + 6 + 6)
6.指定控制器的同步跳跃宽度
7.指定变送器延迟补偿偏移
8.指定传输是否应使用比特率切换
接下来就是使能FIFO
1.Legacy FIFO是不支持CANFD的,Enhanced FIFO支持CANFD。
2.指定FIFO的过滤方案
3.使能使能DMA,此处不使能DMA,如果有需要可以使能
至此,核0的CAN的配置完成了,同样,核1只需要做相同的操作就能注册一路CAN,最后只需要将EB生成的代码导入工程,进行调试就行
1.polling
/* main_c0 */ uint8 CanIf_u8TxConfirmCnt = 0U; boolean CanIf_bTxFlag = FALSE; uint8 CanIf_u8RxIndicationCnt = 0U; boolean CanIf_bRxFlag = FALSE; void CanIf_ControllerBusOff(uint8 ControllerId) { (void)ControllerId; } void CanIf_ControllerModeIndication(uint8 ControllerId, Can_ControllerStateType ControllerMode ) { (void)ControllerId; (void)ControllerMode; } void CanIf_TxConfirmation(PduIdType CanTxPduId) { CanIf_u8TxConfirmCnt++; CanIf_bTxFlag = TRUE; (void)CanTxPduId; } void CanIf_RxIndication(const Can_HwType* Mailbox, const PduInfoType* PduInfoPtr ) { CanIf_u8RxIndicationCnt++; CanIf_bRxFlag = TRUE; (void)Mailbox; (void)PduInfoPtr; } void Can_DummyDelay(uint32 loops) { VAR( volatile uint32, CAN_VAR) data = 0xAA55AA55; VAR( volatile uint32, CAN_VAR) contor1 = 0; VAR( volatile uint32, CAN_VAR) contor2 = loops; do { for (contor1 = 0; contor1 < 0x2FF; contor1++) { data ^= (1 << contor1) | (0xAAAAAA | contor2); } contor2--; } while( contor2 > 0); } Can_PduType Can_CreatePduInfo(Can_IdType id, PduIdType swPduHandle, uint8 length, uint8* sdu) { Can_PduType PduInfo; PduInfo.id = id; PduInfo.swPduHandle = swPduHandle; PduInfo.length = length; PduInfo.sdu = sdu; return PduInfo; } int main_c0(void) { uint8 u8TimeOut = 100U; CanIf_bTxFlag = FALSE; CanIf_bRxFlag = FALSE; /* Initialize the Mcu driver */ #if (MCU_PRECOMPILE_SUPPORT == STD_ON) Mcu_Init(NULL_PTR); #elif (MCU_PRECOMPILE_SUPPORT == STD_OFF) Mcu_Init(&Mcu_Config_VS_0); #endif /* (MCU_PRECOMPILE_SUPPORT == STD_ON) */ /* Initialize the clock tree and apply PLL as system clock */ Mcu_InitClock(McuConf_McuModeSettingConf_McuModeSettingConf_0); #if (MCU_NO_PLL == STD_OFF) while ( MCU_PLL_LOCKED != Mcu_GetPllStatus() ) { /* Busy wait until the System PLL is locked */ } Mcu_DistributePllClock(); #endif Mcu_SetMode(McuModeSettingConf_0); /* Initialize Platform driver */ Platform_Init(NULL_PTR); static Can_PduType Can_PduInfo; /* Can_CreatePduInfo(id, swPduHandle,length, sdu) */ Can_PduInfo = Can_CreatePduInfo(0U, 0U, 8U, Can_au8Sdu8bytes); /* Initilize Can driver */ #if (CAN_43_FLEXCAN_PRECOMPILE_SUPPORT == STD_ON) Can_43_FLEXCAN_Init(NULL_PTR); #else Can_43_FLEXCAN_Init(&Can_43_FLEXCAN_Config_VS_0); #endif Can_43_FLEXCAN_SetControllerMode(CanController_0, CAN_CS_STARTED); if((Can_43_FLEXCAN_Write(CanHardwareObject_2, &Can_PduInfo) == E_OK)) while((!CanIf_bTxFlag) && (u8TimeOut != 0U)) { Can_43_FLEXCAN_MainFunction_Write(); Can_DummyDelay(100U); u8TimeOut--; } u8TimeOut = 100U; while((!CanIf_bRxFlag) && (u8TimeOut != 0U)) { Can_43_FLEXCAN_MainFunction_Read(); Can_DummyDelay(100U); u8TimeOut--; } Can_43_FLEXCAN_SetControllerMode(CanController_0, CAN_CS_STOPPED); Can_43_FLEXCAN_DeInit(); return (0U); } /* main_c1 */ int main_c1(void) { uint8 u8TimeOut = 100U; CanIf_bTxFlag = FALSE; CanIf_bRxFlag = FALSE; /* Initialize the Mcu driver */ #if (MCU_PRECOMPILE_SUPPORT == STD_ON) Mcu_Init(NULL_PTR); #elif (MCU_PRECOMPILE_SUPPORT == STD_OFF) Mcu_Init(&Mcu_Config_VS_0); #endif /* (MCU_PRECOMPILE_SUPPORT == STD_ON) */ /* Initialize the clock tree and apply PLL as system clock */ Mcu_InitClock(McuConf_McuModeSettingConf_McuModeSettingConf_0); #if (MCU_NO_PLL == STD_OFF) while ( MCU_PLL_LOCKED != Mcu_GetPllStatus() ) { /* Busy wait until the System PLL is locked */ } Mcu_DistributePllClock(); #endif Mcu_SetMode(McuModeSettingConf_0); /* Initialize Platform driver */ Platform_Init(NULL_PTR); static Can_PduType Can_PduInfo; /* Can_CreatePduInfo(id, swPduHandle,length, sdu) */ Can_PduInfo = Can_CreatePduInfo(0U, 0U, 8U, Can_au8Sdu8bytes); /* Initilize Can driver */ #if (CAN_43_FLEXCAN_PRECOMPILE_SUPPORT == STD_ON) Can_43_FLEXCAN_Init(NULL_PTR); #else Can_43_FLEXCAN_Init(&Can_43_FLEXCAN_Config_VS_0); #endif Can_43_FLEXCAN_SetControllerMode(CanController_1, CAN_CS_STARTED); if((Can_43_FLEXCAN_Write(CanHardwareObject_3, &Can_PduInfo) == E_OK)) while((!CanIf_bTxFlag) && (u8TimeOut != 0U)) { Can_43_FLEXCAN_MainFunction_Write(); Can_DummyDelay(100U); u8TimeOut--; } u8TimeOut = 100U; while((!CanIf_bRxFlag) && (u8TimeOut != 0U)) { Can_43_FLEXCAN_MainFunction_Read(); Can_DummyDelay(100U); u8TimeOut--; } Can_43_FLEXCAN_SetControllerMode(CanController_1, CAN_CS_STOPPED); Can_43_FLEXCAN_DeInit(); return (0U); }
2.interrupt
/* main_c0 */ int main_co(void) { uint8 u8TimeOut = 100U; CanIf_bTxFlag = FALSE; CanIf_bRxFlag = FALSE; /* Initialize the Mcu driver */ #if (MCU_PRECOMPILE_SUPPORT == STD_ON) Mcu_Init(NULL_PTR); #elif (MCU_PRECOMPILE_SUPPORT == STD_OFF) Mcu_Init(&Mcu_Config_VS_0); #endif /* (MCU_PRECOMPILE_SUPPORT == STD_ON) */ /* Initialize the clock tree and apply PLL as system clock */ Mcu_InitClock(McuConf_McuModeSettingConf_McuModeSettingConf_0); #if (MCU_NO_PLL == STD_OFF) while ( MCU_PLL_LOCKED != Mcu_GetPllStatus() ) { /* Busy wait until the System PLL is locked */ } Mcu_DistributePllClock(); #endif Mcu_SetMode(McuModeSettingConf_0); /* Initialize Platform driver */ Platform_Init(NULL_PTR); static Can_PduType Can_PduInfo; /* Can_CreatePduInfo(id, swPduHandle,length, sdu) */ Can_PduInfo = Can_CreatePduInfo(0U, 0U, 8U, Can_au8Sdu8bytes); /* Initilize Can driver */ #if (CAN_43_FLEXCAN_PRECOMPILE_SUPPORT == STD_ON) Can_43_FLEXCAN_Init(NULL_PTR); #else Can_43_FLEXCAN_Init(&Can_43_FLEXCAN_Config_VS_0); #endif Can_43_FLEXCAN_SetControllerMode(CanController_0, CAN_CS_STARTED); for(;;) { } return (0U); } /* main_c1 */ int main_c1(void) { uint8 u8TimeOut = 100U; CanIf_bTxFlag = FALSE; CanIf_bRxFlag = FALSE; /* Initialize the Mcu driver */ #if (MCU_PRECOMPILE_SUPPORT == STD_ON) Mcu_Init(NULL_PTR); #elif (MCU_PRECOMPILE_SUPPORT == STD_OFF) Mcu_Init(&Mcu_Config_VS_0); #endif /* (MCU_PRECOMPILE_SUPPORT == STD_ON) */ /* Initialize the clock tree and apply PLL as system clock */ Mcu_InitClock(McuConf_McuModeSettingConf_McuModeSettingConf_0); #if (MCU_NO_PLL == STD_OFF) while ( MCU_PLL_LOCKED != Mcu_GetPllStatus() ) { /* Busy wait until the System PLL is locked */ } Mcu_DistributePllClock(); #endif Mcu_SetMode(McuModeSettingConf_0); /* Initialize Platform driver */ Platform_Init(NULL_PTR); static Can_PduType Can_PduInfo; /* Can_CreatePduInfo(id, swPduHandle,length, sdu) */ Can_PduInfo = Can_CreatePduInfo(0U, 0U, 8U, Can_au8Sdu8bytes); /* Initilize Can driver */ #if (CAN_43_FLEXCAN_PRECOMPILE_SUPPORT == STD_ON) Can_43_FLEXCAN_Init(NULL_PTR); #else Can_43_FLEXCAN_Init(&Can_43_FLEXCAN_Config_VS_0); #endif Can_43_FLEXCAN_SetControllerMode(CanController_1, CAN_CS_STARTED); for(;;) { } return (0U); }
FIFO+DMA的形式没有用过,后续有时间将这个验证一下再补上,关于原理那块比较复杂,写的很简单,如果有时间后续将原理那块丰富一下。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。