4. 驱动初始化流程:上电时序控制、PLL配置、分辨率切换、Stream on/off流程实战

驱动初始化,说白了就是让 sensor 从「沉睡」到「干活」的过程。很多刚入行的朋友觉得这步简单,不就是写几个寄存器嘛?其实不然。我见过太多因为上电时序不对导致 sensor 烧坏的案例,也遇到过 PLL 配置差一个 bit 画面全是条纹的尴尬。

这一章,我们就把整个初始化流程拆开揉碎,从硬件时序到软件配置,一步步走通。

4.1 上电时序控制:sensor 的「生命线」

每个 sensor 都有自己严格的上电时序要求。你想想看,sensor 内部有模拟电路、数字电路、像素阵列,它们需要按照特定顺序「醒来」。搞反了或者时间不够,轻则 sensor 不工作,重则直接烧毁。

⚠️ 我曾经犯过的错: 有一次调试 OV5640,为了赶进度,我把 AVDD 和 DVDD 同时上电,结果 sensor 输出全是雪花点。查了两天 datasheet 才发现,AVDD 必须比 DVDD 早 5ms 稳定。从那以后,我再也不敢跳过时序检查。

典型的 sensor 上电时序包含以下阶段:

阶段 信号 典型时序要求 说明
1 AVDD (模拟电源) 先于 DVDD 2-10ms 模拟电路先稳定
2 DVDD (数字电源) AVDD 稳定后 数字逻辑上电
3 IOVDD (IO 电源) 与 DVDD 同时或稍后 通信接口供电
4 MCLK (主时钟) 电源稳定后 1-5ms 提供工作时钟
5 RESET (复位) 时钟稳定后 1ms 释放复位信号

嗯,这里要注意:不同 sensor 的时序参数差异很大。有的 sensor 要求 AVDD 和 DVDD 之间延迟 10ms,有的只需要 1ms。一定要以 datasheet 为准。

4.2 PLL 配置:让 sensor 跑在正确的节奏上

PLL 配置是初始化中最容易出错的环节。我个人的习惯是:先算后配,配完再验。

PLL 的核心公式其实很简单:

VCO = MCLK × PLL_M / PLL_N
PIX_CLK = VCO / PLL_P / PLL_DIV

但实际配置时,有几个坑需要避开:

  • VCO 频率范围:每个 sensor 的 VCO 都有允许范围,比如 400MHz-800MHz。超出范围,PLL 无法锁定。
  • PLL_M 和 PLL_N 的互质关系:有些 sensor 要求这两个值互质,否则会产生 jitter。
  • PLL_P 的分频选择:通常有 1、2、4、8 等选项,需要根据目标像素时钟选择。
💡 我的调试技巧: 配置完 PLL 后,先读回 PLL_LOCK 寄存器。如果没锁定,不要急着改其他参数,先检查 VCO 频率是否在范围内。我遇到过好几次,都是因为 MCLK 频率不准导致 PLL 无法锁定。

4.3 分辨率切换:从 1080p 到 4K 的「变形」

分辨率切换,本质上是重新配置 sensor 的读出窗口和时序。我把它分为三步:

  1. 停止输出:先发 Stream off 命令,让 sensor 停止输出数据。
  2. 修改寄存器:配置新的分辨率参数,包括窗口起始、窗口大小、行长度、帧长度等。
  3. 重新启动:发 Stream on 命令,等待 sensor 输出新分辨率的图像。

这里有个容易忽略的点:切换分辨率时,PLL 是否需要重新配置?

我的经验是:如果目标分辨率的像素时钟与当前一致,可以只改窗口参数。但如果帧率变化较大,建议重新配置 PLL,确保像素时钟在合理范围内。

📌 关键参数对照表:
分辨率 窗口起始 (X, Y) 窗口大小 (W, H) 行长度 (HTS) 帧长度 (VTS)
1920x1080 (0, 0) (1920, 1080) 2200 1125
3840x2160 (0, 0) (3840, 2160) 4400 2250
640x480 (16, 12) (640, 480) 800 525

4.4 Stream on/off 流程:sensor 的「开关」

Stream on/off 是 sensor 驱动中最常用的操作。看似简单,但顺序错了就会出问题。

标准的 Stream on 流程:

1. 检查 sensor 状态(是否已初始化)
2. 配置输出格式(RAW、YUV、JPEG 等)
3. 配置输出分辨率
4. 配置帧率(通过调整 VTS 或 PLL)
5. 写入 Stream on 寄存器(通常为 0x0100 = 0x01)
6. 等待 VSYNC 信号(确认 sensor 开始输出)
7. 读取第一帧数据(丢弃或校验)

标准的 Stream off 流程:

1. 停止 DMA 传输(防止数据丢失)
2. 写入 Stream off 寄存器(0x0100 = 0x00)
3. 等待 sensor 进入 standby 状态
4. 关闭时钟(可选,用于省电)
⚠️ 注意: Stream off 后不要立即重新 Stream on。有些 sensor 需要等待 10-20 帧的时间才能完全稳定。我习惯在 Stream off 后加一个 100ms 的延时,确保 sensor 内部状态完全复位。

4.5 完整初始化流程图

下面这张图,是我在实际项目中总结的 sensor 初始化流程。你可以把它当作 checklist 来用。

Sensor 驱动初始化流程图 Sensor 驱动初始化完整流程 1. 上电时序控制 2. 释放 RESET 3. 初始化 I2C 通信 4. 读取 Sensor ID 5. PLL 配置 6. 分辨率配置 7. Stream On 8. 等待 VSYNC 9. 开始采集图像 📌 关键检查点 • 上电时序:AVDD → DVDD → IOVDD • PLL 锁定:检查 LOCK 寄存器 • Stream on:等待 3-5 帧稳定 • 分辨率切换:先 off 再 on ⚠️ 常见问题 • ID 读不到:检查 I2C 地址 • 无 VSYNC:检查时钟和 PLL • 图像异常:检查分辨率配置

4.6 实战代码片段

最后,分享一段我实际项目中用的初始化代码框架。你可以直接拿来改。

int sensor_init(sensor_t *sensor) {
    // 1. 上电时序
    sensor_power_on(sensor);
    mdelay(10);  // 等待电源稳定
    
    // 2. 释放复位
    gpio_set_value(sensor->reset_pin, 1);
    mdelay(5);
    
    // 3. 初始化 I2C
    i2c_init(sensor->i2c_bus);
    
    // 4. 读取 Sensor ID
    uint16_t id = sensor_read_reg(sensor, 0x0000);
    if (id != sensor->expected_id) {
        printf("Error: Sensor ID mismatch\n");
        return -1;
    }
    
    // 5. 配置 PLL
    sensor_pll_config(sensor, sensor->mclk_hz, sensor->target_fps);
    
    // 6. 配置分辨率
    sensor_resolution_config(sensor, sensor->width, sensor->height);
    
    // 7. Stream on
    sensor_write_reg(sensor, 0x0100, 0x01);
    mdelay(100);  // 等待 sensor 稳定
    
    // 8. 等待 VSYNC
    int ret = wait_for_vsync(sensor, 1000);
    if (ret < 0) {
        printf("Error: No VSYNC detected\n");
        return -1;
    }
    
    return 0;
}
💡 我的习惯: 每次初始化成功后,我都会把关键寄存器的值读回来打印出来。这样一旦出问题,可以快速定位是配置没写进去,还是 sensor 本身有问题。这个习惯帮我省了不少调试时间。

好了,这一章的内容就到这里。初始化流程看似繁琐,但只要你按照流程一步步来,把每个环节的时序和参数都确认清楚,就不会出大问题。记住:sensor 驱动没有捷径,只有细心和耐心。