第3章 传感器与模组:CMOS传感器工作原理、Sensor驱动基础、模组标定简介

好,我们进入第三章。前面两章我们把ISP的全局架构和色彩基础捋了一遍。从这章开始,要真正碰硬件了——传感器。说白了,没有传感器这个“眼睛”,后面算法再牛也是白搭。

我个人习惯,讲传感器之前,先让大家明白一个事儿:ISP处理的是数字信号,但传感器输出的是模拟信号。这个转换过程,就是本章的核心。

3.1 CMOS传感器工作原理

现在市面上99%的手机、相机、车载摄像头,用的都是CMOS传感器。CCD基本退出了消费市场,只在一些工业、科研领域还能见到。

CMOS怎么工作的?我尽量用大白话讲。

每个像素点,本质上就是一个光电二极管。光子打进来,产生电子-空穴对。电子被收集,形成电压。这个电压大小,和光照强度成正比。

但这里有个关键问题:怎么把每个像素的电压读出来?

CMOS用的是“行选+列选”的寻址方式。每一行有一个行选信号,每一列有一个列选信号。要读某个像素,就打开它所在的行和列,把电压送到列总线上去。

嗯,这里要注意:同一行的像素是共享一条行选线的,同一列的像素是共享一条列总线的。所以读出的时候,是一行一行地读。

核心流程:

  1. 光子入射 → 光电转换 → 电子积累
  2. 行选通 → 像素复位 → 读出复位电压
  3. 曝光结束 → 读出信号电压
  4. 相关双采样(CDS) → 消除复位噪声
  5. 模数转换(ADC) → 输出数字码值

我在项目中遇到过一个问题:某款传感器在低光下噪点特别多。查了半天,发现是CDS时序没配好。复位电压和信号电压的采样点间隔太短,噪声没消干净。后来把时序调了一下,信噪比直接提升了3dB。

3.2 Sensor驱动基础

传感器不是上电就能用的。你得通过I2C或SPI总线,给它写寄存器,配置工作模式。

驱动要做哪些事?我列个清单:

配置项 说明 典型值
PLL配置 设置内部时钟频率 根据sensor datasheet计算
曝光时间 控制每帧的积分时间 1/30s ~ 1/10000s
增益 模拟增益和数字增益 1x ~ 16x
帧率 每秒输出多少帧 30fps / 60fps
输出格式 RAW8 / RAW10 / RAW12 RAW10最常见
窗口大小 有效像素区域 1920x1080
镜像/翻转 水平/垂直翻转 根据模组安装方向

驱动初始化的一般步骤:

  1. 上电,等待电源稳定(一般需要1-5ms)
  2. 拉高复位引脚,等待传感器内部初始化完成
  3. 通过I2C写入PLL配置,设定主时钟
  4. 配置输出格式、分辨率、帧率
  5. 配置曝光和增益的初始值
  6. 拉高STANDBY引脚,让传感器开始输出数据
  7. 等待VSYNC信号,确认第一帧到来

给你看一段简化的驱动代码,配置一个OV5640传感器:

// OV5640 初始化序列(简化版)
static const struct regval_list ov5640_init_regs[] = {
    {0x3103, 0x11},  // 系统时钟使能
    {0x3008, 0x82},  // 软件复位
    {0x3008, 0x42},  // 退出复位
    {0x3103, 0x03},  // 时钟分频配置
    {0x3034, 0x1A},  // PLL配置
    {0x3035, 0x21},  // PLL倍频
    {0x3036, 0x46},  // PLL分频
    {0x3037, 0x08},  // 输出时钟分频
    {0x3808, 0x07},  // 输出宽度高8位
    {0x3809, 0x80},  // 输出宽度低8位 (1920)
    {0x380A, 0x04},  // 输出高度高8位
    {0x380B, 0x38},  // 输出高度低8位 (1080)
    {0x3630, 0x36},  // 模拟电路配置
    {0x3631, 0x0E},
    {0x3632, 0xE2},
    {0x3633, 0x23},
    {0x3621, 0xE0},
    {0x3704, 0xA0},
    {0x3703, 0x5A},
    {0x3715, 0x78},
    {0x3717, 0x01},
    {0x3731, 0x12},
    {0x3708, 0x64},
    {0x3705, 0x1A},
    {0x3A02, 0x03},  // AEC配置
    {0x3A03, 0xD8},
    {0x3A08, 0x01},
    {0x3A09, 0x27},
    {0x3A0A, 0x00},
    {0x3A0B, 0xF6},
    {0x3A0E, 0x03},
    {0x3A0D, 0x04},
    {0x5180, 0xFF},  // AWB配置
    {0x5181, 0xF2},
    {0x5182, 0x00},
    {0x5183, 0x14},
    {0x5184, 0x25},
    {0x5185, 0x24},
    {0x5186, 0x09},
    {0x5187, 0x09},
    {0x5188, 0x09},
    {0x5189, 0x75},
    {0x518A, 0x54},
    {0x518B, 0xE0},
    {0x518C, 0xB2},
    {0x518D, 0x42},
    {0x518E, 0x3D},
    {0x518F, 0x56},
    {0x5190, 0x46},
    {0x5191, 0xF8},
    {0x5192, 0x04},
    {0x5193, 0x70},
    {0x5194, 0xF0},
    {0x5195, 0xF0},
    {0x5196, 0x03},
    {0x5197, 0x01},
    {0x5198, 0x04},
    {0x5199, 0x12},
    {0x519A, 0x04},
    {0x519B, 0x00},
    {0x519C, 0x06},
    {0x519D, 0x82},
    {0x519E, 0x38},
    {0x5381, 0x1E},  // 色彩矩阵配置
    {0x5382, 0x5B},
    {0x5383, 0x08},
    {0x5384, 0x0A},
    {0x5385, 0x7E},
    {0x5386, 0x88},
    {0x5387, 0x7C},
    {0x5388, 0x6C},
    {0x5389, 0x10},
    {0x538A, 0x01},
    {0x538B, 0x98},
    {0x5300, 0x08},  // 降噪配置
    {0x5301, 0x30},
    {0x5302, 0x10},
    {0x5303, 0x00},
    {0x5304, 0x08},
    {0x5305, 0x30},
    {0x5306, 0x08},
    {0x5307, 0x16},
    {0x5309, 0x08},
    {0x530A, 0x30},
    {0x530B, 0x04},
    {0x530C, 0x06},
    {0x3008, 0x02},  // 启动输出
};

这段代码看着长,其实逻辑很简单:就是往寄存器里写一堆值。但每个值什么意思,得对着datasheet看。我刚开始做驱动时,最头疼的就是datasheet里那些“Reserved”位——写错了传感器就不干活。

避坑指南:

我曾经因为I2C速率没配好,导致传感器初始化失败。传感器对I2C时序有要求,一般不超过400kHz。有些传感器还要求SCL高电平时间大于某个值。如果初始化失败,先查I2C波形,别急着怀疑寄存器写错了。

3.3 模组标定简介

传感器本身有差异,镜头有差异,组装也有差异。所以每个模组出厂前,都得标定。

标定做什么?说白了,就是测量模组的各种“缺陷”,然后算出补偿参数。这些参数会烧录到模组的OTP(一次性可编程)存储器里,或者存在系统端的校准文件中。

常见的标定项目:

标定项目 测量内容 补偿方式
暗电流标定 无光照时的像素输出 减去暗电流值
镜头阴影标定 四角亮度衰减 LSC增益补偿
坏点标定 死点、亮点、热噪点 坏点替换/插值
白平衡标定 R/G/B通道增益比 AWB增益矩阵
色彩标定 色彩还原准确性 CCM色彩校正矩阵

标定流程一般是这样的:

  1. 搭建标定环境(积分球、标准光源、色卡)
  2. 采集多帧RAW图
  3. 计算各像素的响应特性
  4. 生成补偿参数
  5. 验证标定效果

我印象最深的一次,是某个项目在量产时发现,同一批模组的暗电流差异很大。查来查去,发现是模组厂在组装时,传感器和镜头的间距有微小偏差,导致进光量不一致。后来在标定流程里加了一个“暗电流归一化”步骤,问题才解决。

小技巧:

标定环境很重要。积分球的均匀性、光源的色温稳定性、暗室的漏光情况,都会影响标定精度。我建议标定前先测一下环境,确保光源色温偏差在±50K以内,照度均匀性在95%以上。

下面这张图,展示了传感器到ISP的完整数据链路:

CMOS传感器到ISP数据链路 CMOS传感器 → ISP 数据链路 镜头 像素阵列 光电转换 模拟处理 CDS + PGA ADC 模数转换 ISP RAW图处理 Sensor驱动 I2C配置 关键说明: 1. 镜头将光线聚焦到像素阵列,每个像素完成光电转换 2. 模拟处理阶段进行相关双采样(CDS)和可编程增益放大(PGA) 3. ADC将模拟电压转换为数字码值,输出RAW图 4. Sensor驱动通过I2C配置传感器的工作模式

这张图把整个链路串起来了。你想想看,从光子打到像素上,到ISP拿到RAW图,中间经历了多少环节?每个环节都可能引入噪声和失真。标定,就是把这些“不完美”给量化出来,然后补偿掉。