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);
相关推荐
xiaoxiangsiyan10 小时前
机房交换机交换技术与服务器链路聚合深度指南
运维·服务器·网络·学习·自动化·bond
中议视控10 小时前
展厅可视化网络中央控制系统:支持双向反馈,可视化播控,回显,状态显示,反向控制电脑,声光电网络视讯设备统一管理
网络·分布式·信息可视化
做萤石二次开发的哈哈10 小时前
萤石蓝海AIoT一站式工作台计费说明
网络·数据库·萤石开放平台·蓝海aiot一站式工作台
wsad053210 小时前
CentOS Stream 10 Docker 容器无法访问外网:xt_addrtype 内核模块缺失解决方法
linux·网络·docker·云原生·eureka·centos
Delite80211 小时前
磷酸酯抗燃油矿物油检测技术及多行业应用场景解析
网络·安全
聚美智数11 小时前
SSL证书信息查询-SSL域名解析-SSL证书查询服务-SSL证书解析服务API接口介绍
网络·网络协议·ssl
瓦学妹11 小时前
美国住宅IP如何选?不同平台配置选择标准与教程指南
网络·网络协议·tcp/ip
SLD_Allen12 小时前
基于 eBPF + Cilium 的 Kubernetes 网络可观测与安全治理实践
网络·安全·kubernetes
Jlzn888812 小时前
轻量化与高可靠性的平衡之道:CCS集成母排产线关键工艺解析
大数据·网络·物联网