You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 15:45:07