ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

RK3399 驱动 IMX335 摄像头:设备树配置与 V4L2 出图实战

RK3399 驱动 IMX335 摄像头:设备树配置与 V4L2 出图实战 简介这是一份面向嵌入式驱动开发者的RK3399/RK3399 Pro平台IMX335 Sensor驱动资源主要解决该平台下IMX335摄像头IIC驱动适配与ISP配置的问题适合具备一定Linux内核与Camera驱动基础的工程师参考使用。压缩包共2个文件包含1个C语言驱动源码和1个XML配置文件整体约98KB其中C文件承载IIC通信与Sensor寄存器初始化逻辑XML文件则提供配套ISP参数配置两者配合可完成驱动加载与图像调试。资源已获得1270人学习下载说明其在同类平台适配中具有一定参考价值。读者可从中获取IMX335在RK3399上的驱动实现思路、寄存器配置方法以及ISP XML参数组织方式便于快速移植到自有板卡或进行二次调试减少从零编写驱动的试错成本。1. rk3399 上跑 imx335从设备树到出图的完整链路手里有一块 rk3399 的开发板摄像头接口上插了一颗索尼 imx335系统起来之后/dev/video*死活不出来或者出来了但抓到的帧全是绿的、花的、卡成幻灯片——这是很多做嵌入式视觉的同行都会撞上的场景。imx335 是一颗 500 万像素的 CMOS 传感器MIPI CSI-2 输出在安防、机器视觉、车载环视里用得很多rk3399 则是瑞芯微那颗双核 A72 加四核 A53 的经典 SoCV4L2 和 media controller 框架都比较完整。把这两者接起来本质上要打通三件事I2C 能读到 sensor 的 ID、MIPI CSI-2 链路能稳定出数据、V4L2 子设备能注册成可用的 video node。这篇笔记就按这条链路把设备树怎么写、驱动怎么配、参数怎么调、翻车了看哪里一条条讲清楚。适合正在做 rk3399 摄像头 bring-up 的驱动工程师也适合想从零理解 V4L2 sensor 驱动模型的开发者。2. imx335 与 rk3399 的硬件链路先搞清楚数据怎么走2.1 从 sensor 到 ISP 再到内存的通路imx335 输出的是 MIPI CSI-2 的 RAW10 数据经过 rk3399 的 MIPI CSI-2 接收控制器在 TRM 里叫 MIPI CSI Host再送到 ISP 或者直接走 VICAP 通道写入内存。rk3399 的摄像头子系统有几个关键模块MIPI D-PHY、CSI-2 控制器、ISP、以及 V4L2 层的 rkisp 驱动。imx335 作为 I2C 从设备挂在某条 i2c 总线上地址通常是 0x1a7 位地址写地址 0x34。上电时序里 sensor 需要几路电源AVDD 2.8V、DVDD 1.2V、DOVDD 1.8V还有 MCLK一般 24MHz 或 27MHz和复位、电源使能 GPIO。这些在设备树里都要一一对应少一路电源或者 MCLK 频率不对I2C 就读不到 ID后面全免谈。数据通路上还有一个容易忽略的点rk3399 的 MIPI CSI-2 有 lane 数的限制imx335 可以配成 2 lane 或 4 lane。如果硬件只走了 2 lane设备树里却写了 4 lane链路训练就会失败表现为 dmesg 里一堆 CSI 错误但 I2C 正常。所以第一步不是写代码而是拿原理图确认 lane 数、MCLK 频率、I2C 地址、电源和 GPIO 的对应关系。2.2 设备树里必须写对的几个节点rk3399 的摄像头设备树一般分三层SoC 级的 MIPI CSI 控制器节点、板级的 I2C 和 GPIO 配置、以及 sensor 自己的节点。下面是一个最小可用的 imx335 节点示例放在 i2c 节点下面i2c4 { status okay; clock-frequency 400000; imx335: imx3351a { compatible sony,imx335; reg 0x1a; clocks cru CLK_MIPIDPHY_REF; clock-names xvclk; power-domains power RK3399_PD_ISP; reset-gpios gpio2 RK_PD3 GPIO_ACTIVE_LOW; pwdn-gpios gpio2 RK_PD4 GPIO_ACTIVE_HIGH; /* 电源 regulator 引用按实际板子填 */ avdd-supply vcc_2v8; dvdd-supply vcc_1v2; dovdd-supply vcc_1v8; port { imx335_out: endpoint { remote-endpoint mipi_in_imx335; ># 在 drivers/media/i2c/Makefile 里加 obj-$(CONFIG_VIDEO_IMX335) imx335.o # 在 drivers/media/i2c/Kconfig 里加 config VIDEO_IMX335 tristate Sony IMX335 sensor support depends on I2C VIDEO_V4L2 VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE help This is a driver for the Sony IMX335 CMOS image sensor.然后在 defconfig 里打开CONFIG_VIDEO_IMX335y重新编译内核。如果驱动是作为模块编的还要确认modules.order和modules.builtin里没有冲突。编译完把 dtb 和 Image 一起烧进去启动后先看dmesg | grep imx335正常应该能看到 probe 成功的日志和 sensor ID 的打印。3.2 probe 函数里必须检查的返回值imx335 驱动的 probe 流程一般是拿 regulator、使能时钟、复位、读 chip ID、注册 v4l2 subdev。下面这段是 probe 里读 ID 的核心逻辑很多翻车都出在这里static int imx335_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct imx335 *imx335; int ret; imx335 devm_kzalloc(client-dev, sizeof(*imx335), GFP_KERNEL); if (!imx335) return -ENOMEM; imx335-client client; /* 拿电源顺序一般是 dovdd - avdd - dvdd */ imx335-dovdd devm_regulator_get(client-dev, dovdd); if (IS_ERR(imx335-dovdd)) return PTR_ERR(imx335-dovdd); ret regulator_enable(imx335-dovdd); if (ret) return ret; /* 使能 MCLKimx335 一般要 24MHz */ imx335-xvclk devm_clk_get(client-dev, xvclk); if (IS_ERR(imx335-xvclk)) return PTR_ERR(imx335-xvclk); ret clk_set_rate(imx335-xvclk, 24000000); if (ret) return ret; ret clk_prepare_enable(imx335-xvclk); if (ret) return ret; /* 复位拉低至少 1ms 再拉高 */ gpiod_set_value_cansleep(imx335-reset_gpio, 0); usleep_range(1000, 2000); gpiod_set_value_cansleep(imx335-reset_gpio, 1); usleep_range(1000, 2000); /* 读 chip IDimx335 的 ID 寄存器是 0x3000 起 */ ret imx335_read_reg(imx335, IMX335_CHIP_ID, val); if (ret) { dev_err(client-dev, failed to read chip id\n); goto err_clk; } if (val ! IMX335_CHIP_ID_VAL) { dev_err(client-dev, chip id mismatch: 0x%x\n, val); ret -ENODEV; goto err_clk; } /* 注册 v4l2 subdev后面 media controller 才能找到它 */ ret imx335_register_subdev(imx335); if (ret) goto err_clk; return 0; err_clk: clk_disable_unprepare(imx335-xvclk); return ret; }这段代码里电源使能顺序、MCLK 频率、复位时序、chip ID 校验每一步失败都会导致 probe 失败。最常见的现象是chip id mismatch原因通常是 I2C 地址不对、电源没上、MCLK 没起或者复位时序不对。排查时先用万用表量各路电源再用示波器看 MCLK 有没有 24MHz 输出最后用i2cdetect -y 4确认 I2C 地址能不能扫到。3.3 用 v4l2-ctl 验证出图的最小命令驱动 probe 成功、media controller 链路也 link 好之后就可以用v4l2-ctl抓帧验证。先看拓扑# 查看 media 设备拓扑确认 imx335 - mipi - isp 链路 media-ctl -p -d /dev/media0 # 配置格式1080pRAW10 media-ctl -d /dev/media0 --set-v4l2 imx335 4-001a:0[fmt:SRGGB10_1X10/1920x1080] media-ctl -d /dev/media0 --set-v4l2 rkisp1-isp-subdev:0[fmt:SRGGB10_1X10/1920x1080] # 抓 10 帧存成 raw v4l2-ctl -d /dev/video0 --set-fmt-videowidth1920,height1080,pixelformatRG10 \ --stream-mmap --stream-count10 --stream-toframe.raw抓出来的 raw 可以用raw2rgb或者自己写个 python 脚本转成可视图像确认不是全绿或全黑。如果media-ctl -p里看不到 imx335 的 entity说明 subdev 没注册成功如果链路有但抓帧超时多半是 MIPI lane 数或 link-frequencies 配错了。4. 避坑与排查imx335 在 rk3399 上最容易翻车的 5 个点4.1 现象I2C 能扫到地址但 probe 报 chip id mismatch原因电源时序不对或者 MCLK 没起。imx335 要求 DVDD 先于 AVDD 上电或者至少同时上如果 AVDD 先上而 DVDD 没到内部寄存器读出来就是 0 或 0xff。另外 MCLK 必须在复位释放之前就稳定否则 sensor 内部 PLL 锁不住。解决用示波器抓 MCLK 和复位信号的时序确认 MCLK 先于复位拉高至少 1ms。电源用regulator-always-on或者确认驱动里regulator_enable的调用顺序。如果板子上电源是硬件常开的检查 dts 里 regulator 节点有没有被其他驱动关掉。4.2 现象/dev/video0 出来了但抓帧全是绿色原因MIPI lane 数配错或者># 查看当前链路 media-ctl -p -d /dev/media0 # 把 imx335 的输出直接 link 到 vicap media-ctl -d /dev/media0 -l imx335 4-001a:0-rkisp1-isp-subdev:0[1] media-ctl -d /dev/media0 -l rkisp1-isp-subdev:2-rkisp1_video:0[1]这个技巧在调试阶段特别有用改完立刻生效不用反复烧固件。但要注意链路改了之后格式也要跟着改否则会报Invalid argument。5.2 imx335 的 HDR 模式配置要点imx335 支持 2 帧和 3 帧 HDR配置 HDR 时寄存器序列和线性模式不一样主要是曝光和 gain 的寄存器地址会变。在驱动里一般通过v4l2_ctrl暴露 HDR 模式用户态用v4l2-ctl -c hdr_mode2切换。HDR 模式下 MIPI 输出的数据量翻倍link-frequencies要相应提高否则会丢帧。另外 HDR 的 RAW 数据是交错的ISP 那边要配对应的 HDR 解析模式否则出来的图会重影。5.3 一个我常用的验证习惯每次改完 dts 或驱动我不会直接上完整应用而是按这个顺序过一遍先i2cdetect确认地址再dmesg | grep imx335确认 probe再media-ctl -p确认拓扑再v4l2-ctl --stream-count10抓 raw最后用 python 把 raw 转成 png 肉眼确认。这个顺序能保证每一步的问题都在当前层暴露不会把 I2C 的问题拖到 MIPI 层去查。血泪经验是很多“MIPI 链路问题”最后查下来都是 I2C 没读通或者电源没上先花五分钟确认底层能省半天翻车时间。希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进