引言

STM32H7 系列凭借 Cortex-M7 内核和高达 480MHz 的主频,在工业控制、汽车电子等领域大放异彩。其内置的 FDCAN 模块(兼容 Bosch M_CAN)支持 CAN 2.0 和 CAN FD 两种模式,但在实际项目中,FDCAN 与经典 CAN 节点共存时,时序配置不当会引发通信异常。本文聚焦 480MHz 时钟下的位时序配置陷阱,提供可落地的解决方案。

FDCAN 与经典 CAN 的时序差异

经典 CAN(ISO 11898-1:2003)采用固定 1 Mbps 速率,位时序由同步段(SYNC_SEG)、传播段(PROP_SEG)、相位缓冲段 1(PHASE_SEG1)和相位缓冲段 2(PHASE_SEG2)组成。FDCAN(ISO 11898-1:2015)在仲裁段保持相同结构,但数据段支持可变速率(最高 8 Mbps),且引入了额外的同步机制。

关键差异点:

  • 位时间量化(TQ):经典 CAN 要求 TQ 数在 8~25 之间,而 FDCAN 数据段允许更小的 TQ 数(如 4~25),但仲裁段仍遵循经典规则。
  • 采样点:经典 CAN 推荐采样点在 75%~80%,FDCAN 仲裁段相同,但数据段可调整至 70%~90%。
  • 同步跳转宽度(SJW):FDCAN 支持 1~4 TQ,经典 CAN 通常为 1~2 TQ,配置不当会降低抗干扰能力。

480MHz 下的位时序计算陷阱

STM32H7 的 FDCAN 内核时钟(FDCAN_KER_CK)通常由 PLL1Q 提供,典型值为 80MHz(480MHz / 6)。位时间计算如下:

[ \text{位时间} = \frac{1}{\text{波特率}} ] [ \text{TQ} = \frac{\text{FDCAN_KER_CK}}{\text{波特率}} ]

例如,经典 CAN 1 Mbps 时,TQ = 80MHz / 1Mbps = 80。然而,80 超出了经典 CAN 的 25 TQ 上限!这是第一个陷阱:直接使用 80MHz 内核时钟无法配置 1 Mbps 经典 CAN

解决方案:通过 FDCAN 的时序预分频器(BRP)降低 TQ 数。例如,设置 BRP = 4,则 TQ = 80 / 4 = 20,满足要求。但 BRP 配置不当会导致采样点偏移,尤其在混合网络中。

配置步骤(基于 STM32CubeMX)

  1. 时钟配置:在 RCC 中启用 PLL1,设置 FDCAN_KER_CK 为 80MHz(确保不超过 100MHz 上限)。
  2. FDCAN 参数设置
    • 模式:经典 CAN(或 CAN FD 兼容)
    • 波特率:1 Mbps(仲裁段)
    • 数据段波特率(若启用 FD):5 Mbps
    • 采样点:75%(经典)
    • 同步跳转宽度:2 TQ
  3. 计算预分频器:使用 CubeMX 的自动计算功能,但需手动验证 TQ 数。例如,1 Mbps 时,BRP = 4,TQ = 20,位时间分配:SYNC=1, PROP=2, PHASE1=7, PHASE2=10(采样点 = (1+2+7)/20 = 50%?错误!)。

陷阱二:CubeMX 默认分配可能不满足采样点要求,需手动调整。正确分配:SYNC=1, PROP=3, PHASE1=8, PHASE2=8,采样点 = (1+3+8)/20 = 60%,仍偏低。应改为 SYNC=1, PROP=2, PHASE1=9, PHASE2=8,采样点 = (1+2+9)/20 = 60%?不对,需重新计算。

实际推荐:SYNC=1, PROP=1, PHASE1=6, PHASE2=12,采样点 = (1+1+6)/20 = 40%,更差。正确做法:采样点 = (SYNC + PROP + PHASE1) / TQ,目标 75%,则 (1 + PROP + PHASE1) / 20 = 0.75,得 PROP + PHASE1 = 14,可取 PROP=2, PHASE1=12,但 PHASE1 最大为 16,可行。最终:SYNC=1, PROP=2, PHASE1=12, PHASE2=5,采样点 = (1+2+12)/20 = 75%,且 SJW=2。

完整代码示例(HAL 库)

#include "stm32h7xx_hal.h"

FDCAN_HandleTypeDef hfdcan1;
FDCAN_FilterTypeDef sFilterConfig;

void FDCAN1_Init(void)
{
    hfdcan1.Instance = FDCAN1;
    hfdcan1.Init.ClockDivider = FDCAN_CLOCK_DIV1;
    hfdcan1.Init.FrameFormat = FDCAN_FRAME_CLASSIC;
    hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;
    hfdcan1.Init.AutoRetransmission = ENABLE;
    hfdcan1.Init.TransmitPause = DISABLE;
    hfdcan1.Init.ProtocolException = DISABLE;
    
    // 经典 CAN 1 Mbps,内核时钟 80MHz,BRP=4,TQ=20
    hfdcan1.Init.NominalPrescaler = 4;
    hfdcan1.Init.NominalSyncJumpWidth = 2;
    hfdcan1.Init.NominalTimeSeg1 = 12;  // PROP + PHASE1
    hfdcan1.Init.NominalTimeSeg2 = 5;   // PHASE2
    
    // 若启用 FD,数据段配置(此处省略)
    
    if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK)
    {
        Error_Handler();
    }
    
    // 配置过滤器,接收所有 ID
    sFilterConfig.IdType = FDCAN_STANDARD_ID;
    sFilterConfig.FilterIndex = 0;
    sFilterConfig.FilterType = FDCAN_FILTER_MASK;
    sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
    sFilterConfig.FilterID1 = 0x000;
    sFilterConfig.FilterID2 = 0x7FF;  // 掩码全 1,匹配所有
    HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig);
    
    // 启动 FDCAN
    HAL_FDCAN_Start(&hfdcan1);
    HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0);
}

// 发送经典 CAN 帧
void FDCAN1_Send(uint32_t id, uint8_t *data, uint8_t len)
{
    FDCAN_TxHeaderTypeDef txHeader;
    txHeader.Identifier = id;
    txHeader.IdType = FDCAN_STANDARD_ID;
    txHeader.TxFrameType = FDCAN_DATA_FRAME;
    txHeader.DataLength = len << 16;  // 长度编码,例如 8 字节为 0x00080000
    txHeader.BitRateSwitch = DISABLE;  // 经典 CAN 无 BRS
    txHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
    txHeader.BitRateSwitch = FDCAN_BRS_OFF;
    txHeader.FDFormat = FDCAN_CLASSIC_CAN;
    
    HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &txHeader, data);
}

// 中断回调
void HAL_FDCAN_RxFifo0MsgPendingCallback(FDCAN_HandleTypeDef *hfdcan)
{
    FDCAN_RxHeaderTypeDef rxHeader;
    uint8_t rxData[8];
    if (hfdcan->Instance == FDCAN1)
    {
        HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rxHeader, rxData);
        // 处理数据
    }
}

混合网络兼容性调试技巧

  • 使用示波器测量实际波形:对比发送节点的 TX 引脚和接收节点的 RX 引脚,检查位宽度是否一致。经典 CAN 的位时间应为 1μs(1 Mbps),若偏差超过 2%,则需调整预分频器。
  • 检查错误计数器:通过 HAL_FDCAN_GetError() 读取协议错误和总线错误计数,若持续增加,说明时序不匹配。
  • 利用 FDCAN 的延迟补偿:在 FD 模式下,数据段速率切换时,FDCAN 会自动插入延迟补偿(SSP),但经典 CAN 无此功能,需确保仲裁段时序严格。
  • 避免使用自动重传:在调试阶段,关闭自动重传(AutoRetransmission = DISABLE),便于观察错误帧。

注意事项

  1. 内核时钟选择:FDCAN_KER_CK 必须小于 100MHz,且最好为波特率的整数倍,以减少 TQ 误差。
  2. 采样点范围:经典 CAN 采样点应在 75%~80%,若低于 70%,在长总线(>10m)上易受信号反射影响。
  3. SJW 设置:SJW 不宜过大(建议 2 TQ),否则在重同步时可能引入抖动。
  4. FD 与经典混合:若网络中同时存在 FD 和经典节点,必须确保仲裁段波特率一致,且 FD 节点在发送时使用 BRS=0(不切换速率),否则经典节点会报错。
  5. CubeMX 自动计算陷阱:CubeMX 的位时间计算器可能不适用于 480MHz 主频,务必手动验证 TQ 数和采样点。

结语

STM32H7 的 FDCAN 在 480MHz 下提供了强大性能,但时序配置需谨慎。通过理解位时间结构、手动计算预分频器,并利用调试工具验证,可轻松实现与经典 CAN 的兼容。希望本文能帮助你避开常见陷阱,构建稳定的混合网络。