第一章:Sensor驱动基础——MIPI CSI-2协议、上电时序与I2C调试
各位同学,欢迎来到《瑞芯微Sensor驱动与ISP Pipeline对接实战》的第一章。
做嵌入式视觉,说白了就是让摄像头把光信号变成芯片能处理的数字信号。这中间要过好几道关:Sensor本身怎么工作、数据怎么传过来、ISP怎么接住。咱们第一章,先把最基础的三件事讲透——MIPI CSI-2协议、Sensor上电时序、I2C通信调试。
这三件事,我当年刚入行时踩过不少坑。有一次调一颗索尼的Sensor,上电时序差了0.5ms,结果图像全是花屏,查了三天才发现是reset信号给早了。嗯,这种教训,我希望你们别重复。
本章核心目标:理解MIPI CSI-2物理层与协议层的基本概念,掌握Sensor上电时序的硬件要求,学会用I2C工具调试Sensor寄存器。
1.1 MIPI CSI-2协议概述
MIPI CSI-2,全称是Camera Serial Interface 2,是移动设备和嵌入式平台最主流的摄像头接口协议。瑞芯微的RK3588、RK3568、RV1126这些芯片,CSI-2接口都是标配。
CSI-2的物理层基于MIPI D-PHY。D-PHY使用差分信号传输,一对差分线就是一个Lane。典型的配置是1个Clock Lane + 1~4个Data Lane。数据在DDR模式下传输——时钟的上升沿和下降沿都采样数据,所以带宽利用率很高。
CSI-2协议的分层结构:
- 物理层(PHY Layer):D-PHY规范,定义电气特性、线序、时序。
- 协议层(Protocol Layer):定义数据包格式、帧结构、数据类型。
- 应用层(Application Layer):定义像素格式、数据映射,比如RAW10、RAW12、YUV422。
我个人习惯把CSI-2的数据流想象成「快递包裹」:
- 每一帧图像是一个大包裹
- 每行数据是一个小包裹
- 每个包裹有包头(Header)和包尾(Footer)
- 包头里包含了数据类型、像素格式、行长度等信息
CSI-2的数据包类型,常用的有这些:
| 数据类型(Data Type) | 描述 | 常见场景 |
|---|---|---|
| 0x2B | RAW10 | 10-bit原始Bayer数据 |
| 0x2C | RAW12 | 12-bit原始Bayer数据 |
| 0x1E | YUV422 8-bit | 处理后的YUV数据 |
| 0x12 | JPEG | 压缩图像数据 |
避坑提示:我曾经在调试RK3588时,Sensor输出的是RAW10,但CSI-2配置成了RAW12。结果图像亮度异常,每个像素都偏暗。检查了半天才发现是数据类型不匹配。记住:Sensor输出什么格式,CSI-2就要配什么格式,一个字都不能错。
下面这张图,是我画的一个CSI-2数据流的结构图,帮你理解数据是怎么从Sensor走到SoC的:
1.2 Sensor上电时序与硬件原理图解读
Sensor是个精密的模拟器件。它需要严格的电源上电顺序,否则轻则图像异常,重则烧毁芯片。你想想看,Sensor内部有模拟电路、数字电路、IO电路,它们对电源的依赖完全不同。
典型的Sensor电源域:
- AVDD(模拟电源):通常2.8V,给像素阵列和模拟前端供电。
- DVDD(数字核心电源):通常1.2V或1.8V,给数字逻辑供电。
- IOVDD(IO电源):通常1.8V,给I2C、MIPI接口供电。
上电时序,说白了就是这三个电源谁先来、谁后来,以及复位信号什么时候释放。不同厂家的Sensor要求不一样,但有个通用原则:先模拟、后数字、再IO,最后释放复位。
我拿一颗常见的Sensor举例,它的上电时序要求是这样的:
| 步骤 | 动作 | 时间要求 | 说明 |
|---|---|---|---|
| 1 | AVDD上电 (2.8V) | t0 | 模拟电源先稳定 |
| 2 | DVDD上电 (1.2V) | t0 + 1ms | 数字核心后上电 |
| 3 | IOVDD上电 (1.8V) | t0 + 2ms | IO接口最后上电 |
| 4 | MCLK提供时钟 | t0 + 3ms | 主时钟稳定输入 |
| 5 | 复位释放 (XSHUTN拉高) | t0 + 5ms | 所有电源稳定后释放复位 |
| 6 | I2C初始化配置 | t0 + 10ms | 复位后等待至少5ms再写寄存器 |
警告:千万不要忽略上电时序!我曾经在一个项目里,硬件工程师把DVDD和IOVDD用同一个LDO供电,导致上电时两个电源同时起来。Sensor虽然能工作,但图像偶尔会出现横纹干扰。查了两个月,最后发现是电源纹波耦合到了像素阵列。换成分立LDO供电后,问题彻底解决。
看硬件原理图时,我一般会关注这几个关键点:
- 电源网络:确认AVDD、DVDD、IOVDD是否独立LDO供电,滤波电容是否足够。
- 复位引脚:XSHUTN或RESET_N,确认上拉/下拉电阻是否正确。
- MIPI差分对:确认D0P/D0N、D1P/D1N、CLKP/CLKN等差分线是否等长,阻抗是否匹配(通常100Ω差分阻抗)。
- I2C引脚:确认SCL/SDA是否有上拉电阻(通常1.5kΩ~4.7kΩ)。
1.3 I2C通信调试实战
I2C是Sensor和SoC之间最常用的控制接口。Sensor的寄存器配置、增益设置、曝光控制,全走I2C。如果I2C不通,Sensor就像个哑巴,你喊它它不理。
在瑞芯微平台上,调试I2C最常用的工具是i2c-tools。这套工具集包含i2cdetect、i2cget、i2cset、i2cdump等命令,非常实用。
I2C调试的基本步骤:
- 确认I2C总线编号:在瑞芯微平台上,Sensor通常挂在I2C2或I2C3上。用
i2cdetect -l列出所有I2C总线。 - 扫描设备地址:用
i2cdetect -y <bus_number>扫描总线上的设备。Sensor的I2C地址通常是0x30、0x36、0x6C等。 - 读取寄存器:用
i2cget -y <bus_number> <device_addr> <reg_addr> w读取寄存器值。 - 写入寄存器:用
i2cset -y <bus_number> <device_addr> <reg_addr> <value> w写入寄存器值。
举个例子,假设Sensor的I2C地址是0x36,挂在I2C3上,我想读取芯片ID寄存器(地址0x0000):
# 扫描I2C3总线,看0x36设备是否存在
i2cdetect -y 3
# 读取0x0000寄存器的值(16位地址,16位数据)
i2cget -y 3 0x36 0x0000 w
# 写入0x0000寄存器为0x1234
i2cset -y 3 0x36 0x0000 0x1234 w
调试技巧:我习惯在驱动初始化函数里,第一步就读Sensor的芯片ID。如果读回来的值和数据手册对不上,说明I2C通信有问题。这时候别急着调驱动,先用i2c-tools在用户态验证一下。很多I2C问题其实是硬件问题——上拉电阻没焊、电平不匹配、或者地址搞错了。
常见的I2C调试问题:
- 设备扫描不到:检查I2C地址是否正确(7位地址还是8位地址?Sensor数据手册通常给的是7位地址,但i2cdetect显示的是8位地址,左移了一位)。
- 读取返回0xFF:大概率是设备没应答,检查电源和复位。
- 读取返回0x00:可能是寄存器地址不对,或者设备处于休眠状态。
- 写入后读取不变:检查寄存器是否只读,或者需要先解锁。
嗯,I2C调试说难不难,说简单也不简单。关键是要有耐心,一步一步排查。我见过太多人一上来就怀疑驱动代码有问题,结果最后发现是I2C地址写错了——数据手册上写的是0x30,但那是7位地址,i2cdetect要用0x60才能扫到。
本章小结:MIPI CSI-2是Sensor和SoC之间的数据通道,上电时序是Sensor正常工作的前提,I2C是控制Sensor的命脉。这三件事搞不定,后面的ISP调试根本无从谈起。下一章,我们会深入Sensor的寄存器配置,教你如何让Sensor输出正确的图像格式。