Lazy loaded image
MIPI Camera 驱动实战(V4L2 子系统)
Words 3696Read Time 10 min
2026-3-5
本文从零开始,逐步完成一个基于 V4L2/Media Controller 框架的虚拟 MIPI CSI-2 摄像头传感器驱动,覆盖 Sensor 驱动注册 → V4L2 subdev → Media Entity → DT 配置 → QEMU 验证 全流程。

1. 前置条件

确保以下环境已就绪(参考同级页面的 QEMU + 交叉编译工具链搭建指南):
交叉编译器 arm-linux-gnueabihf-gcc 可用
已编译 v6.1 内核源码,且开启 CONFIG_VIDEO_DEVCONFIG_MEDIA_SUPPORTCONFIG_I2C 支持
QEMU mcimx6ul-evk(Cortex-A7)能正常启动 BusyBox rootfs
内核配置中已启用 CONFIG_VIDEO_V4L2CONFIG_MEDIA_CONTROLLER
为什么选 V4L2? V4L2(Video for Linux 2)是 Linux 视频设备的标准子系统,配合 Media Controller 框架可描述复杂的摄像头流水线拓扑(Sensor → CSI → ISP → Video Node),是 MIPI CSI-2 摄像头的首选框架。

2. V4L2 子系统关键概念

概念
说明
v4l2_subdev
代表视频流水线中的一个子设备(如 Sensor、ISP),类比 IIO 中的 iio_dev
v4l2_subdev_ops
子设备操作集,包含 video(流控制)、pad(格式协商)、core(通用操作)等回调
media_entity
Media Controller 中的实体节点,描述设备在流水线拓扑中的位置和连接关系
media_pad
实体的输入/输出端口,Source Pad 输出数据,Sink Pad 接收数据
v4l2_async_register_subdev
异步注册子设备,等待 CSI 桥接驱动就绪后自动完成绑定
v4l2_ctrl_handler
V4L2 控件管理器,统一管理曝光、增益、白平衡等参数控件

V4L2 摄像头流水线架构


3. 驱动源码

3.1 虚拟摄像头传感器驱动 — fake_cam.c

3.2 关键结构说明

元素
作用
v4l2_i2c_subdev_init
初始化 V4L2 子设备并绑定 I2C client,自动设置 sd->devsd->name
V4L2_SUBDEV_FL_HAS_DEVNODE
标记子设备需要创建 /dev/v4l-subdevX 设备节点,允许用户态直接访问
media_entity_pads_init
初始化 Media Entity 的 Pad(Source/Sink),定义设备在流水线中的连接能力
MEDIA_ENT_F_CAM_SENSOR
标记 Entity 功能为摄像头传感器,media-ctl 拓扑图中将显示为 Sensor 节点
v4l2_ctrl_handler
统一管理曝光、增益、翻转等 V4L2 标准控件,用户通过 v4l2-ctl -C 读写
v4l2_async_register_subdev
异步注册子设备,等待 CSI 桥接驱动调用 v4l2_async_notifier 完成绑定
fake_cam_pad_ops
Pad 操作集:enum_mbus_code 枚举媒体总线格式,get/set_fmt 协商分辨率
fake_cam_s_stream
流控制回调:CSI 驱动调用此函数启动/停止 Sensor 的 MIPI 数据输出
V4L2 subdev 三层操作集core_ops 提供通用功能(日志、电源管理),video_ops 控制数据流启停(s_stream),pad_ops 处理格式协商(分辨率/像素格式在 pad 层面逐级传递)。这种分层设计使得同一个 Sensor 驱动可适配不同的 CSI 桥接驱动。

4. Makefile


5. 编译模块

编译成功后确认产出:
注意 depends: videodev,mc:V4L2 核心(videodev)和 Media Controller(mc)是独立模块,加载 fake_cam.ko 前必须先加载它们(或内核内建)。

6. 设备树配置

6.1 MIPI CSI-2 Sensor 节点说明

摄像头传感器挂载在 I2C 总线上进行寄存器控制,同时通过 MIPI CSI-2 接口传输图像数据。DT 中需要:
  1. I2C 子节点声明 Sensor 设备(reg = I2C 地址)
  1. port 子节点描述 MIPI CSI-2 连接(data-lanes、remote-endpoint)

6.2 需要注入的 DT 节点

QEMU 简化说明:QEMU mcimx6ul-evk 不模拟 MIPI CSI-2 控制器,因此 port 节点中的 remote-endpoint 无法真正连接 CSI 桥接驱动。本实战重点验证 I2C probe → V4L2 subdev 注册 → Media Entity 创建 → Controls sysfs,实际的 media-ctl 拓扑和 v4l2-ctl --stream 需在真实硬件上验证。

6.3 直接修改主 DTB(QEMU 方式)


7. 一键构建脚本 — build.sh

运行方式

8. QEMU 内加载验证

8.1 启动 QEMU — run_qemu.sh

8.2 加载模块

8.3 确认 probe 调用

8.4 查看 V4L2 subdev 信息

8.5 验证 V4L2 Controls

8.6 验证格式协商

8.7 自动化验证脚本 — verify_cam.sh

预期输出:
QEMU 摄像头限制:QEMU mcimx6ul-evk 不模拟 MIPI CSI-2 控制器和 DMA,因此无法进行 v4l2-ctl --stream 实际抓帧。本实战重点验证 V4L2 subdev 注册 + Media Entity + Controls + 格式协商 全链路,实际图像采集在真实硬件上验证。

9. 验证清单

make 编译无 warning,产出 fake_cam.ko
modinfo 输出 depends: videodev,mc
file fake_cam.ko 显示 ARM ELF relocatable
设备树中 i2c1 节点下存在 fake_cam@3c 子节点
insmoddmesg 显示 probe OK, addr=0x3c, default 640x480
/sys/class/video4linux/v4l-subdev0/name 输出 fake_cam 0-003c
V4L2 Controls 可列出(exposure / analogue_gain / hflip / vflip)
v4l2-ctl -c exposure=2000dmesg 显示 set exposure=2000
格式协商返回 640x480 / 1280x720 / 1920x1080 三种帧大小
verify_cam.sh 全部步骤通过
rmmoddmesg 显示 remove called

10. 常见问题排查

现象
原因
解决方案
insmod: unknown symbol v4l2_i2c_subdev_init
V4L2 核心模块未加载
insmod videodev.ko,或内核配置 CONFIG_VIDEO_DEV=y
insmod: unknown symbol media_entity_pads_init
Media Controller 模块未加载
insmod mc.ko,或内核配置 CONFIG_MEDIA_SUPPORT=y
probe 未调用
DT 中 compatible 不匹配或节点不在 I2C 控制器下
确认 compatible = "myvendor,fake-cam" 与驱动 of_match_table 一致
/dev/v4l-subdev0 不存在
未设置 V4L2_SUBDEV_FL_HAS_DEVNODE 或内核未开启 CONFIG_VIDEO_V4L2_SUBDEV_API
确认驱动 flags 包含该标志;内核 menuconfig 启用 V4L2 sub-device userspace API
v4l2-ctl --list-ctrls 为空
v4l2_ctrl_handler 未正确关联到 sd->ctrl_handler
确认 cam->sd.ctrl_handler = handler 在 probe 中正确赋值
v4l2_async_register_subdev 返回 -ENODEV
V4L2 异步注册找不到匹配的 notifier(QEMU 无 CSI 桥接驱动)
QEMU 下可改用 v4l2_async_register_subdev_sensor 或直接注册非异步子设备
media-ctl -p 无输出
rootfs 中缺少 media-ctl 工具
交叉编译 v4l-utils 包并打入 rootfs,或使用 sysfs 手动查看
insmod: invalid module format
vermagic 不匹配
确保 KERNDIR 指向 QEMU 启动时使用的同一内核树

11. 向真实硬件(OV5640 + i.MX8MP)迁移

完成虚拟驱动验证后,迁移到真实 OV5640 MIPI CSI-2 摄像头需替换以下部分:
  1. probe 中添加 Chip ID 检测
    1. 替换为真实寄存器操作
      1. DT compatible 改为 ovti,ov5640添加完整端口描述
        1. 添加电源和时钟管理devm_clk_get + devm_regulator_bulk_get + devm_gpiod_get
        1. 对接 CSI-2 桥接驱动i.MX8MP 的 imx8-isi / imx-mipi-csi2 驱动通过 v4l2_async_notifier 自动绑定 Sensor

        12. 下一步扩展方向

        1. Triggered Buffer + DMA 抓帧 — 配合 CSI DMA 控制器实现连续帧捕获,用 v4l2-ctl --stream-mmap 验证
        1. ISP 流水线 — 在 Sensor 和 Video Device 之间插入 ISP 子设备,实现去马赛克、白平衡等处理
        1. media-ctl 拓扑配置 — 使用 media-ctl -lmedia-ctl -V 配置完整的 Sensor → CSI → ISP → Video 链路
        1. V4L2 用户态应用 — 使用 libv4l2 编写摄像头预览和录制程序
        1. IMU + Camera 时间戳同步 — IIO 触发器与 V4L2 缓冲区时间戳对齐,构建完整感知平台
        上一篇
        Data Structure and Algorithm
        下一篇
        用面试拷问嵌入式技术栈

        Comments
        Loading...