4. Linux设备驱动与摄像头子系统
在 TI Sitara(如 AM62x、AM57x)这类机器视觉边缘终端上,摄像头从“插上就能出图”到“稳定低延迟出图”,中间隔着一整套 Linux 摄像头子系统。理解这套子系统的关键,不是记住某个 ioctl 的名字,而是看清一条图像数据从传感器感光到应用拿到帧缓冲的完整路径:谁负责配置传感器、谁负责搬运像素、谁负责把缓冲区交给用户态。本节围绕 V4L2 框架、CSI-2 与并行接口驱动、设备树配置以及 DMA-BUF 零拷贝链路展开。
一、V4L2 框架:把摄像头抽象成一条可编程的管线
V4L2(Video for Linux 2)是 Linux 内核中统一的视频采集接口。它并不直接“驱动摄像头”,而是定义了一套设备节点与操作语义,让应用通过 /dev/videoX 完成格式协商、缓冲区申请、入队、出队和流开关。对机器视觉应用而言,最常用的调用序列是:VIDIOC_QUERYCAP 确认能力,VIDIOC_S_FMT 设定分辨率与像素格式,VIDIOC_REQBUFS 申请缓冲区,mmap 映射到用户态,随后循环执行 VIDIOC_QBUF 入队与 VIDIOC_DQBUF 出队,最后 VIDIOC_STREAMON 启动。
需要特别区分的是:V4L2 设备节点可能对应“采集节点”(video node)或“元数据/参数节点”(meta/subdev node)。在 Sitara 的媒体控制器(Media Controller)模型下,传感器、CSI-2 接收器、DMA 引擎被拆成多个 subdev,通过 media pipeline 用 pad 和 link 连接。应用若只操作 /dev/video0,往往还需要先用 media-ctl 配置各 subdev 的格式与链路,否则会出现“节点存在但出图格式不对”的典型问题。
二、CSI-2 与并行接口:两种物理接入方式
Sitara 的摄像头接入主要有两类。CSI-2(MIPI CSI-2)是差分串行接口,使用 1~4 条 data lane 加一条 clock lane,具备高带宽、抗干扰强、线缆少的特点,适合高分辨率工业相机。并行接口(Parallel/DVP)则是传统的 PCLK、HSYNC、VSYNC 加 8~16 位数据线,时序直观、调试简单,但引脚多、带宽有限,常见于低分辨率或 legacy 传感器。
在驱动层面,CSI-2 通常由“传感器驱动 + CSI-2 接收控制器驱动(如 Cadence CSI2RX)+ DMA 写引擎”三段组成;并行接口则常由“传感器驱动 + VPFE/VIN 采集控制器”组成。无论哪种,传感器驱动都要实现 v4l2_subdev_ops,提供 s_stream、get_fmt、set_fmt 等回调,并通过 I2C 配置寄存器。CSI-2 还需正确设置 lane 数、数据速率与虚拟通道,否则会出现“有 clock 无数据”或“图像错位”的现象。
三、设备树配置:把硬件连接翻译成内核可识别的拓扑
设备树是摄像头能否被正确枚举的第一道关卡。以 CSI-2 为例,典型结构包含三部分:I2C 总线下的 sensor 节点、CSI2RX 控制器节点、以及连接两者的 port/endpoint。sensor 节点需要 compatible、reg、clocks、reset-gpios、port 等属性;CSI2RX 节点需要 phys、dma-names、ports。下面是一个简化示例:
&i2c2 {
status = "okay";
ov5640: camera@3c {
compatible = "ovti,ov5640";
reg = <0x3c>;
clocks = <&clk_cam0>;
reset-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
port {
ov5640_out: endpoint {
remote-endpoint = <&csi2rx_in>;
data-lanes = <1 2>;
clock-noncontinuous;
};
};
};
};
&csi2rx {
status = "okay";
ports {
port@0 {
csi2rx_in: endpoint {
remote-endpoint = <&ov5640_out>;
data-lanes = <1 2>;
};
};
};
};
配置完成后,用 media-ctl -p 查看 pipeline,应能看到 sensor → csi2rx → dma 的 link 全部为 ENABLED。若 link 为 IMMUTABLE 或缺失,说明 endpoint 引用写错或节点未使能。随后用 v4l2-ctl --list-formats-ext 确认格式,再用 v4l2-ctl --stream-mmap --stream-count=10 抓 10 帧验证通路。
四、DMA-BUF 与零拷贝采集链路
传统采集链路中,DMA 把图像写入内核缓冲区,用户态 read() 或 mmap 后再拷贝到应用缓冲,若还要送 GPU 推理,又得再拷贝一次。每次拷贝都消耗 DDR 带宽和 CPU 时间。DMA-BUF 的作用是让不同驱动/设备共享同一块物理缓冲区,通过文件描述符(fd)传递,避免重复拷贝。
在 V4L2 中启用 DMA-BUF 的典型做法是:应用先用 VIDIOC_REQBUFS 申请缓冲区,再通过 VIDIOC_EXPBUF 把缓冲区导出为 dma-buf fd,然后把这个 fd 传给 GPU、VPU 或 NPU 驱动。这样采集、显示、推理三方共享同一块内存,链路中不再出现像素级 memcpy。判断是否真正零拷贝,可以观察 /proc/interrupts 中 DMA 中断频率、perf 统计的 memcpy 占比,以及端到端延迟是否随分辨率线性恶化。
media-ctl -p 确认 pipeline,再用 v4l2-ctl --stream-mmap 确认出图,最后才引入 DMA-BUF 与推理引擎。分层排查能快速定位是设备树、格式协商还是缓冲区共享的问题。data-lanes 不一致会导致图像撕裂或全黑;clock-noncontinuous 缺失可能让部分传感器无法出流;DMA-BUF 导出后若未正确同步(如缺少 fence),会出现推理读到半帧数据的现象。把这条链路串起来看:设备树负责“描述连接”,V4L2/Media Controller 负责“协商格式与建立管线”,CSI-2/并行驱动负责“把电信号变成像素”,DMA-BUF 负责“让像素只搬一次”。四者配合,才能让 Sitara 边缘终端在高分辨率下保持低延迟、低 CPU 占用的稳定采集。