一、原理
1、FDCAN框图
FDCAN外设提供两条中断线,fdcan_intr0_it和fdcan_intr1_it。通过在FDCAN_ILE寄存器中编程EINT0和EINT1位,可以分别启用或禁用中断线。
CAN核心包含协议控制器和接收/发送移位寄存器。它处理所有ISO 11898- 1:20 15协议功能,并支持11位和29位标识符。
Sync块将来自APB时钟域的信号同步到CAN内核时钟域,反之亦然。
TX Handler:控制从消息RAM到CAN核心的消息传输。最多三个Tx缓冲区可用于传输。Tx缓冲区可以用作Tx FIFO或Tx队列。Tx事件FIFO存储Tx时间戳以及相应的消息ID。还支持发送取消。
RX Handler:控制从CAN核心到外部消息RAM的接收消息的传输。Rx处理程序支持两个接收fifo,用于存储已通过接受过滤的所有消息。Rx时间戳与每条消息一起存储。最多可为11位id定义28个过滤器,最多可为29位id定义8个过滤器
APB interface:将FDCAN连接到APB总线,用于配置寄存器,控制器配置和RAM访问。
Message RAM interface:通过RAM控制器/仲裁器连接FDCAN访问外部1kbyte消息RAM。
2、标准数据帧
(1)起始位:必须是逻辑0
(2)识别码:每一个设备都有独特的ID识别码,相当于设备的地址。(ps.扩展帧的识别码是29位的)
(3)RTR位:如果是远程请求帧,这里必须是1,数据帧就是0
(4)控制码--IDE:用来区分标准格式和拓展格式。标准帧是0,拓展帧是1。
(5)控制码--预留位:为0
(6)控制码--DLC位:数据长度代码(Data Link Control),它的二进制编码是0-8。如果是1,则后面的数据位就只有一个字节Byte,8位bit;如果是8,则后面的数据位就是8个字节,64位。
(7)数据码
(8)循环冗余校验位--CRC校验码码:设备接收端会根据数据计算出它的CRC位,如果计算出来的和接收到的CRC不一致,就会重新发送一遍数据帧。
(9)循环冗余校验位--CRC界定符:他是逻辑1,把后面的信息隔开。
(10)ACK码--ACK确认槽:发送端发送的是逻辑1,接收端回复的是逻辑0来表示应答。
(11)ACK码--ACK界定位:他一定是逻辑1,把后面的数据隔开
(12)结束位:7位都是逻辑1,表示数据帧传输结束。
二、参数配置
设置时钟不分频,FDCAN为传统模式、正常模式
设置分频系数为17,则波特率为170MHz/17/(5+4+1)=1Mbit
三、代码实现
extern FDCAN_TxHeaderTypeDef TxHeader;
extern FDCAN_RxHeaderTypeDef RxHeader;
void FDCAN1_Config(void) //配置过滤器
{
FDCAN_FilterTypeDef sFilterConfig;
sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
sFilterConfig.FilterID1 = 0x000;
sFilterConfig.FilterID2 = 0x7ff;
sFilterConfig.FilterIndex = 0;
sFilterConfig.FilterType = FDCAN_FILTER_RANGE;
sFilterConfig.IdType = FDCAN_STANDARD_ID;
if(HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO1;
sFilterConfig.FilterID1 = 0x00000000;
sFilterConfig.FilterID2 = 0x1fffffff;
sFilterConfig.FilterIndex = 0;
sFilterConfig.FilterType = FDCAN_FILTER_RANGE;
sFilterConfig.IdType = FDCAN_EXTENDED_ID;
if(HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
/* Configure global filter on both FDCAN instances:
Filter all remote frames with STD and EXT ID
Reject non matching frames with STD ID and EXT ID */
if(HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)
{
Error_Handler();
}
if(HAL_FDCAN_Start(&hfdcan1) != HAL_OK)
{
Error_Handler();
}
/* Activate Rx FIFO 0 new message notification on both FDCAN instances */
if(HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)
{
Error_Handler();
}
TxHeader.Identifier = 0x123;
TxHeader.IdType = FDCAN_STANDARD_ID;
TxHeader.TxFrameType = FDCAN_DATA_FRAME;
TxHeader.DataLength = FDCAN_DLC_BYTES_8;
TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
TxHeader.BitRateSwitch = FDCAN_BRS_OFF;
TxHeader.FDFormat = FDCAN_CLASSIC_CAN;
TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
TxHeader.MessageMarker = 0;
HAL_FDCAN_Start(&hfdcan1);
}
main.c文件中只需要开启定时器中断。
程序就会自动每隔100ms发送一次数据,并在接收到数据时储存到数组中。