SG2002 双核摄像头流水线 — UVC + JPU + IVE CSC
C906B(StarryOS)+ C906L(裸机)· UVC 采集 → JPU 硬解 → IVE 硬件 CSC → 共享内存 → mmap 零拷贝 · 真机实测 60fps / 640×480 RGB888
1 · 性能总览
0.1 ms
IVE 硬件 CSC(640×480)
1000×
IVE 硬件 vs 软件 CSC 加速比
57.5 fps
大核用户态实测(mmap 读 RGB)
2 · 优化历程:帧率从 13 到 60
整个优化经历了多个阶段,每个阶段解决一个瓶颈。下图展示帧率随优化的演进:
帧率从 13.4 → 60.0,每个阶段解决一个瓶颈。IVE CSC 额外开销仅 0.1ms,几乎不影响帧率。
3 · 系统架构
大核 C906B(StarryOS, S-mode, 1GHz)
小核 C906L(裸机, M-mode, 25MHz)
硬件外设
共享 DRAM
数据流:摄像头 → USB → 小核(JPU+IVE) → 共享 DRAM → 大核 mmap。控制流:邮箱 + PLIC 双向中断。
4 · 帧处理时序(640×480, 60fps 强光)
5 · 各阶段耗时实测(rdtime, 25MHz)
| 阶段 | 耗时 | 说明 | 瓶颈 |
| ① USB 抓帧(cap) | 12.0 ms | ~70 次 isoch_in_uframe 轮询,每次 ~1.1 微帧 | USB 等时带宽 + 摄像头出帧速度 |
| ② JPU 解码(dec) | 1.0 ms | MJPEG → YUV422,poll ~0.9ms + 拷贝 ~0.1ms | JPU 硬件解码时间 |
| ③ IVE CSC(ive) | 0.1 ms | YUV422 → RGB888 planar,硬件加速 | IVE 硬件处理时间 |
| ④ notify + cache | ~0 ms | 写邮箱 32B + dcache_clean_range + mbox_set | — |
| 大核 ISR | ~0 ms | 清 int_st + 读 DRAM 邮箱 → latest_frame | — |
| 大核 mmap 读 | 0 ms | 零拷贝:用户态直接读共享 DRAM 映射 | — |
| 合计 | ~13.1 ms | 帧预算 16.7ms(60fps),余量 3.6ms | — |
5.1 · JPU 内部分解
| 子步骤 | 耗时 | 说明 |
| JPEG 拷入 stream_buf | ~600 µs | copy_to_phys + dcache_clean |
| JPU 硬件解码(poll) | ~930 µs | 真正的 JPEG 解码计算 |
| dcache clean | ~50 µs | stream_buf 写回 |
| 合计 | ~1.0 ms | — |
5.2 · IVE CSC 耗时对比
| 方案 | 640×480 | 320×240 | 加速比 |
| 小核软件 YUV→RGB | ~120 ms | ~30 ms | 1× |
| 大核软件 YUV→RGB | ~10 ms | ~2.5 ms | 12× |
| IVE 硬件 CSC | 0.1 ms | 0.37 ms | 1200× |
IVE 硬件在 640×480(307200 像素)上仅用 107µs,吞吐约 2.9 G 像素/秒。
6 · 内存布局(4MB 预留区)
布局无重叠:YUV(600KB) + JPU pool(256KB) + RGB(900KB) + 镜像(552KB) = 2.3MB,4MB 预留区够用。
预留区从 2MB 扩到 4MB:修改 DTB fast_image reg = <0x00 0x8fe00000 0x00 0x400000>。
7 · 通信机制
7.1 · 邮箱中断(小核→大核,PLIC source 101)
7.2 · 寄存器索引 = 接收方 CPU 号
这是最容易搞错的一点。CPU 编号:0=CA53, 1=C906B(大核), 2=C906L(小核)。发送方写的是接收方那一组寄存器。小核→大核 = cpu_mbox_en[1],大核→小核 = cpu_mbox_en[2]。
7.3 · Cache 一致性
| 一侧 | 映射方式 | 要求 |
| 小核 | cached identity (VA=PA) | 写共享数据后必须 dcache_clean_range() |
| 大核 | ax_mm::iomap non-cacheable | 直接 read_volatile 即可 |
| 大核用户态 | mmap /dev/cvi-yuv → non-cacheable | 零拷贝,直接读共享 DRAM |
8 · 优化前 vs 优化后对比
| 指标 | 优化前 | 优化后 | 改善 |
| 帧率 | 13.4 fps | 60.0 fps | 4.5× |
| JPU 超时恢复 | 230s 才触发,不自动复位 | 200ms 超时 + hard_reset_at | 1150× 快恢复 |
| 摄像头帧率 | 16.7 fps(AE priority=1) | 60.0 fps(AE priority=0) | 3.6× |
| 大核读 YUV/RGB | read_at 内核拷贝 75ms | mmap 零拷贝 0ms | ∞(消除拷贝) |
| YUV→RGB 转换 | 无(输出 YUV) | IVE 硬件 CSC 0.1ms | 硬件加速 |
| JPU 解码耗时 | 51 ms(含 34ms memcpy + 12ms cache) | 1.0 ms(直写共享区) | 51× |
| 撕裂风险 | 单缓冲 + seqlock(有洞) | —(单缓冲 + IVE 覆盖) | — |
| 预留区 | 2 MB | 4 MB | 2× |
| 输出格式 | YUV420 planar | RGB888 planar | 可直接显示 |
9 · 关键代码位置
| 文件 | 职责 |
| sg200x-bsp/src/ive.rs | IVE 硬件 CSC 驱动(YUV→RGB,寄存器级) |
| sg200x-bsp/src/jpu/decoder.rs | JPU 解码 + set_output_buffer + 按时间超时 + hard_reset_at |
| sg200x-bsp/src/jpu/regs.rs | hard_reset_at(assert→deassert 真复位) |
| sg200x-bsp/src/utils/time.rs | rdtime 超时判定(Deadline) |
| sg200x-bsp/src/usb/class/uvc.rs | UVC 协商 + ae_priority + 帧组装 + 采集统计 |
| sg200x-bsp/src/usb/host/dwc2/ep0.rs | DWC2 通道传输 + HCINTMSK + 中断/轮询混合 |
| bare-metal/src/main.rs | 主循环:抓帧→JPU→IVE→notify,分阶段计时 |
| bare-metal/src/yuv_buf.rs | 共享缓冲布局(YUV + RGB 地址/大小) |
| bare-metal/src/mailbox.rs | DRAM 邮箱 + dcache_clean + HW 邮箱中断 |
| bare-metal/src/trap.rs | M-mode trap + PLIC 61 邮箱 ISR |
| tgoskits/.../dev/cvi_yuv.rs | /dev/cvi-yuv: mmap + read_at 向后兼容 |
| tgoskits/.../dev/cvi_mailbox.rs | /dev/cvi-mailbox: ISR(new_arc) + 探针 |
| tgoskits/platforms/somehal/.../plic.rs | 大核 PLIC + 无锁诊断探针 |
10 · 已知限制与后续方向
当前限制
- 自动曝光限速:弱光下 AE priority=None 允许摄像头降帧率(16.7fps)。设
ae_priority=Some(0) 可强制 60fps 但画面变暗。
- 单缓冲:YUV 和 RGB 各一份,大核读 RGB 时小核可能正在写下一帧。当前靠帧周期余量(3.6ms)避免撕裂,但没有硬件级保证。恢复双缓冲需再扩预留区或缩小分辨率。
- USB 中断不完整:PLIC source 30 在 C906L 上触发率低(~67/100帧),
ch_wait_halted 走轮询兜底。CPU 仍 100% 占用。
- wfi 不可用:C906L 不能读 CLINT MMIO(总线防火墙),写 mtimecmp 成功但
mip.MTIP 不置位。定时器中断无法唤醒 wfi。
后续方向
- 流水线 + 双缓冲:抓帧线程 + 解码/CSC 线程分离,帧周期从
cap+dec+ive 降到 max(cap, dec+ive)。需要 wfi 或协作式调度。
- 大核 IVE CSC:把 IVE 操作移到大核(大核有完整外设访问),小核只输出 YUV,大核按需做 CSC。减轻小核负担。
- 大核软件 CSC:大核 1GHz,纯标量 640×480 YUV→RGB 约 10ms。如果不需要 IVE,大核 mmap YUV 后自行转换即可。
- DWC2 描述符 DMA(DDMA):解锁 mult>1 高带宽等时,支持 YUYV 640×480@30fps(免 JPU)。需修 mult>1 切包 bug。