2、Sensor硬件接口:MIPI CSI-2协议基础、I2C/SPI控制接口、GPIO与Reset时序

好,咱们开始聊Sensor的硬件接口。这部分内容,说白了就是Sensor和SoC之间怎么「说话」的。一个是传图像数据的通道,一个是发控制命令的通道,还有一个是让Sensor「醒过来」或者「睡下去」的开关。这三样搞不明白,后面调驱动就是瞎忙活。

2.1 MIPI CSI-2协议基础

MIPI CSI-2,全称是Camera Serial Interface 2。它负责把Sensor采集到的像素数据,高速地传给ISP。我最早接触MIPI时,总觉得它很神秘,后来拆开看,其实就是差分信号对——D-PHY物理层加上CSI-2协议层。

2.1.1 物理层:D-PHY

D-PHY用的是差分信号,一对线传一个通道。常见的配置有:

  • 1-lane:一对时钟 + 一对数据,低端VGA Sensor常用
  • 2-lane:一对时钟 + 两对数据,1080p 30fps左右
  • 4-lane:一对时钟 + 四对数据,4K 60fps的主流选择

每个lane的速率,从几百Mbps到2.5Gbps不等。嗯,这里要注意:速率越高,PCB走线越讲究。我遇到过一块板子,4-lane MIPI走线长了2mm,结果图像边缘全是雪花——后来加长等长补偿才搞定。

关键参数速查表

参数典型值说明
差分阻抗100Ω ±10%走线必须严格匹配
线对间skew< 150ps时钟与数据线等长
电压摆幅200mV (LP) / 1.2V (HS)低功耗与高速模式切换

2.1.2 协议层:CSI-2 数据包

CSI-2的数据传输,分成了一个个「包」。每个包有包头、数据负载、包尾。我刚开始看协议文档时,被那些「长包短包」「虚拟通道」搞得头大。后来总结了一句话:CSI-2就是「谁的数据 + 什么格式 + 数据本身」

举个例子,一个RAW10格式的像素数据包:

// 伪代码示意
Packet Header: 0x2B (数据类型) + 虚拟通道ID + 数据长度
Payload:      像素数据 (RAW10, 每4个像素占5字节)
Packet Footer: CRC校验 (可选)

为什么要有虚拟通道?因为一个MIPI接口可以接多个Sensor,通过虚拟通道ID区分。我在项目中用过这个特性——一个4-lane接口接了左右两个双目Sensor,各占2个lane,虚拟通道0和1分别对应左右眼。省了一组MIPI接口,但配置起来确实麻烦。

个人经验:调试MIPI信号时,别急着看协议分析仪。先拿示波器量一下时钟和数据线的眼图。眼图清晰,说明物理层没问题;眼图模糊,先查阻抗匹配和走线长度。

2.2 I2C/SPI控制接口

Sensor的控制接口,用来读写寄存器。比如设置曝光时间、增益、输出格式等。主流方案是I2C,少数高速场景用SPI。

2.2.1 I2C:最常用的控制总线

I2C只有两根线:SCL(时钟)和SDA(数据)。Sensor作为从设备,地址一般是7位或10位。我常用的Sensor地址是0x20或0x30,具体看数据手册。

I2C的时序很简单:

  1. 主机发起始条件(SCL高时SDA拉低)
  2. 主机发从设备地址 + 读写位
  3. 从设备应答(ACK)
  4. 主机发寄存器地址
  5. 从设备应答
  6. 主机发数据(写)或从设备发数据(读)
  7. 主机发停止条件(SCL高时SDA拉高)

我曾经踩过一个坑:Sensor的I2C地址是7位的,但驱动里写成了8位左移一位的格式。结果读寄存器永远返回0xFF。查了两天才发现,是地址格式搞错了。所以,一定要确认数据手册里写的是「7位地址」还是「8位地址」

避坑指南:I2C速率别设太高。Sensor内部寄存器访问速度有限,400kHz是安全值。我试过1MHz,结果偶尔丢ACK,图像参数更新不及时,画面闪烁。

2.2.2 SPI:高速控制场景

SPI比I2C快,但多一根线。标准SPI有四根:CS(片选)、SCLK(时钟)、MOSI(主出从入)、MISO(主入从出)。Sensor作为从设备,CS拉低时开始通信。

SPI的时序模式有四种(CPOL和CPHA组合)。我习惯用模式0(CPOL=0, CPHA=0),也就是时钟空闲为低,第一个边沿采样。但不同Sensor可能不同,一定要看数据手册的时序图。

// SPI写寄存器示例(伪代码)
CS_LOW();
spi_transfer(REG_ADDR);  // 发送寄存器地址
spi_transfer(REG_VALUE); // 发送数据
CS_HIGH();

// SPI读寄存器示例
CS_LOW();
spi_transfer(REG_ADDR | 0x80); // 地址 + 读标志
value = spi_transfer(0x00);    // 发送dummy,接收数据
CS_HIGH();

SPI的好处是速度快,适合批量读写。比如初始化Sensor时,要写几十个寄存器,SPI比I2C快得多。但代价是多占一个GPIO做CS。

2.3 GPIO与Reset时序

这部分看着简单,但最容易出问题。Sensor的GPIO通常包括:

  • RESET:硬件复位,低电平有效
  • PWDN / STANDBY:掉电/待机,高电平有效
  • MCLK:主时钟输入(有时也算GPIO)

2.3.1 Reset时序要求

每个Sensor都有严格的Reset时序。我见过最典型的时序是这样的:

// Reset时序(单位:ms)
1. 拉低RESET,保持至少 1ms
2. 拉高RESET,等待 10ms(内部初始化)
3. 提供MCLK时钟,等待 5ms(PLL锁定)
4. 通过I2C/SPI配置寄存器
5. 等待 20ms(图像稳定输出)

为什么要有这些延时?因为Sensor内部有模拟电路和PLL,需要时间稳定。我遇到过一个问题:Reset后立刻写寄存器,结果写不进去。后来查数据手册,发现Reset后需要等20ms才能访问I2C。加了延时就好了。

关键时序参数

参数最小值典型值说明
Reset低电平时间1ms10ms确保内部电路放电
Reset高到I2C可用5ms20ms内部初始化完成
MCLK稳定到PLL锁定2ms5ms时钟源稳定后开始
PLL锁定到输出图像10ms30ms取决于Sensor内部

2.3.2 PWDN与RESET的区别

很多新手搞混这两个引脚。我简单解释一下:

  • RESET:硬复位,所有寄存器恢复默认值。相当于电脑重启。
  • PWDN:软掉电,寄存器值保持。相当于电脑休眠。

正常流程是:上电后先拉低RESET,再拉高,然后初始化。如果只是临时关闭Sensor(比如切换场景),用PWDN就够了,不用重新初始化寄存器。

我的习惯:在驱动里,把Reset和PWDN的时序写成函数。比如sensor_hardware_reset()sensor_standby()。这样上层调用时,不用关心具体延时多少毫秒。而且调试时,可以单独测试这两个函数,快速定位问题。

2.4 小结

Sensor硬件接口,说白了就是三件事:

  1. MIPI CSI-2:传图像数据,注意物理层走线和协议层包格式
  2. I2C/SPI:发控制命令,注意地址格式和时序模式
  3. GPIO与Reset:让Sensor正常启动,注意延时参数

这三样搞定了,Sensor就能「活」起来。下一章,咱们开始聊Sensor的初始化流程——怎么让Sensor输出第一帧图像。那才是真正让人兴奋的时刻。