Pipeline调度基础:帧同步与帧间隔、VBlank与HBlank、逐行与逐帧、调度器职责
各位同学,今天我们进入Pipeline调度的核心地带。说实话,这部分内容我当年刚接触时也绕了不少弯路。你想想看,一个ISP Pipeline里同时跑着几十个模块,每个模块处理速度还不一样,怎么让它们步调一致?这就是调度要解决的问题。
我个人习惯把调度比作交响乐指挥。每个乐器(模块)都有自己的节奏,指挥(调度器)得让它们在同一首曲子里合拍。ISP里这个“拍子”就是帧同步信号。
帧同步与帧间隔
帧同步,说白了就是告诉所有模块:“新的一帧来了,准备干活!”
在传感器端,帧同步通常由VSYNC(垂直同步)信号触发。VSYNC拉高时,表示新一帧图像数据开始传输。我见过不少新手工程师,以为帧同步就是简单的“开始”信号,其实它背后还带着帧间隔的概念。
帧间隔(Frame Interval):相邻两帧VSYNC脉冲之间的时间差。典型值:
- 30fps → 帧间隔 ≈ 33.3ms
- 60fps → 帧间隔 ≈ 16.67ms
- 120fps → 帧间隔 ≈ 8.33ms
帧间隔决定了Pipeline的“时间预算”。你所有模块的处理时间加起来,必须小于这个预算。否则就会丢帧——我在一个1080p@60fps的项目里就踩过这个坑,当时RAW域处理模块慢了2ms,结果每3秒就跳一帧,画面肉眼可见地卡顿。
VBlank与HBlank:被忽视的“喘息时间”
这两个概念,很多做上层应用的人不太在意,但做底层Pipeline调度的人必须吃透。
VBlank(垂直消隐期):一帧结束到下一帧开始之间的时间窗口。传感器在这段时间里不输出有效像素数据,只输出消隐信号。
HBlank(水平消隐期):一行结束到下一行开始之间的时间窗口。同样,这段时间不输出有效像素。
为什么要关注这两个“空白期”?因为它们是调度器的黄金时间!
| 消隐期类型 | 典型时长 | 调度用途 |
|---|---|---|
| VBlank | 几百μs ~ 几ms | 帧级配置切换、统计更新、DMA搬运 |
| HBlank | 几μs ~ 几十μs | 行级参数更新、小批量数据搬运 |
我的经验:我曾经在一个4K@60fps的项目里,利用VBlank窗口做3A统计数据的DMA搬运。如果不卡这个窗口,数据搬运会抢占行处理时间,导致HBlank不够用,最终出现行撕裂。记住:VBlank是“大块时间”,HBlank是“碎片时间”,调度策略完全不同。
逐行处理 vs 逐帧处理
这是Pipeline调度里最容易混淆的概念。我直接画个图帮你理清。
逐行处理的好处是延迟低。你想想看,传感器扫完第一行,你就能开始处理了,不用等整帧读完。但坏处是行与行之间有依赖关系——比如去噪模块需要参考相邻行,这时候逐行处理就有点麻烦。
逐帧处理正好相反。延迟高,但数据完整。3A统计(自动曝光、自动白平衡、自动对焦)必须基于整帧数据,所以只能用逐帧方式。
避坑指南:我曾经在一个项目里,把去马赛克(Demosaic)模块设计成逐帧处理,结果延迟从2行飙升到1080行(一帧)。后来改成逐行+行缓存的方式,延迟降到3行。记住:能用逐行就别用逐帧,除非你确实需要整帧信息。
调度器的基本职责
调度器不是简单的“谁先来谁先走”。它的职责可以归纳为四点:
- 时序对齐:确保所有模块在正确的帧/行边界开始工作。比如,BLC模块必须在RAW域第一行数据到达前完成配置。
- 资源仲裁:多个模块争用DMA带宽、行缓存、Line Buffer时,调度器决定谁先用。我见过一个案例,两个模块同时写同一块DDR区域,数据全乱了。
- 延迟预算管理:每个模块分配多少处理时间,调度器要心里有数。超时的模块要么降质,要么跳过。
- 异常处理:某个模块卡住了怎么办?调度器要能超时复位,或者走旁路。
| 职责 | 典型实现 | 常见问题 |
|---|---|---|
| 时序对齐 | VSYNC/HSYNC计数器 | 计数器溢出导致错位 |
| 资源仲裁 | 轮询/优先级仲裁器 | 低优先级模块饿死 |
| 延迟预算管理 | 看门狗定时器 | 预算设置过紧导致频繁超时 |
| 异常处理 | 超时复位 + 旁路模式 | 复位后状态未完全恢复 |
我的建议:设计调度器时,先画一张“时间轴图”。把VSYNC、HSYNC、每个模块的启动/结束时间都标出来。这张图画清楚了,调度逻辑基本就定了。我每个项目都这么干,从没出过大问题。
嗯,这一节的内容就到这里。帧同步和帧间隔是Pipeline的“心跳”,VBlank和HBlank是“喘息窗口”,逐行和逐帧是两种基本处理模式,调度器就是那个让一切有序运转的“大脑”。把这些基础打牢,后面讲具体调度策略时你会轻松很多。