012、Sensor 工作模式切换:Full Size、Binning、Skipping、Crop 模式的寄存器配置
一、从一次“黑屏”调试说起
去年做一款50M主摄项目,客户要求预览时用12.5M(四合一Binning),拍照切回50M Full Size。逻辑上很简单:预览切Binning省带宽,拍照切Full Size保细节。结果一跑,预览正常,一按快门——黑屏。ISP报“frame length mismatch”,Sensor输出尺寸和预期对不上。
查了两天,最后发现是Binning切回Full Size时,忘了把horizontal/vertical binning factor寄存器复位。Sensor内部还在做2x2合并,但输出尺寸寄存器已经改成了50M的宽高,导致每帧数据量不对,ISP直接罢工。
这个坑让我意识到:Sensor模式切换不是简单的“改几个寄存器值”,而是一套完整的时序、带宽、增益、黑电平校准的联动操作。今天就把这块硬骨头啃透。
二、四种模式的核心差异
先明确概念,别被厂商文档绕晕。
Full Size:Sensor所有像素全部读出,分辨率最大,帧率最低。比如IMX586的48M全尺寸,10bit下通常只有15fps左右。
Binning:相邻像素合并读出,常见2x2或3x3。好处是信噪比提升(相当于像素面积变大),输出分辨率降低,帧率可以翻倍。注意:Binning分模拟合并和数字合并,前者在读出前完成,噪声更低;后者在ADC之后做,灵活性高但噪声略大。
Skipping:跳行跳列读出,不合并。比如每2行取1行、每2列取1列,分辨率降为1/4。缺点是容易产生摩尔纹和锯齿,因为空间采样不均匀。现在主流Sensor基本用Binning替代Skipping,但低端Sensor或特殊场景(如高速连拍)还会见到。
Crop:只读出感光区域的一部分,相当于数字变焦的硬件基础。比如从全尺寸中心截取1920x1080区域。Crop不改变像素合并方式,只改变读出窗口起始位置和大小。
三、寄存器配置的“骨架”
不同厂商(Sony、Samsung、OmniVision)寄存器地址不同,但逻辑框架一致。以Sony IMX系列为例,核心寄存器组包括:
// 模式选择寄存器(0x0100) // 0x00 = 软件待机,0x01 = 流模式 // 注意:改模式前必须先进入待机,否则寄存器写入无效 reg_write(0x0100, 0x00); // 先停流,这里踩过坑,不停直接写会卡死 // 输出尺寸寄存器 reg_write(0x0340, height); // 垂直总行数(含消隐) reg_write(0x0341, height >> 8); reg_write(0x0342, width); // 水平总像素(含消隐) reg_write(0x0343, width >> 8); // 有效输出尺寸 reg_write(0x0344, x_start); // 水平起始 reg_write(0x0345, x_start >> 8); reg_write(0x0346, y_start); // 垂直起始 reg_write(0x0347, y_start >> 8); reg_write(0x0348, x_end); // 水平结束 reg_write(0x0349, x_end >> 8); reg_write(0x034A, y_end); // 垂直结束 reg_write(0x034B, y_end >> 8); // Binning/Skipping控制(0x0380 ~ 0x0387) reg_write(0x0380, bin_h_factor); // 水平binning系数,0x11表示2x2 reg_write(0x0381, bin_h_factor >> 8); reg_write(0x0382, bin_v_factor); // 垂直binning系数 reg_write(0x0383, bin_v_factor >> 8); reg_write(0x0384, skip_h_factor); // 水平skip系数,0x11表示2x2 reg_write(0x0385, skip_h_factor >> 8); reg_write(0x0386, skip_v_factor); reg_write(0x0387, skip_v_factor >> 8);关键点:Binning和Skipping不能同时使能,但有些Sensor允许混合模式(比如水平Binning+垂直Skipping),看具体型号手册。
四、Binning模式配置实战
以2x2 Binning为例,输出分辨率减半,但帧率翻倍。配置时要注意:
- Binning系数:通常0x11表示2x2,0x12表示3x3(但3x3不常见,因为奇数合并会导致像素中心偏移)
- 输出尺寸:必须和Binning后的分辨率匹配。比如全尺寸4000x3000,2x2 Binning后输出2000x1500,但有些Sensor要求输出尺寸写全尺寸,内部自动处理——别自己算错
- 增益补偿:Binning后信号强度翻倍(4个像素合并成1个),模拟增益需要相应降低,否则过曝
// 配置2x2 Binning模式(IMX586示例) // 先进入待机 reg_write(0x0100, 0x00); mdelay(10); // 别这样写:直接写0x01,Sensor没准备好就崩 // 设置binning系数 reg_write(0x0380, 0x11); // 水平2x2 reg_write(0x0382, 0x11); // 垂直2x2 // 设置输出尺寸(Binning后) reg_write(0x0340, 1500); // 垂直有效行 reg_write(0x0342, 2000); // 水平有效像素 // 调整增益(经验值:降低6dB) reg_write(0x0204, 0x00); // 模拟增益寄存器高位 reg_write(0x0205, 0x80); // 1x增益(原2x2 Binning前是2x,这里踩过坑) // 切回流模式 reg_write(0x0100, 0x01);这里有个隐藏问题:Binning后黑电平(OB)会变化。因为合并像素的暗电流叠加,OB值需要重新校准。有些Sensor会自动调整,但多数需要手动写OB寄存器。我遇到过切Binning后画面偏绿,就是OB没更新导致的。
五、Skipping模式配置陷阱
Skipping现在用得少,但做高速场景(如720p 240fps)时还会碰到。配置和Binning类似,但寄存器不同:
// 2x2 Skipping配置 reg_write(0x0384, 0x11); // 水平skip 2x reg_write(0x0386, 0x11); // 垂直skip 2x // 注意:Skipping时binning系数必须设为0x11(1x1,即不合并) reg_write(0x0380, 0x11); reg_write(0x0382, 0x11);Skipping最大的坑是相位对齐。因为跳行跳列,像素的Bayer模式会被破坏。比如RGGB排列,跳一行后变成GBRG,ISP的demosaic算法会出错。解决方案是:要么Sensor内部做Bayer重排(高端Sensor支持),要么ISP端根据Skipping模式重新映射Bayer顺序。别这样写:直接当全尺寸Bayer处理,画面会出彩色条纹。
六、Crop模式:窗口裁剪的细节
Crop常用于数字变焦或画中画。配置相对简单,但要注意边界对齐:
// 从全尺寸中心裁剪1920x1080 // 全尺寸4000x3000,中心起始坐标 x_start = (4000 - 1920) / 2; // 1040 y_start = (3000 - 1080) / 2; // 960 x_end = x_start + 1920 - 1; // 2959 y_end = y_start + 1080 - 1; // 2039 reg_write(0x0344, x_start); reg_write(0x0346, y_start); reg_write(0x0348, x_end); reg_write(0x034A, y_end);Crop模式下,输出尺寸寄存器(0x0340/0x0342)必须和裁剪后的尺寸一致,否则ISP会报错。另外,Crop区域的起始坐标必须是偶数(Bayer排列要求),奇数坐标会导致颜色错乱。这里踩过坑:客户要求精确裁剪到1921x1081,我说不行,必须偶数对齐,最后妥协成1920x1080。
七、模式切换的时序控制
这是最容易被忽略的部分。Sensor从一种模式切到另一种,不是瞬间完成的。典型流程:
- 停流:写0x0100=0x00,等待VSYNC信号停止(至少等2帧时间)
- 写寄存器:所有模式相关寄存器一次性写入,不要分多次写(有些Sensor支持组写入,用0x0104寄存器控制)
- 等待稳定:切回流模式后,等待至少1帧的消隐期,再开始取图
- 重新校准:Binning/Crop切换后,黑电平、增益、白平衡参数可能失效,需要重新做3A
// 模式切换完整流程(伪代码) void switch_mode(int mode) { // 1. 停流 reg_write(0x0100, 0x00); wait_for_vsync(2); // 等2帧,确保Sensor完全停止 // 2. 写模式寄存器 if (mode == FULL_SIZE) { set_full_size_regs(); } else if (mode == BINNING_2X2) { set_binning_2x2_regs(); } // 3. 切回流 reg_write(0x0100, 0x01); wait_for_vsync(1); // 等1帧,让输出稳定 // 4. 重新校准(重要!) isp_black_level_calibrate(); isp_awb_reset(); }有些Sensor支持“无缝切换”,即不停止流直接改寄存器,但仅限于同分辨率下的增益、曝光调整。模式切换(分辨率变化)必须停流,这是铁律。
八、实战经验总结
- 寄存器写入顺序:先改尺寸相关,再改Binning/Skipping,最后改增益。别倒着写,否则Sensor内部状态机可能乱掉
- 消隐时间调整:Binning后帧率翻倍,但MIPI带宽可能不够。需要适当增加HBLANK(水平消隐)来降低带宽,否则丢帧。公式:MIPI速率 = (width + HBLANK) * (height + VBLANK) * fps * bits_per_pixel。别算错单位
- Binning模式下的HDR:如果Sensor支持HDR(如DOL模式),Binning会破坏HDR的时序。有些Sensor在Binning下自动禁用HDR,有些不会——必须手动关
- 调试工具:用示波器抓MIPI的HSYNC和VSYNC,看帧间隔是否稳定。如果切模式后帧率跳变,大概率是消隐时间没配好
- 文档陷阱:厂商寄存器手册经常写“reserved”位,别乱写。但有些“reserved”其实是内部状态位,读出来可以判断模式是否切换成功。比如IMX586的0x0005寄存器,bit[3]表示Binning是否生效
最后说一句:模式切换的稳定性,取决于你停流后等了多久。别为了省那几毫秒,把整个系统搞崩。我见过最离谱的案例,切模式后等了0.5ms就取图,结果前两帧全是花屏——因为Sensor内部PLL还没锁定。老老实实等2帧,不丢人。