CAN FD扩展帧

一、CAN FD扩展帧是什么?

1.1 标准帧 vs 扩展帧

特性 标准帧 扩展帧
ID位数 11位 29位
ID范围 0x000 ~ 0x7FF 0x00000000 ~ 0x1FFFFFFF
节点容量 最多2048个 最多5.36亿
应用场景 小型网络 大型复杂系统

扩展帧的29位ID为大型网络提供了海量的地址空间,是CAN FD的强大特性之一。

1.2 CAN FD vs 传统CAN

复制代码
传统CAN 2.0:
┌──────┬──────────┬──────┬─────┐
│ ID   │ DLC(≤8)  │ Data │ CRC │
│ 11/29│  4bit    │ 0-8B │15bit│
└──────┴──────────┴──────┴─────┘

CAN FD:
┌──────┬──────────┬──────┬───────┬─────┐
│ ID   │ DLC(≤64) │ Data │ Stuff │ CRC │
│ 11/29│  4bit    │0-64B │ Count │17/21│
└──────┴──────────┴──────┴───────┴─────┘
         ↑
    可指示最多64字节数据!

核心优势

  • 数据段速率可达8Mbps(传统CAN仅1Mbps)

  • 单帧最大64字节(传统CAN仅8字节)

  • 硬件CRC校验,无需软件组帧


二、扩展帧ID的位域设计

2.1 为什么需要自定义ID结构?

CAN FD的29位ID不仅仅是"地址",更是协议的载体。通过位域划分,可以在ID中编码丰富的语义信息。

2.2 实际案例:机器人关节控制协议

以下是一个真实项目的ID编码方案:

复制代码
/* 29位扩展ID的位域分配 */
#define CAN_DEV_ID_NUM       (7u)    // 设备ID:7位,0-127
#define CAN_DEV_ID_SHIFT     (0u)

#define CAN_PRODUCT_ID_NUM   (7u)    // 产品ID:7位
#define CAN_PRODUCT_ID_SHIFT (7u)    // 注意:从bit7开始!

#define CAN_RW_NUM           (1u)    // 读写标志:1位
#define CAN_RW_SHIFT         (14u)   // 0=读,1=写

#define CAN_REG_NUM          (8u)    // 寄存器号:8位
#define CAN_REG_SHIFT        (15u)

#define CAN_REG_ADD_NUM      (5u)    // 子地址:5位
#define CAN_REG_ADD_SHIFT    (23u)

// 广播地址
#define CAN_BROADCAST_DEV_ID (0u)

ID布局可视化

复制代码
Bit: 28 ...... 24 | 23 ...... 15 | 14 | 13 ...... 7 | 6 ...... 0
     [子地址 5位]   [寄存器 8位]  [R/W] [产品ID 7位] [设备ID 7位]

三、关键认知:ID里存的是源地址!

3.1 CAN总线的寻址哲学

这是初学者最容易混淆的地方:

总线类型 寻址方式 ID含义
I2C/SPI 目标寻址 我要跟谁通信
CAN 源地址广播 我是谁

3.2 为什么这样设计?

CAN总线是广播式通信,所有节点同时监听总线。发送方报出自己身份,接收方根据"谁发的"来决定是否处理。

复制代码
// 发送时:填写自己的ID
uint32_t u32_id = pack_id(MY_PRODUCT_ID, MY_DEV_ID, rw, reg, reg_add);

// 接收时:判断发送方是谁
if(u8_dev_id == MASTER_ID || u8_dev_id == BROADCAST_ID) {
    // 来自主控或广播,处理
}

3.3 目标地址放哪里?

如果需要点对点通信,目标地址放在数据区

复制代码
// 发送给设备5
uint8_t au8_data[64];
au8_data[0] = 0x05;  // 目标设备ID
// ... 其他数据

四、硬件过滤器的正确配置

4.1 过滤的是什么?

过滤的是"发送方ID",不是"目标地址"!

复制代码
// 错误理解:过滤"发给我的帧"
// 正确理解:过滤"我关心的发送方发的帧"

// 示例:只接收来自主控(0x01)和广播(0x00)的帧
uint32_t u32_master_id = pack_id(PRODUCT_ID, 0x01, 0, 0, 0);
uint32_t u32_broadcast_id = pack_id(PRODUCT_ID, 0x00, 0, 0, 0);

st_filter.FilterID1 = u32_master_id;
st_filter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;

4.2 多FDCAN外设的过滤器配置陷阱

问题现象:FDCAN1收不到数据,FDCAN2正常。

根本原因 :多个FDCAN外设共享同一个过滤器RAM,FilterIndex冲突导致覆盖。

复制代码
// ❌ 错误:两个外设使用相同的FilterIndex
// bsp_fdcan1_init()
st_filter.FilterIndex = 0;  // 被覆盖!
st_filter.FilterIndex = 1;  // 被覆盖!

// bsp_fdcan2_init()
st_filter.FilterIndex = 0;  // 覆盖了CAN1的配置
st_filter.FilterIndex = 1;  // 覆盖了CAN1的配置

✅ 正确方案1:错开FilterIndex

c

复制代码
// FDCAN1使用0~1
st_filter.FilterIndex = 0;
st_filter.FilterIndex = 1;

// FDCAN2使用2~3
st_filter.FilterIndex = 2;
st_filter.FilterIndex = 3;

✅ 正确方案2:使用全局过滤器(推荐)

复制代码
// FDCAN1:所有扩展帧进FIFO0
HAL_FDCAN_ConfigGlobalFilter(&hfdcan1,
    FDCAN_REJECT, FDCAN_REJECT,
    FDCAN_FILTER_TO_RXFIFO0,  // 扩展数据帧
    FDCAN_FILTER_TO_RXFIFO0); // 扩展远程帧

// FDCAN2:所有扩展帧进FIFO1
HAL_FDCAN_ConfigGlobalFilter(&hfdcan2,
    FDCAN_REJECT, FDCAN_REJECT,
    FDCAN_FILTER_TO_RXFIFO1,
    FDCAN_FILTER_TO_RXFIFO1);
相关推荐
GCKJ_08242 小时前
观成科技:利用DoH加密通信的恶意木马流量分析
网络
zjun10013 小时前
TCP专栏-1.TCP协议概念说明
网络·网络协议·tcp/ip
德迅云安全杨德俊3 小时前
DDoS 解析与防御体系
网络·安全·web安全·ddos
国科安芯3 小时前
商业航天电机控制领域抗辐射 MCU 芯片应用研究
网络·单片机·嵌入式硬件·安全性测试
Lentou4 小时前
日志轮询策略
linux·服务器·网络
星融元asterfusion4 小时前
如何为您的网络选择正确的PTP配置文件:一份实用指南
网络·ptp·时间同步
光路科技4 小时前
一文讲透DHCP Snooping:从原理到工业网络实践
网络
威联通安全存储5 小时前
穿透宿主机内核:QNAP Virtualization Station 硬件直通解析
网络·nas
BenD-_-5 小时前
CVE-2026-31431 Copy Fail:Linux 内核本地提权漏洞风险与缓解
linux·网络·安全
YOU OU5 小时前
网络初识(java)
网络