title: "Linux CAN驱动开发" tags: [CAN, SocketCAN, 嵌入式Linux, 网络驱动, FlexCAN] created: 2026-09-17 updated: 2026-09-17
CAN(Controller Area Network,控制局域网络)由德国BOSCH(博世)公司开发,现已成为国际标准(ISO 11898),是当前应用最广泛的现场总线之一。CAN最初为汽车电子设计,现已广泛应用于工业自动化、医疗、船舶和工业设备等领域。
CAN总线使用两根差分线(CAN_H 和 CAN_L)连接所有节点,形成多主总线。每个节点都是独立的CAN控制器,同一CAN网络中所有节点的通信速度必须一致。总线两端各接一个120Ω终端电阻,用于匹配阻抗、吸收信号反射。
| 特性 | 说明 |
|---|---|
| 多主控制 | 总线空闲时所有单元均可发送,通过ID仲裁决定优先级 |
| 系统柔软性 | 节点无地址概念,增减节点不影响其他单元软硬件 |
| 通信速度快 | 最高1Mbps(距离<40m),最远10km(速率<5Kbps) |
| 错误检测 | 所有单元均可检测错误,检测后立即通知全网 |
| 错误恢复 | 发送单元检测到错误后自动重发,直到成功 |
| 故障封闭 | 可区分暂时性错误和持续性错误,隔离故障节点 |
| 连接节点多 | 理论无限制,实际受总线延迟和电气负载约束 |
CAN总线采用差分信号传输:
CAN协议定义了5种帧类型:
| 帧类型 | 用途 |
|---|---|
| 数据帧 | CAN节点之间传输数据 |
| 遥控帧 | 接收单元向发送单元请求数据 |
| 错误帧 | 检测到错误时通知其他单元 |
| 过载帧 | 接收单元通知尚未做好接收准备 |
| 帧间隔 | 分隔数据帧/遥控帧与前面的帧 |
数据帧是CAN通信中最常用的帧,由以下7段组成:
遥控帧与数据帧结构基本相同,主要区别:
CAN总线一个位分为4个段:
| 段名 | 说明 | Tq范围 |
|---|---|---|
| SS(同步段) | 固定1个Tq | 1 Tq |
| PTS(传播时间段) | 补偿总线传播延迟 | 1~8 Tq |
| PBS1(相位缓冲段1) | 补偿相位误差 | 1~8 Tq |
| PBS2(相位缓冲段2) | 补偿相位误差 | 2~8 Tq |
波特率计算公式:
波特率 = f_CANCLK / (总Tq数)
总Tq = SS + PTS + PBS1 + PBS2 = 1 + (PROPSEG+1) + (PSEG1+1) + (PSEG2+1)
在总线空闲时,最先开始发送的单元获得发送权。多个单元同时发送时,从仲裁段第一位开始逐位比较:发送显性电平(0)的单元在仲裁中优先。连续输出显性电平最多的单元赢得仲裁,失利的单元立刻停止发送转为接收。
I.MX6ULL 的 CAN 控制器称为 FlexCAN,符合 CAN2.0B 协议,支持标准/扩展格式,支持 64 个消息缓冲(邮箱),最高 1Mbit/S,每个邮箱可独立配置为接收或发送并带独立接收掩码。驱动文件位于 drivers/net/can/flexcan.c。
FlexCAN 支持的 4 种工作模式:
| 模式 | 使能方式 | 说明 |
|---|---|---|
| 正常模式(Normal) | 默认 | 正常收发,所有 CAN 协议功能使能 |
| 冻结模式(Freeze) | MCR.FRZ = 1 | 无法收发,CAN 总线同步丢失 |
| 仅监听模式(Listen-Only) | CTRL.LOM = 1 | 禁止发送,错误计数器冻结,只接收其他单元的 ACK,工作于被动错误模式 |
| 回环模式(Loop-Back) | CTRL.LPB = 1 | 内部回环,用于自测,发送数据流直接反馈给内部接收单元 |
另有 2 种低功耗模式:禁止模式(Disable) 和 停止模式(Stop)。
位时序寄存器位域(CTRL 寄存器):
| 位域 | 作用 | 取值范围 | 对应段 |
|---|---|---|---|
| PRESDIV | 分频值,决定 Tq | — | — |
| PROPSEG | 传播时间段 PTS | 0~7 → 1~8 Tq | PTS |
| PSEG1 | 相位缓冲段1 PBS1 | 0~7 → 1~8 Tq | PBS1 |
| PSEG2 | 相位缓冲段2 PBS2 | 1~7 → 2~8 Tq | PBS2 |
| RJW | 再同步补偿宽度 SJW | 0~3 → 1~4 Tq | SJW |
其中 f_Tq = f_CANCLK / (PRESDIV + 1),SYNC_SEG 固定为 1 个 Tq。总 Tq 与波特率关系见 1.6 节。
⚠️ 来源说明:原书第六十六章只讲解 FlexCAN 的使能与测试,并明确说明“本教程不讲解应用编程”;本章 SocketCAN 数据结构、API 及 flexcan.c 源码分析等均不属于《I.MX6U嵌入式Linux驱动开发指南》内容,为扩展知识。
Linux通过SocketCAN框架将CAN总线抽象为网络设备,用户空间通过标准socket接口访问CAN:
┌─────────────────────────────────────────────┐
│ 用户空间应用 │
│ (cansend / candump / 自定义CAN程序) │
├─────────────────────────────────────────────┤
│ SocketCAN接口层 │
│ socket() / bind() / send() / recv() │
├─────────────────────────────────────────────┤
│ CAN协议栈 (can_dev.c) │
│ can_frame / can_filter / can_dlc │
├─────────────────────────────────────────────┤
│ 网络设备接口层 (net_device) │
├─────────────────────────────────────────────┤
│ CAN控制器驱动 │
│ (flexcan.c / mcp251x.c / sja1000.c 等) │
├─────────────────────────────────────────────┤
│ CAN控制器硬件 │
│ FlexCAN / MCP2515 / SJA1000 等 │
└─────────────────────────────────────────────┘
socket(PF_CAN, SOCK_RAW, CAN_RAW)struct can_frame {
canid_t can_id; /* 32位CAN ID + 帧标志位 */
__u8 can_dlc; /* 数据长度 (0~8) */
__u8 __pad; /* 填充 */
__u8 __res0; /* 保留 */
__u8 __res1; /* 保留 */
__u8 data[CAN_MAX_DLEN]; /* CAN帧数据 (最大8字节) */
};
can_id 字段的位定义:
CAN_ERR_FLAG(0x20000000)— 错误帧标志CAN_RTR_FLAG(0x40000000)— 远程帧标志CAN_EFF_FLAG(0x80000000)— 扩展帧标志struct can_filter {
canid_t can_id; /* CAN ID */
canid_t can_mask; /* 掩码,与can_id进行按位与 */
};
+------------------+
| SocketCAN API |
+--------+---------+
|
+--------+---------+
| can_dev.c | CAN核心层
+--------+---------+
|
+--------+---------+
| net_device | 网络设备接口
+--------+---------+
|
+---------------+---------------+
| | |
+-------+------+ +-----+-------+ +-----+-------+
| flexcan.c | | mcp251x.c | | sja1000.c |
| FlexCAN驱动 | | MCP251x驱动 | | SJA1000驱动 |
+-------+------+ +-----+-------+ +-----+-------+
| | |
+-------+------+ +-----+-------+ +-----+-------+
| FlexCAN | | MCP2515 | | SJA1000 |
| (i.MX6ULL) | | (SPI CAN) | | (PCI CAN) |
+---------------+ +-------------+ +-------------+
CAN设备在设备树中通常表示为网络设备节点,包含以下关键属性:
compatible:匹配驱动程序reg:寄存器基地址和大小interrupts:中断号和类型clocks:时钟源bitrate:CAN总线波特率/* CAN1引脚复用 - UART3_CTS/RTS 复用为 FlexCAN1 */
pinctrl_flexcan1: flexcan1grp {
fsl,pins = <
MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX 0x1b020
MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX 0x1b020
>;
};
flexcan1: can@02090000 {
compatible = "fsl,imx6ul-flexcan", "fsl,imx6q-flexcan";
reg = <0x02090000 0x4000>;
interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_CAN1_IPG>,
<&clks IMX6UL_CLK_CAN1_SERIAL>;
clock-names = "ipg", "per";
stop-mode = <&gpr 0x10 1 0x10 17>;
status = "disabled";
};
&flexcan1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_flexcan1>;
xceiver-supply = <®_can_3v3>;
status = "okay";
};
关闭 FlexCAN2:I.MX6ULL 有两个 CAN 控制器,NXP 官方 EVK 两个都使能了;但正点原子 I.MX6U-ALPHA 开发板把 FlexCAN2 的 IO 分配给了 ECSPI3,因此必须在 imx6ull-alientek-emmc.dts 中把名为 flexcan2 的节点屏蔽/删除,否则 ECSPI3 外设无法使用(原书 66.3.1 节)。
| 属性 | 说明 |
|---|---|
compatible |
匹配FlexCAN驱动:"fsl,imx6ul-flexcan" |
reg |
寄存器基地址0x02090000,映射大小0x4000 |
interrupts |
GIC中断号110,高电平触发 |
clocks |
两个时钟:IPG总线时钟和Serial时钟 |
xceiver-supply |
CAN收发器供电电压(3.3V) |
status = "okay" |
使能该CAN控制器 |
⚠️ 来源说明:本节不属于《I.MX6U嵌入式Linux驱动开发指南》内容,为扩展知识(原书不讲解 CAN 应用编程,但测试中用到了
ip与 can-utils 命令)。
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
int s;
struct sockaddr_can addr;
struct ifreq ifr;
/* 1. 创建CAN原始套接字 */
s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
/* 2. 指定CAN网络接口 */
strcpy(ifr.ifr_name, "can0");
ioctl(s, SIOCGIFINDEX, &ifr);
/* 3. 绑定到CAN接口 */
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
bind(s, (struct sockaddr *)&addr, sizeof(addr));
struct can_frame frame;
/* 设置帧ID(标准帧) */
frame.can_id = 0x5A1;
/* 设置数据长度 */
frame.can_dlc = 8;
/* 填充8字节数据 */
frame.data[0] = 0x11;
frame.data[1] = 0x22;
frame.data[2] = 0x33;
frame.data[3] = 0x44;
frame.data[4] = 0x55;
frame.data[5] = 0x66;
frame.data[6] = 0x77;
frame.data[7] = 0x88;
/* 发送帧 */
write(s, &frame, sizeof(struct can_frame));
struct can_frame rx_frame;
int nbytes;
/* 接收CAN帧 */
nbytes = read(s, &rx_frame, sizeof(struct can_frame));
if (nbytes > 0) {
printf("ID: 0x%03X, DLC: %d, Data: ", rx_frame.can_id, rx_frame.can_dlc);
for (int i = 0; i < rx_frame.can_dlc; i++) {
printf("%02X ", rx_frame.data[i]);
}
printf("\n");
}
/* 接收特定ID的帧 */
struct can_filter filters[2];
/* 只接收ID=0x123和0x456的帧 */
filters[0].can_id = 0x123;
filters[0].can_mask = CAN_SFF_MASK; /* 0x7FF */
filters[1].can_id = 0x456;
filters[1].can_mask = CAN_SFF_MASK;
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, filters, sizeof(filters));
# 设置CAN波特率为500Kbps
ip link set can0 type can bitrate 500000
# 打开CAN接口
ip link set can0 up
# 关闭CAN接口
ip link set can0 down
# 开启回环测试模式
ip link set can0 type can bitrate 500000 loopback on
# 查看CAN接口信息
ip -details link show can0
# 设置CANFD波特率(CAN-FD)
ip link set can0 type canfd bitrate 1000000 dbitrate 2000000 fd on
| 工具 | 用途 | 示例 |
|---|---|---|
cansend |
发送CAN帧 | cansend can0 5A1#11.22.33.44.55.66.77.88 |
candump |
接收/显示CAN帧 | candump can0 |
canconfig |
配置CAN参数 | canconfig can0 bitrate 500000 |
cangen |
生成随机CAN帧 | cangen can0 -g 100 -I 42A -L 8 -D i |
canplayer |
重放CAN日志 | canplayer -I candump.log |
canecho |
回显CAN帧 | canecho can0 |
canstat |
显示CAN统计 | canstat can0 |
cansend帧格式:cansend <接口> <帧ID>#<数据>
candump输出格式:<接口> <帧ID> [数据]
can0 5A1 [8] 11 22 33 44 55 66 77 88
⚠️ 来源说明:本节 flexcan.c 源码分析不属于《I.MX6U嵌入式Linux驱动开发指南》内容,为扩展知识(原书仅给出驱动文件路径
drivers/net/can/flexcan.c)。
Linux内核中的FlexCAN驱动位于 drivers/net/can/flexcan.c,驱动入口注册网络设备:
static const struct of_device_id flexcan_of_match[] = {
{ .compatible = "fsl,imx6q-flexcan", },
{ .compatible = "fsl,imx6ul-flexcan", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, flexcan_of_match);
static struct platform_driver flexcan_driver = {
.driver = {
.name = "flexcan",
.of_match_table = flexcan_of_match,
},
.probe = flexcan_probe,
.remove = flexcan_remove,
};
module_platform_driver(flexcan_driver);
FlexCAN驱动的初始化主要包括以下步骤:
devm_ioremap_resource() 映射CAN控制器寄存器register_netdev() 注册CAN网络设备设置中断:注册接收和错误中断处理函数
static int flexcan_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct flexcan_priv *priv;
struct flexcan_regs __iomem *regs;
struct resource *res;
void __iomem *base;
u32 clock_freq = 24000000; /* 24MHz */
/* 1. 获取并映射寄存器 */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
/* 2. 分配并初始化net_device */
dev = alloc_netdev(sizeof(*priv), "can%d", NET_NAME_UNKNOWN,
flexcan_setup, priv);
priv = netdev_priv(dev);
priv->dev = dev;
priv->regs = base;
priv->clock_freq = clock_freq;
/* 3. 设置网络设备操作集 */
dev->netdev_ops = &flexcan_netdev_ops;
/* 4. 注册网络设备 */
register_netdev(dev);
return 0;
}
CAN发送通过网络设备的 ndo_start_xmit 回调实现:
static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct flexcan_priv *priv = netdev_priv(dev);
struct can_frame *cf = (struct can_frame *)skb->data;
struct flexcan_mb __iomem *mb;
u32 can_id;
/* 1. 获取空闲发送邮箱 */
mb = flexcan_get_tx_mb(priv);
/* 2. 设置CAN ID */
can_id = cf->can_id;
if (cf->can_id & CAN_EFF_FLAG)
can_id |= FlexCAN_ESF_WR; /* 扩展帧标志 */
writel(can_id, &mb->can_id);
/* 3. 写入数据到邮箱 */
writel(cf->data[0] | (cf->data[1] << 8) |
(cf->data[2] << 16) | (cf->data[3] << 24),
&mb->data[0]);
writel(cf->data[4] | (cf->data[5] << 8) |
(cf->data[6] << 16) | (cf->data[7] << 24),
&mb->data[1]);
/* 4. 设置数据长度并触发发送 */
writel(FlexCAN_MB_CS_TX | FlexCAN_MB_CS_LENGTH(cf->can_dlc),
&mb->cs);
/* 5. 释放skb */
can_free_echo_skb(dev, 0);
dev->trans_start = jiffies;
return NETDEV_TX_OK;
}
CAN接收通过中断方式实现,接收中断处理函数从邮箱读取数据:
static irqreturn_t flexcan_irq(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->regs;
u32 iflag1;
/* 1. 读取中断标志 */
iflag1 = readl(®s->iflag1);
/* 2. 处理接收中断 */
if (iflag1 & FLEXCAN_TX_MB) {
/* 发送完成中断 */
writel(FLEXCAN_TX_MB, ®s->iflag1);
can_free_echo_skb(dev, 0);
dev->stats.tx_packets++;
}
/* 3. 处理接收FIFO中断 */
if (iflag1 & FLEXCAN_RX_MB) {
flexcan_receive(dev);
writel(FLEXCAN_RX_MB, ®s->iflag1);
}
return IRQ_HANDLED;
}
static int flexcan_receive(struct net_device *dev)
{
struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->regs;
struct can_frame *cf;
struct sk_buff *skb;
struct flexcan_mb __iomem *mb;
u32 can_id, can_dlc;
/* 1. 分配skb */
skb = netdev_alloc_skb(dev, sizeof(*cf));
cf = (struct can_frame *)skb_put(skb, sizeof(*cf));
/* 2. 从接收邮箱读取数据 */
mb = ®s->mb[0];
can_id = readl(&mb->can_id);
can_dlc = readl(&mb->cs) & FlexCAN_MB_CS_LENGTH_MASK;
/* 3. 填充can_frame */
cf->can_id = can_id & CAN_SFF_MASK;
cf->can_dlc = can_dlc;
cf->data[0] = readl(&mb->data[0]) & 0xFF;
cf->data[1] = (readl(&mb->data[0]) >> 8) & 0xFF;
cf->data[2] = (readl(&mb->data[0]) >> 16) & 0xFF;
cf->data[3] = (readl(&mb->data[0]) >> 24) & 0xFF;
cf->data[4] = readl(&mb->data[1]) & 0xFF;
cf->data[5] = (readl(&mb->data[1]) >> 8) & 0xFF;
cf->data[6] = (readl(&mb->data[1]) >> 16) & 0xFF;
cf->data[7] = (readl(&mb->data[1]) >> 24) & 0xFF;
/* 4. 递交协议栈 */
skb->protocol = htons(ETH_P_CAN);
skb->ip_summed = CHECKSUM_UNNECESSARY;
netif_receive_skb(skb);
dev->stats.rx_packets++;
dev->stats.rx_bytes += cf->can_dlc;
return 0;
}
FlexCAN的波特率通过CTRL寄存器配置,涉及5个关键参数:
| 参数 | 寄存器位域 | Tq范围 | 说明 |
|---|---|---|---|
| PRESDIV | CTRL.PRESDIV | - | 分频值,Tq = CAN_CLK / (PRESDIV+1) |
| PROPSEG | CTRL.PROPSEG | 1~8 Tq | 传播时间段 |
| PSEG1 | CTRL.PSEG1 | 1~8 Tq | 相位缓冲段1 |
| PSEG2 | CTRL.PSEG2 | 2~8 Tq | 相位缓冲段2 |
| RJW | CTRL.RJW | 1~4 Tq | 再同步补偿宽度 |
波特率计算:
Tq = CAN_CLK / (PRESDIV + 1)
总Tq = 1 + (PROPSEG + 1) + (PSEG1 + 1) + (PSEG2 + 1)
波特率 = CAN_CLK / ((PRESDIV + 1) × 总Tq)
例如:CAN_CLK = 24MHz,PRESDIV = 5,PROPSEG = 6,PSEG1 = 7,PSEG2 = 2
Tq = 24MHz / (5+1) = 4MHz (250ns)
总Tq = 1 + 7 + 8 + 3 = 19
波特率 = 4MHz / 19 ≈ 210.5Kbps
busybox 自带的 ip 命令不支持 CAN 操作,需要移植 iproute2(原书使用 4.4.0 版本):
tar -vxzf iproute2-4.4.0.tar.gz
cd iproute2-4.4.0
# 修改 Makefile:CC := gcc 改为 CC:=arm-linux-gnueabihf-gcc
make
# 得到的 ip 命令先拷贝到临时目录验证(切勿直接覆盖!)
sudo cp ip /home/zuozhongkai/linux/nfs/test_rootfs/lib/modules/4.1.15/ -f
在开发板上验证 ./ip -V 打印版本号正常后,再替换 busybox 的 /sbin/ip:
cd lib/modules/4.1.15/
cp ip /sbin/ip -f # 建议先备份根文件系统
rm ip
reboot
ip -V # 重启后确认版本号
can-utils 移植(原书使用 2020.02.04 版本):
tar -vxzf can-utils-2020.02.04.tar.gz
cd can-utils-2020.02.04
./autogen.sh
./configure --target=arm-linux-gnueabihf --host=arm-linux-gnueabihf \
--prefix=/home/zuozhongkai/linux/IMX6ULL/tool/can-utils --disable-static --enable-shared
make
make install
sudo cp bin/* /home/zuozhongkai/linux/nfs/rootfs/usr/bin/ -f # 拷贝到 /usr/bin
使能Linux内核的FlexCAN驱动:
-> Networking support
-> CAN bus subsystem support # 打开CAN总线子系统
-> CAN Device Drivers
-> Platform CAN drivers with Netlink support
-> Support for Freescale FLEXCAN based chips # 选中
# 查看所有网络接口,确认can0是否存在
ifconfig -a
# 查看CAN设备详细信息
ip -details link show can0
步骤1:设置CAN接口并打开
# 设置波特率
ip link set can0 type can bitrate 500000
# 打开接口
ifconfig can0 up
步骤2:接收端监听
candump can0
步骤3:发送端发送数据
cansend can0 5A1#11.22.33.44.55.66.77.88
预期输出(接收端):
can0 5A1 [8] 11 22 33 44 55 66 77 88
在单板上进行CAN回环测试,无需外部CAN设备:
# 关闭接口(如果已打开)
ifconfig can0 down
# 开启回环模式
ip link set can0 type can bitrate 500000 loopback on
# 重新打开接口
ifconfig can0 up
# 后台接收数据
candump can0 &
# 发送数据
cansend can0 5A1#11.22.33.44.55.66.77.88
预期输出:开发板收到自己发送的数据。
ifconfig can0 down
⚠️ 来源说明:本节不属于《I.MX6U嵌入式Linux驱动开发指南》内容,为扩展知识。
| 特性 | I.MX6ULL | STM32F4/F7 | RK3568 |
|---|---|---|---|
| CAN控制器 | FlexCAN | bxCAN/FDCAN | CAN 2.0 |
| CAN版本 | CAN2.0B | CAN2.0B + CAN-FD | CAN2.0B |
| 最大速率 | 1Mbps | 1Mbps (CAN-FD 8Mbps) | 1Mbps |
| 消息邮箱 | 64个MB | bxCAN 3个TX + 3个RX | 多通道 |
| 接收FIFO | 支持(含ID过滤) | 支持(2级FIFO) | 支持 |
| 设备树兼容 | "fsl,imx6ul-flexcan" |
"st,stm32-can" |
"rockchip,rk3568-can" |
| 驱动文件 | flexcan.c |
kvaser_pci.c / c_can_platform.c |
rockchip_can.c |
| 回环模式 | 支持(CTRL.LPB) | 支持(BTR.LBKM) | 支持 |
| 低功耗模式 | 禁止/停止模式 | Sleep/Stop模式 | 支持 |
drivers/net/can/flexcan.cdrivers/net/can/rockchip/rockchip_can.c⚠️ 来源说明:本节不属于《I.MX6U嵌入式Linux驱动开发指南》内容,为扩展知识。
答:SocketCAN是Linux下CAN总线的标准访问方式,相比传统字符设备驱动有以下优势:
答:CAN采用逐位仲裁机制:多个节点同时发送时,从仲裁段第一位开始逐位比较。发送显性电平(0)的节点在仲裁中优先,因为CAN总线上显性电平会覆盖隐性电平(线与机制)。连续输出显性电平最多的节点赢得仲裁,失利节点立即停止发送转为接收。
与I2C仲裁的区别:
答:FlexCAN使用消息邮箱(Mailbox)作为数据收发的缓冲区。每个邮箱可以独立配置为发送或接收模式,包含:
发送流程:CPU将数据写入空闲的发送邮箱,设置CS寄存器触发发送。FlexCAN自动完成仲裁、CRC计算和发送。
接收流程:FlexCAN将接收到的帧与邮箱ID比较,匹配后存入对应邮箱,触发接收中断。支持接收掩码寄存器,实现灵活的ID过滤。
答:
采样点位于PBS1结束处,用于读取总线电平。采样点位置 = (1 + PTS + PBS1) / 总Tq × 100%。通常设置采样点在75%~80%处,以获得最佳抗干扰能力。采样点太靠前容易采到不稳定信号,太靠后容易受位填充影响。
答:分层排查:
dmesg | grep can 查看驱动加载日志;检查设备树配置是否正确ip link set can0 type can loopback on 排除外部设备干扰ip -s link show can0 查看错误计数、丢帧统计内容来源: 《I.MX6U嵌入式Linux驱动开发指南》第六十六章 Linux CAN驱动实验 最后更新: 2026-09-17