STM32 CAN/CAN-FD 初始化检查清单
这是一份快速参考,概括了初始化STM32 CAN-FD设备的关键步骤:
- 模式选择: 在 CAN、CAN-FD without BitRate Switching 和 CAN-FD with BitRate Switching 三种模式中做出选择。
- CubeMX配置: 计算并配置标称段和数据段(如果启用速率切换)的波特率参数。开启NVIC: FDCAN interrupt0。
- 过滤器配置: 在CAN-FD初始化之后、启动硬件之前,配置至少一个过滤器以允许接收报文。
- 使能接收: 配置过滤器后调用
HAL_FDCAN_ConfigFilter(),应用到硬件并开启HAL_FDCAN_ActivateNotification()接收中断。 - 启动设备: 调用
HAL_FDCAN_Start()函数启动CAN-FD外设。 - 编写中断函数: 实现接收回调函数
HAL_FDCAN_RxFifo0Callback()来处理接收到的报文数据。
STM32 CAN/CAN-FD 通信配置详细指南
第一步:选择通信模式
在STM32CubeMX中,根据您的应用需求选择合适的CAN-FD模式。
- CAN: 传统CAN协议,最高1 Mbps波特率,数据帧最大8字节。
- CAN-FD without BitRate Switching: CAN-FD协议,数据帧最大64字节,但整个报文都使用标称波特率。在这种模式下,数据段的位定时参数(
Data Time Seg)会被忽略,但为了避免混淆,强烈建议将其配置为与标称段相同。 - CAN-FD with BitRate Switching: CAN-FD协议,数据帧最大64字节,并在数据段切换到更高的波特率,以实现高速传输。这是利用CAN-FD全部性能的模式。
第二步:位定时和波特率计算
位定时参数决定了通信的波特率和可靠性。一个位的总时间量子数(Time Quanta, tq)由以下公式决定:
总时间量子数=Prescaler×(1+Time Seg1+Time Seg2)
其中,1 代表固定的同步段(SYNC_SEG),它是确保所有节点同步的关键部分。
- 时间量子(tq)的经验公式: 为了保证硬件逻辑正常工作,时间量子(tq)不应过短。经验上,
tq的长度应在 100 ns 到 125 ns 之间,对应的时钟频率为8到10MHz。 - 采样点位置: 采样点通常位于
Time Seg1结束之后,最佳位置建议在总位时间的 75%-85% 之间。
采样点百分比=1+Time Seg1+Time Seg2(1+Time Seg1)×100%
第三步:过滤器和中断配置
这一步是确保能够成功接收报文的关键。
即使不配置任何过滤器,CAN控制器也能接收所有报文,但许多现代CAN-FD外设(如STM32的FDCAN)在默认情况下会丢弃所有报文。因此,必须至少配置一个过滤器来告诉硬件如何处理接收到的报文。
将您的过滤器和中断激活代码放在CAN-FD初始化之后、主循环(while(1))之前的初始化区域:
// FLAG: 配置CANFD过滤器
// 注意,在调用MX_FDCANx_Init()之后
FDCAN_FilterTypeDef sFilterConfig;
/* 配置标准ID过滤器:接收所有标准报文到FIFO0 */
sFilterConfig.IdType = FDCAN_STANDARD_ID;
sFilterConfig.FilterIndex = 0;
sFilterConfig.FilterType = FDCAN_FILTER_MASK;
sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
sFilterConfig.FilterID1 = 0x000;
sFilterConfig.FilterID2 = 0x000;
if (HAL_FDCAN_ConfigFilter(&hfdcanX, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
// 在这里激活接收FIFO0的新报文中断通知
if (HAL_FDCAN_ActivateNotification(&hfdcanX, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)
{
Error_Handler();
}
// 注意,后面可以开启CANFD
第四步:启动设备并编写中断函数
在完成所有配置后,调用HAL_FDCAN_Start()来启动CAN-FD外设。然后,编写中断服务程序(ISR)来处理接收到的报文。
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)
{
// 检查中断是否来自 FDCAN1 模块
if (hfdcan->Instance == FDCAN1)
{
/* 检查是否为新报文到达中断 */
if ((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != RESET)
{
/* 从FIFO0中获取报文数据 */
if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &HO10025_state_yaw.RxHeader, HO10025_state_yaw.rx_buffer) == HAL_OK)
{
/* 报文读取成功,在这里处理您的数据 */
// 您也可以判断报文ID,并根据ID执行不同的操作
// if (RxHeader.Identifier == 0x123) {
// // 执行特定ID的报文处理
// }
}
}
}
/* 其他 FDCAN 模块的中断处理可以放在这里 */
}