STM32U575 FDCAN底层编程:DLC、标准ID及消息发送配置疑问
问题
在Keil uVision环境中使用底层嵌入式C语言,对STM32U575微控制器的FDCAN进行初始化与配置,以实现和Microchip CAN总线分析仪的通信。硬件配置包含1个STM32U575微控制器、1个CAN总线分析仪,以及连接开发板Rx和Tx引脚的两根线缆。
目前已完成位定时、FIFO工作模式、设备运行模式等基础参数的初始化,但在配置数据长度代码(DLC)、标准ID以及实际发送消息时遇到困惑:该芯片没有对应这些参数的专用寄存器。根据参考手册了解到需要操作存储这些参数的RAM,但手册并未指出具体需要修改哪些寄存器。此前使用的STM32F303有专门的寄存器用于配置DLC、标准ID和发送消息,而这款芯片的机制明显不同。
尝试逆向分析STM32CubeMX提供的HAL例程(FDCAN_LOOPBACK.uvprojx)以找出涉及的寄存器,但未成功,希望得到类似HAL例程功能的底层嵌入式C实现方案。
当前编写的代码:
#include "stm32u575xx.h" typedef struct { uint32_t identifier; // Message identifier uint8_t dataLength; // Number of data bytes (up to 64) uint8_t data[64]; // Data bytes } FDCAN_Message; FDCAN_Message message; void FDCAN_SendMessage(FDCAN_Message* message); static void FDCAN1_Init(void); int main(void) { FDCAN1_Init(); message.identifier = 0x123; // Set the message identifier message.dataLength = 8; // Set the number of data bytes message.data[0] = 0xAA; // Set the data bytes (example values) message.data[1] = 0xBB; } static void FDCAN1_Init(void) { RCC -> APB1ENR2 |= RCC_APB1ENR2_FDCAN1EN; RCC -> CCIPR1 &= ~ RCC_CCIPR1_FDCANSEL_0; FDCAN1 -> CCCR &= ~ FDCAN_CCCR_INIT; FDCAN1 -> CCCR |= FDCAN_CCCR_INIT; // Set INIT and CCE bits while ((FDCAN1->CCCR & FDCAN_CCCR_INIT) == 0U); FDCAN1 -> CCCR |= FDCAN_CCCR_CCE; FDCAN1 -> CCCR &= ~ FDCAN_CCCR_CSR;//FDCAN1 -> CFGR |= FDCAN_CKDIV_PDIV_Pos; FDCAN1 -> CCCR &= ~ FDCAN_CCCR_DAR; //AutoRetransmission = ENABLE; FDCAN1 -> CCCR |= FDCAN_CCCR_TXP; //TransmitPause = ENABLE; FDCAN1 -> CCCR &= ~ FDCAN_CCCR_PXHD_Pos; //ProtocolException = DISABLE; FDCAN1 -> CCCR |= (FDCAN_CCCR_FDOE | FDCAN_CCCR_BRSE); //Frame Format FDCAN1 -> CCCR |= FDCAN_CCCR_TEST; FDCAN1 -> TEST |= FDCAN_TEST_LBCK; //LOOPBACK mode FDCAN1->NBTP = 0x000B0905; // Configure FDCAN1 bit timings (assuming 500kbps) FDCAN1->DBTP = FDCAN_DBTP_DSJW_Pos | FDCAN_DBTP_DTSEG2_Pos| FDCAN_DBTP_DTSEG1_Pos | FDCAN_DBTP_DBRP_Pos; FDCAN1 -> TXBC &= ~ FDCAN_TXBC_TFQM; // TX FIFO operation mode FDCAN1 -> XIDAM &= ~ 0x00000001; FDCAN1 -> XIDAM |= 0x00000001; //Extended ID mask FDCAN1 -> RXGFC |= FDCAN_RXGFC_LSS_Msk; FDCAN1 -> RXGFC |= 0x00000020; FDCAN1 -> RXGFC |= FDCAN_RXGFC_RRFE; FDCAN1 -> RXGFC &= ~ FDCAN_RXGFC_RRFS_Pos; FDCAN1 -> CCCR &= ~ FDCAN_CCCR_INIT; }
参考的HAL例程主体代码:
int main(void) { /* USER CODE BEGIN 1 */ /* STM32U5xx HAL library initialization: - Configure the Flash prefetch - Configure the Systick to generate an interrupt each 1 msec - Set NVIC Group Priority to 3 - Low Level Initialization */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* Configure the System Power */ SystemPower_Config(); /* USER CODE BEGIN SysInit */ /* Configure LED5 and LED6 */ BSP_LED_Init(LED5); BSP_LED_Init(LED6); /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_ICACHE_Init(); MX_FDCAN1_Init(); /* USER CODE BEGIN 2 */ /*##-1 Configure the FDCAN filters ########################################*/ /* Configure standard ID reception filter to Rx FIFO 0 */ sFilterConfig.IdType = FDCAN_STANDARD_ID; sFilterConfig.FilterIndex = 0; sFilterConfig.FilterType = FDCAN_FILTER_DUAL; sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; sFilterConfig.FilterID1 = 0x444; sFilterConfig.FilterID2 = 0x555; if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK) { Error_Handler(); } /* Configure extended ID reception filter to Rx FIFO 1 */ sFilterConfig.IdType = FDCAN_EXTENDED_ID; sFilterConfig.FilterIndex = 0; sFilterConfig.FilterType = FDCAN_FILTER_RANGE_NO_EIDM; sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO1; sFilterConfig.FilterID1 = 0x1111111; sFilterConfig.FilterID2 = 0x2222222; if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK) { Error_Handler(); } /* Configure global filter: 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(); } /*##-2 Start FDCAN controller (continuous listening CAN bus) ##############*/ if (HAL_FDCAN_Start(&hfdcan1) != HAL_OK) { Error_Handler(); } /*##-3 Transmit messages ##################################################*/ /* Add message to Tx FIFO */ TxHeader.Identifier = 0x444; TxHeader.IdType = FDCAN_STANDARD_ID; TxHeader.TxFrameType = FDCAN_DATA_FRAME; TxHeader.DataLength = FDCAN_DLC_BYTES_12; TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE; TxHeader.BitRateSwitch = FDCAN_BRS_ON; TxHeader.FDFormat = FDCAN_FD_CAN; TxHeader.TxEventFifoControl = FDCAN_STORE_TX_EVENTS; TxHeader.MessageMarker = 0x52; if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, TxData0) != HAL_OK) { Error_Handler(); } /* Add second message to Tx FIFO */ TxHeader.Identifier = 0x1111112; TxHeader.IdType = FDCAN_EXTENDED_ID; TxHeader.TxFrameType = FDCAN_DATA_FRAME; TxHeader.DataLength = FDCAN_DLC_BYTES_12; TxHeader.ErrorStateIndicator = FDCAN_ESI_PASSIVE; TxHeader.BitRateSwitch = FDCAN_BRS_ON; TxHeader.FDFormat = FDCAN_FD_CAN; TxHeader.TxEventFifoControl = FDCAN_STORE_TX_EVENTS; TxHeader.MessageMarker = 0xCC; if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, TxData1) != HAL_OK) { Error_Handler(); } /* Add third message to Tx FIFO */ TxHeader.Identifier = 0x1111113; TxHeader.IdType = FDCAN_EXTENDED_ID; TxHeader.TxFrameType = FDCAN_DATA_FRAME; TxHeader.DataLength = FDCAN_DLC_BYTES_12; TxHeader.ErrorStateIndicator = FDCAN_ESI_PASSIVE; TxHeader.BitRateSwitch = FDCAN_BRS_OFF; TxHeader.FDFormat = FDCAN_FD_CAN; TxHeader.TxEventFifoControl = FDCAN_STORE_TX_EVENTS; TxHeader.MessageMarker = 0xDD; if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, TxData2) != HAL_OK) { Error_Handler(); } /* Wait transmissions complete */ while (HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1) != 3) {} /*##-4 Receive messages ###################################################*/ /* Check one message is received in Rx FIFO 0 */ if(HAL_FDCAN_GetRxFifoFillLevel(&hfdcan1, FDCAN_RX_FIFO0) != 1) { Error_Handler(); } /* Retrieve message from Rx FIFO 0 */ if (HAL_FDCAN_GetRxMessage(&hfdcan1, FDCAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK) { Error_Handler(); } /* Compare payload to expected data */ if (BufferCmp8b(TxData0, RxData, 12) != 0) { Error_Handler(); } /* Check two messages are received in Rx FIFO 1 */ if(HAL_FDCAN_GetRxFifoFillLevel(&hfdcan1, FDCAN_RX_FIFO1) != 2) { Error_Handler(); } /* Retrieve message from Rx FIFO 1 */ if (HAL_FDCAN_GetRxMessage(&hfdcan1, FDCAN_RX_FIFO1, &RxHeader, RxData) != HAL_OK) { Error_Handler(); } /* Compare payload to expected data */ if (BufferCmp8b(TxData1, RxData, 12) != 0) { Error_Handler(); } /* Retrieve next message from Rx FIFO 1 */ if (HAL_FDCAN_GetRxMessage(&hfdcan1, FDCAN_RX_FIFO1, &RxHeader, RxData) != HAL_OK) { Error_Handler(); } /* Compare payload to expected data */ if (BufferCmp8b(TxData2, RxData, 12) != 0) { Error_Handler(); } /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* Toggle LED5 */ BSP_LED_Toggle(LED5); HAL_Delay(100); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }
解决方案
STM32U5系列的FDCAN采用邮箱RAM映射机制,而非传统的寄存器直接配置ID和DLC。要发送消息,需操作FDCAN的Tx FIFO对应的RAM区域,通过TXBAR(Transmit Buffer Add Request)寄存器触发发送请求。
核心原理
- FDCAN的Tx FIFO每个消息占据16字节RAM空间:前4字节存储ID、DLC、帧类型等控制信息,后12字节存储数据(FD模式下可扩展到64字节,需配置对应寄存器)。
- 通过
TXBAR寄存器的TXBARn位(n为FIFO索引),通知硬件读取对应RAM区域的消息并发送。
底层C实现方案
1. 补充FDCAN消息结构体与宏定义
在原有代码基础上,添加控制位的宏定义,适配FDCAN的RAM格式:
#include "stm32u575xx.h" // FDCAN Tx消息RAM控制字段位定义 #define FDCAN_TX_STD_ID_MASK 0x1FFFFFFFU #define FDCAN_TX_IDE_BIT (1U << 31) // 扩展ID标识位 #define FDCAN_TX_RTR_BIT (1U << 30) // 远程帧标识位 #define FDCAN_TX_FDF_BIT (1U << 29) // FD帧格式标识位 #define FDCAN_TX_BRS_BIT (1U << 28) // 波特率切换标识位 #define FDCAN_TX_ESI_BIT (1U << 27) // 错误状态标识位 #define FDCAN_TX_DLC_MASK 0x0000000FU // DLC字段掩码 typedef struct { uint32_t identifier; // 消息ID(标准ID用低11位,扩展ID用低29位) uint8_t is_extended; // 0:标准ID,1:扩展ID uint8_t is_fd_frame; // 0:CAN帧,1:FD帧 uint8_t brs_enable; // 0:不切换波特率,1:切换波特率 uint8_t dataLength; // 数据长度(0-64) uint8_t data[64]; // 数据字节 } FDCAN_Message; FDCAN_Message message; void FDCAN_SendMessage(FDCAN_Message* message); static void FDCAN1_Init(void);
2. 完善初始化函数
修正原有初始化中的DBTP配置(原代码直接用位位置赋值错误),并确保Tx FIFO处于可用状态:
static void FDCAN1_Init(void) { // 使能FDCAN1时钟 RCC->APB1ENR2 |= RCC_APB1ENR2_FDCAN1EN; // 选择FDCAN时钟源为PCLK1 RCC->CCIPR1 &= ~RCC_CCIPR1_FDCANSEL_Msk; RCC->CCIPR1 |= RCC_CCIPR1_FDCANSEL_0; // 进入初始化模式 FDCAN1->CCCR &= ~FDCAN_CCCR_INIT; FDCAN1->CCCR |= FDCAN_CCCR_INIT; while (!(FDCAN1->CCCR & FDCAN_CCCR_INIT)); // 使能配置更改 FDCAN1->CCCR |= FDCAN_CCCR_CCE; // 配置核心参数 FDCAN1->CCCR &= ~FDCAN_CCCR_CSR; // 禁用时钟停止请求 FDCAN1->CCCR &= ~FDCAN_CCCR_DAR; // 启用自动重传 FDCAN1->CCCR &= ~FDCAN_CCCR_TXP; // 禁用发送暂停 FDCAN1->CCCR &= ~FDCAN_CCCR_PXHD; // 禁用协议异常检测 FDCAN1->CCCR |= FDCAN_CCCR_FDOE | FDCAN_CCCR_BRSE; // 启用FD帧和波特率切换 // 回环模式(调试用,实际通信需注释) FDCAN1->CCCR |= FDCAN_CCCR_TEST; FDCAN1->TEST |= FDCAN_TEST_LBCK; // 位定时配置(500kbps,基于PC
相关产品推荐
相关产品推荐

