4、图像传感器接口与数据采集:MIPI CSI-2协议解析、Sensor驱动配置、RAW数据格式
图像传感器是ISP流水线的起点。说白了,Sensor没配好,后面算法再牛也白搭。这一章我们聚焦三个核心:MIPI CSI-2物理层和协议怎么跑、Sensor驱动怎么配、RAW数据到底长什么样。
4.1 MIPI CSI-2协议解析
MIPI CSI-2是目前移动端和嵌入式视觉系统最主流的Sensor接口。我最早接触它是在做手机摄像头项目时,那时候对D-PHY的时序要求理解不深,结果第一版板子跑不到目标速率,折腾了两周才找到问题——原来是PCB走线等长没做好。
4.1.1 物理层:D-PHY
CSI-2的物理层通常是D-PHY,采用差分信号传输。一条lane由一对差分线(Dp/Dn)组成。常见的配置是1-lane、2-lane或4-lane。
| 参数 | 典型值 | 说明 |
|---|---|---|
| 每lane速率 | 80 Mbps ~ 2.5 Gbps | 取决于Sensor和SoC能力 |
| 工作模式 | HS(高速)/ LP(低功耗) | HS传数据,LP传控制 |
| 电压摆幅 | HS: 200mV / LP: 1.2V | 差分摆幅很小,抗干扰强 |
| 时钟lane | DDR双边沿采样 | 每个时钟沿传1bit |
D-PHY有两种工作状态:高速模式(HS) 和 低功耗模式(LP)。HS模式下数据以差分信号高速传输,LP模式下用单端信号传输控制指令。嗯,这里要注意:从LP切换到HS需要经过一个特定的时序序列(LP-11 → LP-01 → LP-00 → HS-0),这个时序必须严格满足,否则接收端会丢包。
4.1.2 协议层:CSI-2 LLP
CSI-2的协议层叫LLP(Low Level Protocol)。它定义了数据怎么打包成包(Packet)传输。每个包分为短包(Short Packet) 和 长包(Long Packet)。
- 短包: 只有包头,没有数据负载。用于帧同步、行同步、事件触发等控制信息。
- 长包: 包含包头、数据负载和包尾。数据负载就是实际的像素数据。
包的结构如下:
长包格式:
[SoT] [PH: 2字节数据ID + 2字节字计数 + 1字节ECC] [Payload: 字计数指定长度] [PF: 2字节CRC16] [EoT]
短包格式:
[SoT] [PH: 2字节数据ID + 2字节数据值 + 1字节ECC] [EoT]
数据ID(Data Identifier)包含虚拟通道(VC) 和数据类型(DT)。VC支持最多4个虚拟通道,可以复用同一条物理链路传输多路视频流。DT则标识了数据类型,比如RAW8、RAW10、YUV422等。
4.1.3 帧结构
一帧图像在CSI-2链路上是这样组织的:
FS(帧起始短包) → Line1(行长包) → Line2(行长包) → ... → LineN(行长包) → FE(帧结束短包)
每一行数据作为一个长包传输。行与行之间可以有消隐区(HBlank),帧与帧之间有帧消隐(VBlank)。这些消隐时间可以用来做其他处理,比如DMA传输或CPU干预。
4.2 Sensor驱动配置
Sensor驱动配置是嵌入式系统工程师的必修课。我习惯把配置流程分成三步:硬件初始化 → 寄存器配置 → 流控管理。
4.2.1 硬件初始化
上电时序是第一步,也是最容易出问题的地方。不同Sensor对电源上电顺序有严格要求,比如:
- 先上模拟电源(AVDD)
- 再上数字电源(DVDD)
- 最后上IO电源(IOVDD)
- 等待稳定后,释放复位信号
- 等待MCLK稳定
- 通过I2C/SPI读取Sensor ID确认通信正常
4.2.2 寄存器配置
Sensor的寄存器配置通常通过I2C或SPI接口进行。典型的配置项包括:
| 寄存器组 | 典型地址 | 配置内容 |
|---|---|---|
| 模式选择 | 0x0100 | 软件复位、待机/流控模式 |
| 分辨率 | 0x0340-0x0347 | 输出宽度、高度、起始位置 |
| 帧率控制 | 0x0348-0x034B | 行时间、帧消隐、PLL分频 |
| 输出格式 | 0x0112 | RAW8/RAW10/RAW12/YUV等 |
| 增益/曝光 | 0x0202-0x0205 | 模拟增益、数字增益、曝光时间 |
| MIPI配置 | 0x0300-0x0307 | Lane数、速率、时钟分频 |
下面是一个典型的Sensor初始化代码片段(伪代码):
// 1. 上电后等待10ms
delay_ms(10);
// 2. 读取Sensor ID确认通信
uint16_t id = i2c_read_16bit(0x0000);
if (id != 0x1234) {
printf("Sensor ID mismatch!\n");
return -1;
}
// 3. 软件复位
i2c_write_8bit(0x0103, 0x01);
delay_ms(5);
// 4. 配置输出分辨率 1920x1080
i2c_write_16bit(0x0340, 1080); // 输出高度
i2c_write_16bit(0x0342, 2200); // 行长度(含消隐)
// 5. 配置输出格式 RAW10
i2c_write_8bit(0x0112, 0x2B); // 0x2B = RAW10
// 6. 配置MIPI 4-lane, 速率 800Mbps/lane
i2c_write_8bit(0x0305, 0x04); // Lane数
i2c_write_16bit(0x0307, 0x0064); // PLL配置
// 7. 启动流控
i2c_write_8bit(0x0100, 0x01); // Streaming ON
4.2.3 流控管理
流控(Streaming)管理控制Sensor是否持续输出图像数据。启动流控后,Sensor会按照配置的帧率和分辨率持续通过MIPI接口发送数据。停止流控时,Sensor进入待机模式,功耗大幅降低。
我建议在系统初始化时先配置好所有寄存器,最后再启动流控。这样能避免在配置过程中产生不完整帧。
4.3 RAW数据格式
RAW数据是Sensor直接输出的原始像素值,未经任何ISP处理。它保留了最完整的图像信息,也是ISP算法的输入起点。
4.3.1 Bayer模式
大多数彩色Sensor使用Bayer滤色阵列。每个像素只采集一种颜色分量(R、G或B),通过插值算法恢复全彩色。常见的Bayer模式有:
- BGGR: 第一行 B G B G ...,第二行 G R G R ...
- RGGB: 第一行 R G R G ...,第二行 G B G B ...
- GBRG: 第一行 G B G B ...,第二行 R G R G ...
- GRBG: 第一行 G R G R ...,第二行 B G B G ...
嗯,这里要注意:不同Sensor的Bayer模式可能不同,配置错了会导致颜色完全错乱。我习惯在驱动初始化时读取Sensor的寄存器确认Bayer模式,而不是硬编码。
4.3.2 RAW位深与存储
RAW数据常见的位深有8bit、10bit、12bit、14bit、16bit。位深越高,动态范围越大,但数据量也越大。
| 位深 | 每像素bit数 | 存储方式 | 典型应用 |
|---|---|---|---|
| RAW8 | 8 | 1字节/像素 | 低端摄像头、预览 |
| RAW10 | 10 | 5字节/4像素(packed)或2字节/像素(unpacked) | 主流手机、安防 |
| RAW12 | 12 | 3字节/2像素(packed)或2字节/像素(unpacked) | 工业相机、医疗 |
| RAW16 | 16 | 2字节/像素 | 高动态、科学级 |
RAW10的packed存储方式比较特殊:每4个像素占用5个字节。比如像素值分别是A[9:0]、B[9:0]、C[9:0]、D[9:0],存储为:
Byte0: A[7:0]
Byte1: B[7:0]
Byte2: C[7:0]
Byte3: D[7:0]
Byte4: {A[9:8], B[9:8], C[9:8], D[9:8]}
这种打包方式节省带宽,但处理时需要拆包。我在项目中通常用unpacked方式,虽然多占内存,但CPU处理起来更简单。
4.3.3 RAW数据在内存中的布局
Sensor通过MIPI接口传输的数据,经过接收端(如SoC的CSI控制器)后,会被DMA写入内存。内存中的布局通常是:
地址偏移: 0x0000 ~ 0x0FFF → Line0 (1920像素, RAW10 packed = 2400字节)
地址偏移: 0x1000 ~ 0x1FFF → Line1
...
地址偏移: 0x0438000 ~ 0x0438FFF → Line1079
每行数据可能有对齐要求(比如32字节对齐)。如果不对齐,DMA传输可能会出错。我建议在分配DMA缓冲区时,使用cacheline对齐的内存,避免cache一致性问题。
4.4 本章知识体系
下面这张图总结了本章的核心知识点和它们之间的关系:
4.5 嵌入式系统采集实战要点
最后,我把嵌入式系统中采集Sensor数据的几个关键点列出来,这些都是我在实际项目中踩过的坑:
- DMA缓冲区管理: 使用双缓冲(ping-pong buffer)避免丢帧。一个缓冲区在DMA传输,另一个供CPU处理。
- 帧同步: 通过CSI-2的FS/FE短包或Sensor的VSYNC信号判断帧边界。我习惯用硬件VSYNC中断,比轮询更可靠。
- 数据校验: 抓取第一帧后,检查帧大小是否等于 宽度×高度×每像素字节数。如果不一致,说明配置有问题。
- 时钟域同步: MIPI时钟和系统总线时钟是异步的,需要FIFO或桥接逻辑做跨时钟域处理。