STM32G474E-EVAL1开发板FDCAN收发异常问题求助
STM32G474 FDCAN发送FIFO阻塞、接收中断无触发问题排查
项目背景
基于STM32G474处理器与STM32G474E-EVAL1开发板开发,使用125Kbps Classic CAN模式,遇到两个FDCAN核心问题:
- 问题1:调用
HAL_FDCAN_AddMessageToTxFifoQ后,3级发送FIFO很快填满,但CAN总线无数据输出(已确认物理连接、终端电阻正常) - 问题2:配置过滤器接收所有消息至RX FIFO0并激活
FDCAN_IT_RX_FIFO0_NEW_MESSAGE中断,但主机发送消息时FDCAN1_IT0_IRQHandler从未触发(已用CAN分析仪确认消息发出)
相关代码
FDCAN初始化代码(CubeMX生成+自定义过滤器)
/** * @brief FDCAN1 Initialization Function * @param None * @retval None */ static void MX_FDCAN1_Init(void) { /* USER CODE BEGIN FDCAN1_Init 0 */ /* USER CODE END FDCAN1_Init 0 */ /* USER CODE BEGIN FDCAN1_Init 1 */ /* USER CODE END FDCAN1_Init 1 */ hfdcan1.Instance = FDCAN1; hfdcan1.Init.ClockDivider = FDCAN_CLOCK_DIV1; hfdcan1.Init.FrameFormat = FDCAN_FRAME_CLASSIC; hfdcan1.Init.Mode = FDCAN_MODE_NORMAL; hfdcan1.Init.AutoRetransmission = DISABLE; hfdcan1.Init.TransmitPause = DISABLE; hfdcan1.Init.ProtocolException = DISABLE; hfdcan1.Init.NominalPrescaler = 160; hfdcan1.Init.NominalSyncJumpWidth = 1; hfdcan1.Init.NominalTimeSeg1 = 2; hfdcan1.Init.NominalTimeSeg2 = 2; hfdcan1.Init.DataPrescaler = 1; hfdcan1.Init.DataSyncJumpWidth = 16; hfdcan1.Init.DataTimeSeg1 = 15; hfdcan1.Init.DataTimeSeg2 = 5; hfdcan1.Init.StdFiltersNbr = 1; hfdcan1.Init.ExtFiltersNbr = 0; hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN FDCAN1_Init 2 */ // Set up filters FDCAN_FilterTypeDef sFilterConfig; sFilterConfig.IdType = FDCAN_STANDARD_ID; // vs. Extended ID sFilterConfig.FilterIndex = 0; // the number of the filter we are using sFilterConfig.FilterType = FDCAN_FILTER_MASK; sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; // what to do filter match sFilterConfig.FilterID1 = 0; // filter sFilterConfig.FilterID2 = 0; // mask: 0=>accept all messages if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK) { // Filter configuration error Error_Handler(); } // There will be no remote messages if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK) { Error_Handler(); } /* USER CODE END FDCAN_Init 2 */ }
后续初始化函数
void canfestival_CAN_Initialize(CO_Data* can_handle) { // Set up the transmit header TxHeader.IdType = FDCAN_STANDARD_ID; TxHeader.TxFrameType = FDCAN_DATA_FRAME; TxHeader.DataLength = FDCAN_DLC_BYTES_8; TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE; // Error State Indicator for Tx errors TxHeader.BitRateSwitch = FDCAN_BRS_OFF; TxHeader.FDFormat = FDCAN_CLASSIC_CAN; TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS; TxHeader.MessageMarker = 0; // Start CAN timer for use by CANfestival if (HAL_TIM_Base_Start_IT(&hCAN_FESTIVAL_TIMER) != HAL_OK) { Error_Handler(); } // Start FDCAN module if (HAL_FDCAN_Start(&hFDCAN_MODULE) != HAL_OK) { Error_Handler(); } // Set up to interrupt when a new message arrives in the RX Fifo 0 if (HAL_FDCAN_ActivateNotification(&hFDCAN_MODULE, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK) { Error_Handler(); } }
发送任务代码
void canxmit_Task(void) { Message message; osStatus_t status; while(true) { // Check to see if the Tx FIFO is full. if ((hFDCAN_MODULE.Instance->TXFQS & FDCAN_TXFQS_TFQF) != 0) { break; // Tx FIFO is full. } // Check for any messages in the RTOS queue. status = osMessageQueueGet(CanXmitQueueHandle, &message, NULL, 0); if (status == osErrorTimeout) { break; // No new messages to send. } if (status != osOK) { Error_Handler(); } // Copy message from data structure used by CANfestival into that required for HAL. TxHeader.Identifier = message.cob_id; TxHeader.TxFrameType = (message.rtr != 0) ? FDCAN_REMOTE_FRAME : FDCAN_DATA_FRAME; TxHeader.DataLength = message.len; for (uint32_t i = 0; i < message.len; i++) { TxData[i] = message.data[i]; } // Add message to CAN Fifo queue for transmission. if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, TxData) != HAL_OK) { Error_Handler(); } } }
问题分析与解决方案
问题1:发送FIFO阻塞无传输的修复
波特率配置不匹配
当前标称位时间参数计算出的波特率为100Kbps(假设FDCAN时钟为80MHz),与目标125Kbps不符,导致总线通信失败、消息滞留在FIFO。
修复: 调整参数至正确的125Kbps配置:hfdcan1.Init.NominalPrescaler = 128; hfdcan1.Init.NominalSyncJumpWidth = 1; hfdcan1.Init.NominalTimeSeg1 = 2; hfdcan1.Init.NominalTimeSeg2 = 2;计算:
80MHz / (128 * (1+2+2)) = 125Kbps关闭自动重传导致失败无重试
配置AutoRetransmission = DISABLE,若首次发送因总线错误失败,FDCAN不会重试,消息会填满FIFO。
修复: 开启自动重传:hfdcan1.Init.AutoRetransmission = ENABLE;句柄不一致
初始化使用hfdcan1,但启动和FIFO检查使用hFDCAN_MODULE,需统一句柄。
修复: 将所有FDCAN操作改为使用同一个句柄(如全部用hfdcan1)。
问题2:接收中断无触发的修复
NVIC中断未配置
CubeMX若未开启FDCAN1_IT0中断或未设置优先级,中断无法触发。
修复: 在CubeMX的NVIC设置中勾选FDCAN1_IT0并配置优先级,或手动添加:HAL_NVIC_SetPriority(FDCAN1_IT0_IRQn, 5, 0); HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn);全局过滤器拒绝消息
当前全局过滤器配置为FDCAN_REJECT非匹配消息,若主机发送的消息未被过滤器匹配(如扩展ID)会被丢弃。
修复: 修改全局过滤器,接受所有标准ID消息至RX FIFO0:HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN_ACCEPT_IN_RX_FIFO0, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE);中断激活与启动顺序错误
先启动FDCAN再激活中断可能导致中断未正确注册。
修复: 调整顺序为先激活中断再启动FDCAN:// 先激活中断 if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK) { Error_Handler(); } // 再启动FDCAN if (HAL_FDCAN_Start(&hfdcan1) != HAL_OK) { Error_Handler(); }
额外检查点
- 确认FDCAN引脚配置为正确复用功能:STM32G474E-EVAL1的FDCAN1通常为PA11(RX)、PA12(TX),需配置为AF9
- 读取
hfdcan1.Instance->ESR寄存器检查错误状态,若总线关闭需调用HAL_FDCAN_ResetError(&hfdcan1)恢复
内容的提问来源于stack exchange,提问作者Rick N.
相关产品推荐
相关产品推荐

