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 必须与硬件连接一致
个人习惯:我每次拿到一颗新Sensor,第一件事不是调图像质量,而是先读它的datasheet,把PCLK和VTS/HTS的公式算清楚。算不对这个,后面所有配置都是空中楼阁。

驱动代码里,核心是初始化序列。通常是一组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>;
            };
        };
    };
};
注意:data-lanes的顺序不是随便写的。它必须对应Sensor输出的物理Lane顺序。我曾经遇到一个项目,硬件工程师把Lane 2和Lane 3接反了,结果图像颜色完全错乱。排查了三天才发现是这个问题。

配置完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数据看起来全是噪声,检查一下字节序对不对。我习惯在抓取工具里加一个参数,允许用户指定字节序。
我的建议:第一次调通Sensor驱动后,别急着调图像质量。先抓一帧RAW数据,用工具验证一下数据完整性。比如检查一下像素值范围是不是0-1023(如果是RAW10),有没有全黑或全白的行。这一步能帮你快速定位硬件或驱动问题。

3.5 本章知识体系图

我把这一章的核心流程画了一张图,你对照着看,思路会更清晰:

RAW数据采集流程 RAW数据采集核心流程 Sensor I2C驱动配置 MIPI CSI 设备树配置 rk_aiq工具 RAW数据文件 关键检查点: 1. Sensor初始化时序是否正确(复位延时足够) 2. MIPI时钟与PCLK是否匹配(用示波器验证)

这张图把整个流程串起来了:从Sensor硬件开始,经过I2C驱动配置和MIPI CSI接口配置,最后通过rk_aiq工具抓取RAW数据。每一步都有对应的检查点,你按这个流程走,基本不会出大问题。