3、RAW数据采集:Sensor驱动配置、MIPI CSI接口配置、RAW数据抓取工具
好,咱们进入第三讲。前两章我们把ISP Pipeline的宏观架构和RAW数据的格式聊清楚了。这一章,咱们得动真格的了——怎么让Sensor真正跑起来,把RAW数据抓到手里。
说白了,这一步是ISP Pipeline的“水源”。水源不干净,或者压根没水,后面再牛的算法也是白搭。我见过不少项目,算法团队在PC上仿真跑得飞起,一上板子图像全是花的,最后查出来是Sensor初始化时序没配好。嗯,这种坑,咱们得绕过去。
3.1 Sensor驱动配置:让“眼睛”睁开
Sensor就像相机的“视网膜”。驱动配置的核心,就是告诉这颗Sensor:你该用什么帧率、什么分辨率、什么增益模式开始工作。
在RK平台上,Sensor驱动通常是一个I2C设备驱动。你需要配置的关键参数,我列个表,你对照着看:
| 参数项 | 典型值/范围 | 说明 |
|---|---|---|
| PCLK (Pixel Clock) | 74.25 MHz / 150 MHz | 决定了数据输出的速率,必须与MIPI速率匹配 |
| 帧率 (FPS) | 30 / 60 / 120 | 由VTS和HTS计算得出,注意不要超过Sensor极限 |
| 分辨率 | 1920x1080 / 3840x2160 | 需要与ISP的输入分辨率对齐 |
| 曝光时间 | 1/30 s ~ 1/10000 s | 通过调整行数或步长控制 |
| 增益 (Gain) | 1x ~ 16x (模拟+数字) | 模拟增益优先,数字增益会引入噪声 |
| MIPI Lane数 | 2-lane / 4-lane | 必须与硬件连接一致 |
驱动代码里,核心是初始化序列。通常是一组I2C写操作,按顺序写入寄存器。我截一段伪代码,你感受一下结构:
// Sensor初始化序列示例
static const struct regval_list sensor_init_regs[] = {
{0x0103, 0x01}, // 软件复位
{0x0100, 0x00}, // 进入待机模式
// 配置PLL
{0x0300, 0x05}, // PLL预分频
{0x0301, 0x1E}, // PLL倍频系数
{0x0302, 0x01}, // PLL后分频
// 配置输出格式
{0x0340, 0x04}, // 输出分辨率高字节
{0x0341, 0x38}, // 输出分辨率低字节 (1080)
// 配置MIPI
{0x3010, 0x0F}, // 使能4-lane MIPI
{0x0100, 0x01}, // 进入流模式
};
这里有个坑,我提醒你一下:复位后一定要加延时。有些Sensor复位后需要几毫秒才能稳定,你紧接着写配置,它可能根本没响应。我曾经在这个问题上浪费了半天,最后发现是延时不够。
3.2 MIPI CSI接口配置:数据的高速公路
Sensor把RAW数据准备好了,怎么传到SoC?走MIPI CSI接口。这就像一条高速公路,Sensor是出发地,ISP是目的地,MIPI就是中间的路。
配置MIPI CSI,核心是三个东西:
- 时钟(Clock):MIPI的差分时钟,频率必须和Sensor的PCLK匹配。不匹配的话,数据采样会出错。
- 数据通道(Data Lane):2-lane还是4-lane,决定了带宽。4-lane能跑更高的分辨率或帧率。
- 协议(Protocol):RAW8、RAW10还是RAW12?这个必须和Sensor输出格式一致。
在RK平台上,MIPI D-PHY的配置通常在设备树(DTS)里完成。我举个例子:
// RK3588 MIPI CSI DTS配置片段
&csi2_dphy0 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
mipi_in: endpoint {
remote-endpoint = <&sensor_out>;
data-lanes = <1 2 3 4>; // 4-lane模式
clock-lanes = <0>;
};
};
};
};
配置完DTS,还需要在驱动里设置MIPI的时序参数。比如:
- HS-Trail:高速传输结束后的保持时间
- CLK-Post:时钟通道在最后一个数据通道结束后的保持时间
- LPX:低功耗状态下的脉冲宽度
这些参数通常在Sensor的datasheet里有推荐值。如果你不熟悉,直接用推荐值就行。但如果你发现MIPI信号不稳定,比如图像有横纹或者丢帧,可以微调这些参数。
3.3 RAW数据抓取工具:rk_aiq实战
驱动配好了,MIPI也通了,怎么确认数据真的进来了?用工具抓一把RAW数据看看。
RK平台最常用的工具是rk_aiq。它不仅能抓RAW,还能做ISP调试。但这一讲,我们只聚焦在“抓取”这个动作上。
基本用法很简单:
// 抓取一帧RAW数据
rk_aiq -i /dev/video0 -o output.raw -w 1920 -h 1080 -f NV12
// 参数说明:
// -i: 输入设备节点,通常是 /dev/video0 或 /dev/video1
// -o: 输出文件名
// -w -h: 图像宽高
// -f: 输出格式,NV12是YUV格式,但我们可以指定RAW格式
但这里有个关键点:rk_aiq默认输出的是经过ISP处理后的YUV数据。如果你想抓原始的Bayer RAW,需要加一个参数:
// 抓取RAW10格式的Bayer数据
rk_aiq -i /dev/video0 -o raw_bayer.raw -w 1920 -h 1080 -f RAW10
为什么抓RAW这么重要?
因为只有RAW数据才能真实反映Sensor的原始性能。你拿YUV数据去分析噪声、坏点、动态范围,结果已经被ISP“美化”过了,不准确。我习惯在项目初期,先抓几帧RAW数据,用工具(比如Imatest或自己写的Python脚本)做一次“体检”,看看Sensor本身有没有问题。
抓取完成后,你会得到一个.raw文件。这个文件怎么打开?你可以用Python的numpy和matplotlib来读取和显示:
import numpy as np
import matplotlib.pyplot as plt
# 读取RAW10数据,每个像素10bit,但存储时通常按16bit对齐
width, height = 1920, 1080
raw_data = np.fromfile('raw_bayer.raw', dtype=np.uint16)
raw_data = raw_data.reshape((height, width))
# 显示图像(注意:RAW是Bayer模式,直接显示会有马赛克)
plt.imshow(raw_data, cmap='gray')
plt.show()
你看到的会是一张灰蒙蒙的图,上面有细密的网格。别慌,那是Bayer pattern。下一章我们会讲怎么把它变成彩色图像。
3.4 避坑指南:我踩过的几个雷
最后,分享几个我在项目中真实遇到的坑,你遇到了可以少走弯路:
- MIPI时钟不准:有一次我抓到的RAW图像有规律的条纹,排查了很久,最后发现是SoC的MIPI PLL配置不对,导致时钟频率偏差了0.5%。用示波器一量,果然。解决方案是重新计算PLL参数。
- Sensor ID读取失败:驱动加载时,会先读Sensor的ID寄存器来确认硬件是否存在。如果I2C通信有问题,ID读不到,驱动会直接报错。我建议你在驱动初始化时,加一个重试机制,最多重试3次,每次间隔10ms。
- RAW数据字节序:有些Sensor输出的是大端(Big Endian),有些是小端(Little Endian)。如果你抓到的RAW数据看起来全是噪声,检查一下字节序对不对。我习惯在抓取工具里加一个参数,允许用户指定字节序。
3.5 本章知识体系图
我把这一章的核心流程画了一张图,你对照着看,思路会更清晰:
这张图把整个流程串起来了:从Sensor硬件开始,经过I2C驱动配置和MIPI CSI接口配置,最后通过rk_aiq工具抓取RAW数据。每一步都有对应的检查点,你按这个流程走,基本不会出大问题。