2、Camera硬件基础:摄像头模组构成与接口协议
做Camera驱动开发,第一件事是什么?
不是看代码,是看硬件。我见过太多工程师上来就调寄存器,结果折腾半天发现是模组供电不对。所以今天咱们先把摄像头模组的底裤扒干净——从物理构成到通信协议,把那些你迟早要踩的坑提前说清楚。
2.1 摄像头模组三大件:Lens、Sensor、ISP
一个完整的摄像头模组,说白了就三样东西:镜头、传感器、图像处理器。我习惯把它们比作「眼睛、视网膜、视觉皮层」——缺一个都看不见东西。
2.1.1 Lens(镜头)
镜头负责把光线汇聚到传感器上。参数很多,但驱动工程师最该关注的是这几点:
- 焦距:决定了视场角。我调过一款广角镜头,边缘畸变特别严重,后来发现是镜头模组装配公差太大。
- 光圈:F值越小进光量越大。但要注意,大光圈镜头在强光下容易过曝,需要配合Sensor的曝光控制。
- VCM(音圈马达):自动对焦的核心。我踩过最大的坑——VCM驱动电流没配好,镜头咔咔响就是不对焦。
2.1.2 Sensor(图像传感器)
Sensor是模组的心脏。它把光信号转成电信号。目前主流是CMOS,少数高端用CCD。
我个人习惯把Sensor参数分成三类:
| 类别 | 关键参数 | 驱动关注点 |
|---|---|---|
| 分辨率 | 像素阵列(如1920x1080) | MIPI lane数够不够?带宽算过没? |
| 帧率 | 30fps / 60fps / 120fps | 曝光时间窗口够不够? |
| 输出格式 | RAW10 / RAW12 / YUV | ISP能不能处理?DMA配置对了吗? |
嗯,这里要注意:Sensor的寄存器配置顺序很重要。我遇到过一例——先配了输出格式再配分辨率,结果Sensor直接死锁。后来查手册才发现,某些型号必须按特定顺序初始化。
2.1.3 ISP(图像信号处理器)
ISP负责把Sensor的原始数据变成人眼能看的画面。它可能集成在Sensor内部,也可能是独立的芯片。
你想想看,Sensor输出的RAW数据有多「原始」?每个像素只有一种颜色(拜耳阵列),而且有噪声、有暗角、有坏点。ISP要干的事包括:
- 去马赛克:把拜耳阵列插值成RGB
- 自动白平衡:让白色在不同光源下看起来都是白的
- 降噪:2D降噪、3D降噪,我调过最头疼的是运动场景下的拖影
- Gamma校正:人眼对暗部更敏感,Gamma曲线就是干这个的
2.2 MIPI CSI/DSI接口协议
MIPI是移动设备上最主流的摄像头接口。CSI是摄像头接口,DSI是显示接口。咱们做Camera驱动,主要跟CSI打交道。
2.2.1 MIPI CSI物理层
MIPI用差分信号传输,一组差分对叫一个Lane。常见的配置有1-Lane、2-Lane、4-Lane。带宽怎么算?
带宽 = Lane数 × 每Lane速率 × 8/10编码效率
举个例子:4-Lane、每Lane 1Gbps,实际可用带宽是 4 × 1G × 0.8 = 3.2Gbps。够不够传1080p 60fps?算一下:1080p 60fps RAW10的数据量是 1920×1080×10×60 ≈ 1.24Gbps。嗯,绰绰有余。
但我遇到过一个问题:某款Sensor标称支持4-Lane,但实际布线时有一对差分线等长没做好,导致信号歪斜,画面出现条纹。后来我学乖了——硬件设计阶段就要求Layout工程师把MIPI差分对等长控制在±5mil以内。
2.2.2 CSI协议层
CSI协议分三层:物理层、协议层、应用层。驱动工程师最关心的是协议层——怎么把数据包解析出来。
一个典型的CSI数据包长这样:
| 包起始码 | 数据标识符 | 字计数 | 有效数据 | 校验和 |
- 包起始码:0x00000001 或 0x00000002(短包/长包)
- 数据标识符:告诉你是Y数据还是UV数据,或者是嵌入式数据
- 字计数:有效数据的字节数
- 校验和:CRC校验,我习惯在驱动里打开CRC检查,一旦出错就打印警告
2.2.3 DSI接口(顺带一提)
虽然咱们主要做Camera,但DSI也得了解。因为有些平台用DSI做预览回显——Camera数据经过ISP处理后,直接通过DSI送到显示屏。
DSI和CSI在物理层几乎一样,区别在协议层。DSI有命令模式和视频模式两种传输方式。我建议:做预览回显时用视频模式,延迟更低;做拍照预览时用命令模式,控制更灵活。
2.3 I2C/SPI控制总线
Sensor的寄存器配置、ISP的参数调整,全靠这两条总线。它们就像Camera模组的「神经」,控制着每一个像素的行为。
2.3.1 I2C总线
I2C是Camera模组最常用的控制总线。两根线:SCL(时钟)、SDA(数据)。
驱动里配置I2C时,我习惯关注三个参数:
- 速率:标准模式100kHz,快速模式400kHz。我建议用400kHz,但要注意上拉电阻——我遇到过因为上拉电阻太大,信号上升沿太慢,导致通信失败的案例。
- 地址:7位地址还是10位地址?大部分Sensor用7位。但要注意,有些Sensor的地址可以配置——通过拉高/拉低某个引脚来改变地址。我习惯在驱动里把地址做成可配置的,方便调试。
- 时序:起始条件、停止条件、应答信号。嗯,这里有个坑——有些Sensor的应答信号延迟特别大,需要把I2C控制器的时钟延展功能打开。
// 我常用的I2C读写函数模板
static int sensor_i2c_write(struct i2c_client *client, u16 reg, u8 val)
{
struct i2c_msg msg;
u8 buf[3];
int ret;
buf[0] = (reg >> 8) & 0xFF; // 寄存器高字节
buf[1] = reg & 0xFF; // 寄存器低字节
buf[2] = val; // 写入值
msg.addr = client->addr;
msg.flags = 0; // 写操作
msg.len = 3;
msg.buf = buf;
ret = i2c_transfer(client->adapter, &msg, 1);
if (ret != 1) {
dev_err(&client->dev, "I2C write failed\n");
return -EIO;
}
return 0;
}
2.3.2 SPI总线
SPI比I2C快,但线多。四根线:SCLK、MOSI、MISO、CS。有些高速Sensor会用SPI来传输配置数据,甚至有些ISP的固件升级也走SPI。
我建议:如果Sensor支持SPI和I2C两种接口,优先选SPI。为什么?因为SPI是全双工,而且没有I2C那种应答延迟。我在一个项目中把I2C换成SPI后,Sensor初始化时间从200ms降到了30ms。
但SPI也有坑:
- 时钟极性/相位:CPOL和CPHA必须和Sensor匹配。我习惯在驱动里先读Sensor的ID寄存器——如果读出来是0xFF或0x00,大概率是SPI模式配错了。
- 片选信号:有些Sensor要求CS在传输期间保持低电平,有些则要求每个字节之间拉高一次。这个必须看数据手册,不能猜。
2.4 小结
Camera硬件基础就这些。说白了,Lens负责收光,Sensor负责转电,ISP负责美化。MIPI是高速公路,I2C/SPI是控制通道。
我个人觉得,做Camera驱动最难的不是写代码,而是理解硬件怎么工作。你想想看,如果你连Sensor的曝光时间怎么配置、MIPI的带宽怎么算都不清楚,出了问题只能瞎猜。
下一章咱们开始实战——从零搭建一个Camera驱动的框架。到时候我会把今天讲的硬件知识都用上。
- 摄像头模组 = Lens + Sensor + ISP,缺一不可
- MIPI CSI带宽 = Lane数 × 每Lane速率 × 0.8
- I2C配置注意速率和上拉电阻,SPI注意时钟极性和片选
- 驱动里一定要加调试接口和总线测试函数