客製 OV 接入
支援多 CSI 的板卡(如 RK3588)可接多顆;用 media-ctl 建多條管線,每顆一個 video device。
dmesg 確認 ov5640 probe、讀到 ID。v4l2-ctl 取一幀,確認格式。□ 硬體:CSI lane / I2C / reset / clock □ DT overlay:compatible / reg / clocks / reset-gpios □ 驅動:現成 or 改 init table □ dmesg:probe 成功?讀到 ID? □ 出圖:能取到幀? □ RAW:Bayer order / 黑位 / 缺陷像素 □ 調校:黑位 → LSC → AWB/CCM → NR/Sharpen
多相機不是「多接一顆」那麼簡單——兩顆感測器可能共享同一組 MIPI lanes,靠 virtual channel(VC) 區分資料流。
| 接法 | 資料路徑 | Orange Pi 情境 |
|---|---|---|
| 每顆各自 lanes | 各自的 CSI receiver | RK3588 多組 receiver |
| 共享 lanes + VC | 同一 D-PHY 帶 VC 標籤 | 需要接收器支援多 VC |
| 時序多工 | 分時切換 | 不適合即時雙流 |
在 media graph 中,每顆感測器是獨立的 subdev entity,各自連到(可共享的)CSI 接收器。啟動時要對「每一條管線」分別設定格式與 link,並確認 video 節點一一對應。
# 確認 CSI lane / I2C bus / reset GPIO / XCLK
sudo i2cdetect -l
cat /sys/kernel/debug/gpio | grep -i reset# 假設 overlay 新增節點: # &i2c3 { ov5640: ov5640@3c { compatible="ovti,ov5640"; reg=<0x3c>; # clocks=<&clk_xclk>; clock-frequency=<24000000>; ... }; }; sudo dtoverlay overlay-name.dtbo sudo reboot
dmesg | grep -i -E "ov5640|csi|probe"
sudo i2cget -y 3 0x3c 0x300a # 應回 0x56media-ctl -d /dev/media0 -r media-ctl -d /dev/media0 -l "'ov5640 3-003c':0->'csi2':0[1]" v4l2-ctl -d /dev/video0 --set-fmt-video=width=1280,height=720,pixelformat=UYVY \ --stream-mmap=3 --stream-count=1 --stream-to=shot.yuv
# 蓋鏡頭拍黑幀定黑位;拍灰卡驗 Bayer order 與 LSC(回單元 2/8/12)
python3 - <<'EOF'
import numpy as np
raw = np.fromfile('dark.raw', dtype=np.uint16).reshape(720,1280)
print('OB =', np.median(raw[600:700,400:880]))
EOF| 節點 | 失敗 | 方向 |
|---|---|---|
| DT | overlay 沒載入/編譯錯 | dmesg 看 dtoverlay 錯誤、檢查 compatible/reg/clocks |
| Probe | probe failure | 回單元 6:電源/clock/reset/位址 |
| ID | 讀不到 0x5640 | 回單元 3 I2C 決策樹 |
| 出圖 | 無資料 | MIPI lane count/VC 設定、格式對齊 |
| RAW | Bayer/黑位錯 | 回單元 2/8 驗證 |
| 多相機 | 第二路沒資料 | 檢查 VC/共享資源頻寬(單元 11) |
clock-frequency 與實際 XCLK 不符——PLL 全錯;② reset GPIO 極性反;③ 兩顆感測器用相同 I2C 位址沒改——衝突;④ 一次改多個變數——保留官方模組當對照組,一次只換一個。場景:Orange Pi 5 Plus(RK3588)同時接 OV5640(RGB)與 OV9281(IR),設計即時切換管線。
v4l2-ctl --list-devices | grep -A3 "ov5640\|ov9281"
ls /dev/video0 /dev/video2 # 假設 0=OV5640, 2=OV9281gst-launch-1.0 \ v4l2src device=/dev/video0 name=rgb ! 'video/x-raw,width=1280,height=720' ! tee name=t \ v4l2src device=/dev/video2 name=ir ! 'video/x-raw,width=1280,height=720' ! t. \ t. ! queue ! valve drop-bytes=1 ! autovideosink
# 啟 OV5640 v4l2-ctl -d /dev/video0 --stream-mmap=3 --stream-count=10 # 停 OV5640,啟 OV9281 v4l2-ctl -d /dev/video2 --stream-mmap=3 --stream-count=10
OV9281 是單色 IR 感測器,但在 RK3588 上有一些與 OV5640 不同的 MIPI 設定:
| 項目 | OV5640 | OV9281 |
|---|---|---|
| MIPI lanes | 2 lanes | 1 lane(通常) |
| Clock 頻率 | 最高 160MHz | 最高 480MHz(但實際用較低) |
| 格式 | SRGGB10 / YUYV | Y8 / Y10(無 Bayer) |
| Frame rate 上限 | 30fps(1080p) | 120fps(720p) |
| DT 位址 | 0x3c | 0x60 |
容易忽略的邊界案例:OV9281 的 MIPI clock 可以跑很高(480MHz),但 RK3588 的 CSI receiver 在 1 lane 模式下可能有 clock 上限——如果你的 DT 設了 480MHz 但硬體只支援 360MHz,會出現 frame sync 失敗(偶發黑幀)而非直接失敗。這需要量測 MIPI clock 來確認。
| 症狀 | 可能原因 | 解決方案 |
|---|---|---|
| OV9281 取流偶發黑幀 | MIPI clock 超 CSI receiver 1-lane 上限 | 降低 DT 的 clock-frequency 到 360MHz 以下 |
| OV5640 + OV9281 同時 streaming 有 frame drop | DDR 頻寬不足 | 降低兩路解析度;確認 DDR DT 設定 |
| GStreamer tee 切換延遲 >3 frame | queue 緩衝造成 | 減少 queue 的 max-size-buffers |
| OV9281 出 Y8 格式但 RK3588 要求 SRGGB | format 設錯 | OV9281 是單色,應設 greyscale 格式(Y8) |
| 多感測器 I2C 衝突(同 bus 不同位址) | address strap 設定相同 | 改其中一顆的 SCCB_ID 腳(0x60 vs 0x3c) |
把單元 16(多感測器)與單元 1–6 串成完整多相機 bring-up 專案:在 RK3588 上同時 bring-up OV5640(RGB)與 OV9281(IR),建立兩條獨立管線並驗證同時取流。這是本課程的「畢業專案」。
sudo i2cdetect -l # 確認兩顆感測器分掛不同 bus:bus3=OV5640(0x3c),bus4=OV9281(0x60) sudo i2cget -y 3 0x3c 0x300a # 0x56 sudo i2cget -y 4 0x60 0x300a # 0x92
v4l2-ctl --list-devices
# 假設 /dev/video0=OV5640, /dev/video2=OV9281
media-ctl -p -d /dev/media0 | grep -E "ov5640|ov9281|csi"media-ctl -d /dev/media0 -r media-ctl -d /dev/media0 -l "'ov5640 3-003c':0->'csi2_a':0[1]" media-ctl -d /dev/media0 -V "'ov5640 3-003c':0[fmt:UYVY8_2X8/1280x720]" media-ctl -d /dev/media1 -l "'ov9281 4-0060':0->'csi2_b':0[1]" media-ctl -d /dev/media1 -V "'ov9281 4-0060':0[fmt:Y8_1X8/1280x720]"
v4l2-ctl -d /dev/video0 --stream-mmap=3 --stream-count=30 --stream-to=rgb.yuv &
v4l2-ctl -d /dev/video2 --stream-mmap=3 --stream-count=30 --stream-to=ir.yuv &
wait
ls -l rgb.yuv ir.yuv
# 兩檔大小符合各自格式理論值 = 兩路同時成功| 步驟 | 作法 | 通過判據 |
|---|---|---|
| 1. 硬體盤點 | i2cdetect + 讀 ID | 每顆感測器位址與 ID 正確 |
| 2. 節點對應 | v4l2-ctl --list-devices | 每顆感測器有獨立 video node |
| 3. 單路測試 | 逐路單獨取流 | 各路皆可獨立出圖 |
| 4. 同時測試 | 兩路並行取流 | 無 frame drop / 無資源衝突 |
| 5. 頻寬計算 | 算總 bitrate vs DDR/CSI 上限 | 未超過上限(單元 11) |
| 6. 長期穩定 | 同時跑 10 分鐘 | 0 掉幀、0 逾時 |
| 面向 | Orange Pi | RPi5 | Orin Nano | Thor |
|---|---|---|---|---|
| 多 CSI | RK3588 4× / H618 1× | 2× CSI(4-lane) | 多路 CSI | 多路 CSI |
| Virtual Channel | RK3588 支援 VC0-3 | 支援 | 支援 | 支援 |
| 同時取流 | 可行(RK3588) | 可行 | 可行 | 可行 |
| 工具 | media-ctl 逐路設定 | libcamera multi-camera | Argus 多 camera | Holoscan 多 stream |
| 頻寬瓶頸 | DDR 為主 | ISP/記憶體 | NVIDIA 強(多路 4K) | 最強(多路高解析) |
- [ ] 我能完成多相機 bring-up 專案並讓兩路同時取流。 - [ ] 我能列出每顆感測器的 bus、位址、video node 對應。 - [ ] 我會用「單路→並行→二分法」排查多相機問題。 - [ ] 我能計算兩路同時取流的總頻寬需求。 - [ ] 我能說明 virtual channel 與獨立 lanes 的差異。 - [ ] 我已驗證多路 10 分鐘長期穩定無掉幀。
多感測器與實作案例的「讀→改→寫→驗證」是進階應用的基礎:
| 步驟 | 操作 | 指令 | 預期值 |
|---|---|---|---|
| 1. 掃描所有 I2C | i2cdetect -y 3 | i2cdetect -y 3 | 兩顆感測器位址 |
| 2. 讀第一顆 ID | 0x300A + 0x300B | i2cget -y 3 0x3c 0x300a | 0x56 |
| 3. 讀第二顆 ID | 0x300A + 0x300B | i2cget -y 3 0x3c 0x300a(不同 bus) | 0x56 |
| 4. 建兩路 media link | media-ctl -l | media-ctl -l "...; ..." | 兩條 link active |
| 5. 設定兩路 format | media-ctl -V | media-ctl -V "...; ..." | 兩路格式正確 |
| 6. 同時取流 | v4l2-ctl | v4l2-ctl --stream-mmap=1 -d /dev/video0 & v4l2-ctl ... -d /dev/video1 | 兩路同時成功 |
決策樹 A:兩路同時取流失敗
兩路同時取流? ├─ 一路成功一路失敗 │ ├─ 失敗的那路 I2C 問題 → i2cdetect 確認 │ └─ CSI receiver 不足 → 檢查 DT lane 數 ├─ 兩路都失敗 │ ├─ DDR 頻寬不足 → 降低解析度 │ └─ ISP 處理量不足 → 嘗試不同組合 └─ 兩路成功但掉幀 └─ 用「先單路→再並行→二分法」找瓶頸
決策樹 B:客製 OV 接入四步
新感測器接入四步: ├─ 1. I2C 位址確認 → i2cdetect ├─ 2. DT overlay 建立 → i2c + sensor 節點 ├─ 3. 驅動 probe → dmesg 看 probe 結果 └─ 4. media graph 建立 → media-ctl -l -V
| 步驟 | 指令 | 預期輸出 | 判讀標準 |
|---|---|---|---|
| 1. 掃描 I2C | i2cdetect -y 3 | 兩顆感測器 | 位址不衝突 |
| 2. 讀兩顆 ID | i2cget -y 3 0x3c 0x300a | 0x56 + 0x56 | 兩顆都正常 |
| 3. 建兩路 link | media-ctl -l | 兩條 link active | 正確 pad |
| 4. 設定兩路 format | media-ctl -V | 兩路格式正確 | 依各感測器能力 |
| 5. 同時取流 | v4l2-ctl --stream-mmap=1 & v4l2-ctl ... | 兩路成功 | 無 timeout |
| 6. 長期穩定 | 10 分鐘測試 | 無掉幀 | 穩定 |
| 面向 | Orange Pi | RPi5 | Orin Nano | Thor | 推薦 |
|---|---|---|---|---|---|
| CSI 接收器 | 4× / 1× | 2× (4-lane) | 多路 CSI | 多路 CSI | 多相機→RK3588 |
| 同時取流 | 可行(RK3588) | 可行 | 可行 | 可行 | 多路→RK3588 |
| 工具 | media-ctl 逐路 | libcamera multi | Argus multi | Holoscan multi | 底層→media-ctl |
| 頻寬瓶頸 | DDR 為主 | ISP/記憶體 | 強(多路 4K) | 最強(多路) | 高解析→NVIDIA |
| 學習成本 | 中(完全手動) | 低(libcamera) | 低(封裝好) | 低(封裝好) | 學習→Orange Pi |
- [ ] 完成「多相機 bring-up」專案並讓兩路同時取流 - [ ] 列出每顆感測器的 bus、位址、video node 對應 - [ ] 用「單路→並行→二分法」排查多相機問題 - [ ] 計算兩路同時取流的總頻寬需求 - [ ] 說明 virtual channel 與獨立 lanes 的差異 - [ ] 驗證多路 10 分鐘長期穩定無掉幀 - [ ] 用客製 OV 四步接入新感測器 - [ ] 產出「multi-camera setup guide」 - [ ] 用二分法找頻寬瓶頸 - [ ] 產出「multi-camera stability report」