# 引言 在高速嵌入式系统中,STM32H7 凭借 400MHz 主频和双 FDCAN 控制器,成为车载和工业通信的热门选择。然而,FDCAN 协议在仲裁阶段与经典 CAN 的位时序存在细微差别,尤其是在 400MHz 时钟下,若直接沿用经典 CAN 的位定时参数,可能导致仲裁位采样点偏移,引发总线错误。本文通过实测数据,剖析两者差异,并给出可落地的配置方案。 # 原理:FDCAN 与经典 CAN 的仲裁位结构 CAN 2.0 和 CAN FD 的仲裁段均采用非破坏性位仲裁,但位时序定义略有不同。经典 CAN(ISO 11898-1:2003)将位时间分为同步段(SYNC_SEG)、传播段(PROP_SEG)、相位缓冲段 1(PS1)和相位缓冲段 2(PS2)。而 FDCAN(ISO 11898-1:2015)在仲裁段(数据率与仲裁率相同)中,同步段固定为 1 个时间量子(tq),但重同步跳转宽度(SJW)和相位段的调整逻辑更灵活,且支持可编程的传播段(通常合并到 PS1)。 在 400MHz 主频下,STM32H7 的 FDCAN 内核时钟(FDCAN_KER_CK)通常由 PLL1Q 或 PLL2Q 提供,最大可达 80MHz(由 RCC 时钟树限制)。经典 CAN 外设(bxCAN)则直接使用 APB1 时钟(最高 100MHz)。两者在相同位速率下,tq 的数量和采样点位置可能不同,导致仲裁位的实际时序差异。 # 实测:400MHz 下仲裁位时序对比 测试环境:STM32H743ZI(主频 400MHz),FDCAN1 和 bxCAN1 均配置为 1Mbps 仲裁速率,采样点 75%。使用逻辑分析仪(采样率 500MS/s)捕获标准帧 ID=0x123 的仲裁场。 - FDCAN 配置:FDCAN_KER_CK = 80MHz,位时间 = 80 tq(1Mbps),SYNC=1,PS1=59,PS2=20,SJW=4。 - 经典 CAN 配置:APB1 = 100MHz,位时间 = 100 tq(1Mbps),SYNC=1,PS1=74,PS2=25,SJW=4。 实测波形(截取 SOF 到 IDE 位): ```text FDCAN: SOF | SYNC(1tq) | PROP+PS1(59tq) | PS2(20tq) | ... 经典CAN: SOF | SYNC(1tq) | PROP(10tq)+PS1(64tq) | PS2(25tq) | ... ``` 关键差异: - FDCAN 的传播段被隐式合并到 PS1,而经典 CAN 显式区分传播段(用于补偿总线延迟)。在 400MHz 下,FDCAN 的 tq 更短(12.5ns vs 10ns),因此传播段的总时长(以 ns 计)更短,对长总线(如 5m 以上)的延迟补偿能力较弱。 - 采样点位置:FDCAN 在 75% 处(60tq),经典 CAN 也在 75% 处(75tq),但 FDCAN 的同步段后立即进入相位段,重同步时 SJW 的调整步长更精细(4tq=50ns vs 40ns),但可能因 tq 数量多导致累积误差。 # 配置步骤:基于 STM32CubeMX 的精确设置 1. **时钟配置**:在 CubeMX 中,设置 RCC 时钟树,使 FDCAN_KER_CK 为 80MHz(例如 PLL1Q = 80MHz),APB1 为 100MHz(用于经典 CAN)。 2. **FDCAN 初始化**: - 在 FDCAN1 参数中,选择 `FDCAN 模式` 为 `FDCAN 2.0`(仅仲裁段)。 - 设置 `Nominal Prescaler` = 1(因为内核时钟 80MHz,目标 1Mbps,位时间 = 80 tq)。 - 设置 `Nominal Sync Jump Width` = 4。 - 设置 `Nominal Time Segment 1` = 59(包括传播段和 PS1)。 - 设置 `Nominal Time Segment 2` = 20。 - 采样点自动计算为 (1+59)/(1+59+20) = 75%。 3. **经典 CAN 初始化**(bxCAN): - 设置 `Prescaler` = 1(APB1=100MHz,位时间=100 tq)。 - `BS1` = 74(含传播段,但需手动分配传播段为 10tq,PS1=64tq)。 - `BS2` = 25,`SJW` = 4。 4. **生成代码**:CubeMX 生成初始化函数,但需手动调整 FDCAN 的时序参数(CubeMX 可能不提供传播段单独设置)。 # 完整代码示例 以下代码基于 STM32H7 HAL 库,演示 FDCAN 和经典 CAN 的初始化(仅仲裁段配置)。 ```c // FDCAN 初始化(1Mbps,采样点75%) void FDCAN1_Init(void) { FDCAN_HandleTypeDef hfdcan1; hfdcan1.Instance = FDCAN1; hfdcan1.Init.ClockDivider = FDCAN_CLOCK_DIV1; // 内核时钟80MHz hfdcan1.Init.FrameFormat = FDCAN_FRAME_CLASSIC; // 仅经典CAN帧(仲裁段) hfdcan1.Init.Mode = FDCAN_MODE_NORMAL; hfdcan1.Init.AutoRetransmission = ENABLE; hfdcan1.Init.TransmitPause = DISABLE; hfdcan1.Init.ProtocolException = DISABLE; hfdcan1.Init.NominalPrescaler = 1; // 位时间 = 80 tq hfdcan1.Init.NominalSyncJumpWidth = 4; hfdcan1.Init.NominalTimeSeg1 = 59; // 传播段+PS1 hfdcan1.Init.NominalTimeSeg2 = 20; hfdcan1.Init.DataPrescaler = 1; hfdcan1.Init.DataSyncJumpWidth = 4; hfdcan1.Init.DataTimeSeg1 = 13; hfdcan1.Init.DataTimeSeg2 = 2; hfdcan1.Init.StdFiltersNbr = 1; hfdcan1.Init.ExtFiltersNbr = 0; hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK) { Error_Handler(); } } // 经典 CAN 初始化(1Mbps,采样点75%) void CAN1_Init(void) { CAN_HandleTypeDef hcan1; hcan1.Instance = CAN1; hcan1.Init.Prescaler = 1; // APB1=100MHz,位时间=100tq hcan1.Init.Mode = CAN_MODE_NORMAL; hcan1.Init.SyncJumpWidth = CAN_SJW_4TQ; hcan1.Init.TimeSeg1 = CAN_BS1_74TQ; // 传播段10tq + PS1 64tq hcan1.Init.TimeSeg2 = CAN_BS2_25TQ; hcan1.Init.TimeTriggeredCommunication = DISABLE; hcan1.Init.AutoBusOff = ENABLE; hcan1.Init.AutoWakeUp = DISABLE; hcan1.Init.AutoRetransmission = ENABLE; hcan1.Init.ReceiveFifoLocked = DISABLE; hcan1.Init.TransmitFifoPriority = DISABLE; if (HAL_CAN_Init(&hcan1) != HAL_OK) { Error_Handler(); } } ``` # 注意事项 - **时钟源选择**:FDCAN 内核时钟必须来自 PLL,且频率不能超过 80MHz(H7 系列限制),否则位时间 tq 数量会减少,导致采样点精度下降。 - **传播段补偿**:若总线长度超过 2m,建议在 FDCAN 中手动增加 PS1 长度(例如将 TimeSeg1 设为 60-70),以补偿延迟,但需保证采样点仍在 70-80% 区间。 - **重同步**:FDCAN 的 SJW 最大为 4tq,经典 CAN 最大为 16tq(但通常设为 4)。在强噪声环境下,FDCAN 的重同步能力较弱,可能更容易出现位错误。 - **兼容性测试**:当 FDCAN 节点与经典 CAN 节点混合组网时,务必用示波器验证仲裁位的电平宽度。实测发现,FDCAN 的显性位(dominant)在仲裁输出时,其驱动能力与经典 CAN 相同,但时序边沿更陡峭(因为 tq 更短),可能引起振铃,建议在 CAN 收发器 TX 端增加共模电感。 # 结语 STM32H7 的 FDCAN 在 400MHz 下提供了更精细的时间量子,但仲裁位时序与经典 CAN 存在结构性差异。通过理解同步段和相位段的调整机制,并按照本文的配置方法,可以确保两种控制器在同一总线上稳定共存。实测数据表明,只要采样点一致,仲裁过程不会出错,但传播段补偿需额外关注。希望本文能帮助你在实际项目中少走弯路。