# STM32H7 400MHz 下 FDCAN 仲裁段与数据段波特率不一致的配置陷阱与实测 ## 引言 STM32H7 系列凭借 400MHz 主频和双 FDCAN 控制器,成为车载和工业通信的首选。然而,FDCAN 支持仲裁段(Arbitration Phase)与数据段(Data Phase)不同波特率的特性,在高速时钟下极易因位时间参数计算错误导致通信失败。本文基于实际项目,剖析配置陷阱,提供可复现的解决方案。 ## FDCAN 位时间结构 FDCAN 的位时间由四段组成:同步段(SYNC_SEG)、传播段(PROP_SEG)、相位缓冲段1(PHASE_SEG1)和相位缓冲段2(PHASE_SEG2)。每个段的时间量子(Time Quantum, TQ)数可独立配置,而 TQ 长度由分频后的时钟决定。 关键点:**仲裁段和数据段使用不同的位时间寄存器**(NBTP 和 DBTP),但共享同一个时钟源。在 STM32H7 中,FDCAN 内核时钟通常来自 FDCAN 总线时钟(如 APB1 或 APB2),最高可达 100MHz(H7 系列中 FDCAN 时钟源可选 PLL1Q 或 PLL2Q)。 ## 配置陷阱分析 ### 陷阱1:忽略时钟分频器差异 STM32H7 的 FDCAN 时钟源可配置为 `FDCAN1` 的 `fdcan_ker_ck`,该时钟经过预分频器(BRP)后产生 TQ。许多开发者误以为仲裁段和数据段共用同一个 BRP,但实际上 **NBTP 和 DBTP 各自包含独立的 BRP 字段**。若未分别设置,会导致波特率完全错误。 ### 陷阱2:位时间参数超出范围 在 400MHz 主频下,若 FDCAN 内核时钟选择 100MHz,仲裁段波特率设为 1Mbps,数据段设为 5Mbps,则: - 仲裁段:TQ = 100MHz / BRP,若 BRP=1,则 TQ=10ns,位时间需 100 个 TQ(1μs),但 FDCAN 位时间最大仅 129 TQ(NBTP 中 TSEG1 最大 128,TSEG2 最大 128),看似可行,但实际中 SYNC_SEG 固定为 1 TQ,且 TSEG1 和 TSEG2 需满足采样点要求。 - 数据段:TQ 相同,但位时间仅需 20 个 TQ(200ns),此时 TSEG1 和 TSEG2 的分配极易超出硬件限制。 ### 陷阱3:采样点设置不当 标准 CAN 推荐采样点 75%~80%,FDCAN 数据段因速率高,建议采样点 70%~75%。若沿用默认值,可能因采样点偏移导致位错误。 ## 配置步骤(基于 STM32CubeMX + HAL) ### 1. 时钟树配置 在 STM32CubeMX 中,设置主频 400MHz,并将 FDCAN 内核时钟选择为 PLL1Q,输出 100MHz(可通过 `RCC->FDCAN` 时钟源选择)。 ### 2. FDCAN 参数设置 以仲裁段 1Mbps、数据段 5Mbps 为例: - 仲裁段:BRP=1,TSEG1=79,TSEG2=20,SJW=4,采样点 = (1+79)/(1+79+20) = 80/100 = 80% - 数据段:BRP=1,TSEG1=13,TSEG2=6,SJW=2,采样点 = (1+13)/(1+13+6) = 14/20 = 70% 注意:数据段位时间共 20 TQ,符合 FDCAN 规范(最小 8 TQ)。 ### 3. 代码实现 ```c /* FDCAN1 初始化函数 */ void FDCAN1_Init(void) { FDCAN_FilterTypeDef sFilterConfig; FDCAN_RxHeaderTypeDef RxHeader; /* 使能 FDCAN1 时钟 */ __HAL_RCC_FDCAN1_CLK_ENABLE(); /* 配置 FDCAN1 参数 */ hfdcan1.Instance = FDCAN1; hfdcan1.Init.ClockDivider = FDCAN_CLOCK_DIV1; // 时钟不分频,使用 100MHz hfdcan1.Init.FrameFormat = FDCAN_FRAME_FD_BRS; // 允许 BRS,数据段可变波特率 hfdcan1.Init.Mode = FDCAN_MODE_NORMAL; hfdcan1.Init.AutoRetransmission = DISABLE; hfdcan1.Init.TransmitPause = DISABLE; hfdcan1.Init.ProtocolException = DISABLE; /* 仲裁段波特率 1Mbps */ hfdcan1.Init.NominalPrescaler = 1; // BRP=1 hfdcan1.Init.NominalSyncJumpWidth = 4; // SJW=4 hfdcan1.Init.NominalTimeSeg1 = 79; // TSEG1=79 hfdcan1.Init.NominalTimeSeg2 = 20; // TSEG2=20 /* 数据段波特率 5Mbps */ hfdcan1.Init.DataPrescaler = 1; // BRP=1 hfdcan1.Init.DataSyncJumpWidth = 2; // SJW=2 hfdcan1.Init.DataTimeSeg1 = 13; // TSEG1=13 hfdcan1.Init.DataTimeSeg2 = 6; // TSEG2=6 hfdcan1.Init.StdFiltersNbr = 1; hfdcan1.Init.ExtFiltersNbr = 0; hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK) { Error_Handler(); } /* 配置过滤器 */ sFilterConfig.IdType = FDCAN_STANDARD_ID; sFilterConfig.FilterIndex = 0; sFilterConfig.FilterType = FDCAN_FILTER_MASK; sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; sFilterConfig.FilterID1 = 0x123; sFilterConfig.FilterMask = 0x7FF; HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig); /* 启动 FDCAN */ HAL_FDCAN_Start(&hfdcan1); HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0); } ``` ### 4. 发送与接收示例 ```c /* 发送 FD 帧,使用 BRS */ void FDCAN_SendFD(void) { FDCAN_TxHeaderTypeDef TxHeader; uint8_t data[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; TxHeader.Identifier = 0x123; TxHeader.IdType = FDCAN_STANDARD_ID; TxHeader.TxFrameType = FDCAN_DATA_FRAME; TxHeader.DataLength = FDCAN_DLC_BYTES_8; TxHeader.FDFormat = FDCAN_FD_CAN; // FD 格式 TxHeader.BitRateSwitch = FDCAN_BRS_ON; // 启用 BRS TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS; HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, data); } ``` ## 实测结果与问题排查 在 STM32H750 开发板上,使用逻辑分析仪抓取总线波形,实测结果: - 仲裁段波形位宽 1μs,符合 1Mbps; - 数据段位宽 200ns,符合 5Mbps; - 采样点稳定,无位错误。 常见问题: - 若数据段波特率设置过高(如 8Mbps),位时间仅 12.5 TQ,此时 TSEG1 和 TSEG2 的分配必须精确,否则同步失败。建议数据段波特率不超过 5Mbps,以保证足够的 TQ 数。 - 若使用外部收发器,需注意其支持的数据速率(如 TJA1044 支持 5Mbps)。 ## 注意事项 - **时钟源选择**:确保 FDCAN 内核时钟不超过 100MHz,否则需调整分频器。 - **位时间计算**:建议使用 STM32CubeMX 的图形化工具自动计算,但需手动验证采样点。 - **BRS 使能**:只有在 FDFormat 为 FD 且 BitRateSwitch 开启时,数据段波特率才生效。 - **中断优先级**:FDCAN 中断优先级应高于其他非实时中断,避免丢帧。 - **硬件设计**:CAN 总线终端电阻必须正确,否则高速率下信号反射严重。 ## 总结 STM32H7 的 FDCAN 在 400MHz 下实现仲裁段与数据段不同波特率,关键在于理解位时间结构并分别配置 NBTP 和 DBTP。通过合理计算 TQ 分配和采样点,可稳定实现 1Mbps/5Mbps 的混合速率通信。希望本文的实测经验和代码能帮助开发者少走弯路。