libcamera 架構、unicam、DT overlay
| 元件 | 職責 | RPi 實例 |
|---|---|---|
| PipelineHandler | 把感測器+ISP 串成一個 Camera | src/libcamera/pipeline/rpi/pisp/ |
| Camera | 暴露給應用的相機實體 | "/base/soc/.../i2c.../ov5647@36" |
| Controls | 標準化控制介面 | ExposureTime / AnalogueGain / AeEnable |
| IPA | AE/AWB 演算法 + 產生 ISP 參數 | src/ipa/rpi/pisp/ |
| Request / Stream | 單幀處理與輸出流 | — |
你操作高階控制;libcamera 做「控制 → register」的轉換。理解這層抽象,tuning 檔才看得懂(單元 14)。
ls /dev/video* /dev/media* media-ctl -p -d /dev/media0 | head -30
compatible = "ovti,ov5647"; # 匹配 of_device_id → 載入驅動 reg = <0x36>; # probe 用 I2C 位址 clocks = <&cam0_clk>; # XCLK 來源(pixel clock) reset-gpios = <...>; # RESET(CAM_GPIO) pwdn-gpios = <...>; # PWDN(如有) port { csi-lane = <2>; } # MIPI lane 數
| 欄位 | 驅動用途 |
|---|---|
| compatible | 與 of_device_id 匹配 → probe |
| reg | probe 時 i2c_new_client_device 使用的位址 |
| clocks | 供給 XCLK |
| reset-gpios | probe 時先 reset(時序) |
sudo dtoverlay -a | grep ov56 dmesg | grep -i -E "ov5647|unicam"
rpicam-hello --list-cameras
# 預期:ov5647,含 modes(2592x1944 10-bit …)libcamera 對感測器驅動有一套「標準控制介面」,ov5647.c 實作:
| libcamera 控制 | 驅動如何滿足 |
|---|---|
| ExposureTime | 寫 0x3500–0x3503(依行數換算) |
| AnalogueGain | 寫 0x350A–0x350B(查 gain map) |
| ColourGains | 寫 AWB gains register |
| VBlank/HBlank | 寫 timing register(影響幀率) |
compatible 寫錯一個字 → 驅動不 probe。這是「list-cameras 空」的常見根因。
dmesg | grep -i ov5647,找 probe 結果。rpicam-hello --list-cameras,記錄輸出的 modes。i2cdetect 結果對照。場景:你換了 OV5647 的 init table,但預覽畫面出現異常的綠色條紋。需要確認是 media 管線格式不一致還是 ISP 參數問題。
# 1. 完整列出所有 entity 與 pad format media-ctl -p -d /dev/media0 # 輸出節錄: # - entity 3: ov5647 0-0036 (1 pad, 1 link) # pad0: Source [fmt:SGBRG10_1X10/2592x1944] # - entity 6: unicam (2 pads, 1 link) # pad0: Sink [fmt:SGBRG10_1X10/2592x1944] # 2. 檢查 ISP pipeline handler 的格式轉換 media-ctl -p -d /dev/media0 | grep -A5 "rpi" # 3. 若格式不一致,手動設定(不建議但除錯用) # media-ctl -d /dev/media0 \ # --set-v4l2 "ov5647 0-0036:0[fmt:SGBRG10_1X10/2592x1944]" # 4. 用 v4l2-ctl 確認 streaming 格式 v4l2-ctl -d /dev/video0 --list-formats-ext
libcamera 的 pipeline handler(RPi 的 PipelineHandlerPiSP)在 probe 時自動建立 media graph,但它的格式推導邏輯比你想的複雜:
port { csi-lane = <2>; } 若寫成 csi-lane = <4>,驅動照樣 probe 成功(因為 lane 數是在 MIPI 層檢查的),但 streaming 時 unicam 會因 lane 數不匹配而靜默失敗——dmesg 可能不會出現明顯錯誤,只會「沒有畫面」。| 症狀 | 可能原因 | 解決方案 |
|---|---|---|
| media-ctl 顯示 format mismatch | 感測器 init table 的 format 宣告與 DT overlay 不一致 | 對照 ov5647.c 的 init table 與 DT overlay 的 port/csi-lane 宣告 |
| rpicam-hello --list-cameras 能看到但預覽黑畫面 | pipeline probe 成功但 ISP 管線未正確連接 | media-ctl -p 確認 entity 間的 link 是否建立;檢查 dmesg 的 pipeline 訊息 |
| 改了 DT overlay 後 dmesg 沒有新訊息 | overlay 修改後未 reboot(DT 在開機時載入) | sudo reboot;確認 /boot/firmware/config.txt 的 dtoverlay 行正確 |
| libcamera 已看到相機但 picamera2.set_controls 無效 | 控制未傳到驅動層(control ID 不匹配或未 implement) | 用 rpicam-still --info 確認控制是否生效;檢查 ov5647.c 是否 implement 該 control |
| streaming 幀率遠低於預期 | ISP 管線格式轉換耗時、或 DMA buffer 不足 | media-ctl 檢查管線複雜度;增大 CMA 預算(cma=256M) |
media-ctl -p 畫出從感測器到 ISP 輸出的完整 entity 連結圖(用 ASCII 或文字描述),標出每個 link 的格式與方向(source→sink)。場景:RPi5 的 Camera 1 要接一顆客製板上的 OV5647。官方 overlay 只覆蓋 Camera 0,你必須為 Camera 1 寫一份自訂 overlay,並驗證到 libcamera 看到兩顆相機。本專案整合單元 1(腳位)、3(I2C)、4(overlay/驅動)、6(bring-up)知識。
// ov5647-cam1.dts(概念,欄位意義對應單元 4.4) /dts-v1/; /plugin/; &i2c_csi_dsi1 { # Camera 1 的 I2C(i2c-10) compatible = "ovti,ov5647"; # 匹配 ov5647.c reg = <0x36>; # I2C 位址 clocks = <&cam1_clk>; # XCLK reset-gpios = <...>; # CAM_GPIO 1 pwdn-gpios = <...>; port { endpoint { data-lanes = <1 2>; }; }; # 2-lane };
# 1. 編譯 dts → dtbo(樹莓派工具鏈) dtc -@ -I dts -O dtb -o ov5647-cam1.dtbo ov5647-cam1.dts sudo cp ov5647-cam1.dtbo /boot/firmware/overlays/ # 2. 加入 config.txt 並重啟 echo "dtoverlay=ov5647-cam1" | sudo tee -a /boot/firmware/config.txt sudo reboot # 3. 驗證 probe(預期出現兩顆) dmesg | grep -i ov5647 sudo i2cdetect -y 10 | grep 36 # Camera 1 的 bus rpicam-hello --list-cameras # 預期:0 : ov5647 1 : ov5647 # 4. 驗證 media graph 兩條管線 media-ctl -p -d /dev/media0 | grep -E "entity|ov5647|unicam"
dmesg | grep -i ov5647 確認兩顆都 probe(含 Chip ID)。sudo i2cdetect -y 10(Camera 1)與 -y 22(Camera 0)確認各自 0x36。rpicam-hello --list-cameras 確認兩顆 camera 索引。media-ctl -p -d /dev/media0(與 media1)比對感測器 pad 格式與 unicam sink 格式一致。| 面向 | RPi5 | Orange Pi | Orin Nano | Thor |
|---|---|---|---|---|
| overlay 機制 | config.txt + dtbo(簡單) | overlays/ + 手改 dtb | dtb + kernel patch | dtb + Holoscan 描述 |
| 驅動來源 | mainline(ov5647.c 等) | 廠商 BSP | NVIDIA 維護 | NVIDIA 維護 |
| 自訂感測器難度 | 中(文件齊全) | 高(文件少) | 高(需 NDA/簽約) | 高(生態新) |
| 排錯工具 | dmesg + media-ctl | dmesg(陽春) | tegra 專用 tool | Holoscan CLI |
| 步驟 | 操作 | 位元級說明 |
|---|---|---|
| 1. 列舉 subdev | v4l2-ctl -d /dev/v4l-subdev0 --list-subdevs | 確認 sensor subdev 存在 |
| 2. 讀取曝光控制 | v4l2-ctl -d /dev/v4l-subdev0 -C exposure | 返回當前曝光值(行數) |
| 3. 設定手動曝光 | v4l2-ctl -d /dev/v4l-subdev0 -c exposure=100,exposure_auto=0 | exposure_auto=0 解除 AE,exposure=100 行 |
| 4. 驗證 | v4l2-ctl -d /dev/v4l-subdev0 -C exposure | 回讀確認值 = 100 |
決策樹 A:libcamera 與 V4L2 工具衝突
工具衝突
├─ 檢查 A:cam -d /dev/media0 是否佔用 pipeline
│ ├─ 是 → 關閉 cam 後再用 v4l2-ctl
│ └─ 否 → 繼續
├─ 檢查 B:rpicam-hello 是否在背景執行
│ ├─ 是 → kill 後重試
│ └─ 否 → 繼續
└─ 檢查 C:是否有其他 process 打開 /dev/video*
├─ 是 → lsof /dev/video* 找出並終止
└─ 否 → driver 問題,檢查 media topology
| 面向 | RPi5 | Orange Pi | Orin Nano | Thor | 推薦 |
|---|---|---|---|---|---|
| 主要框架 | libcamera + V4L2 | V4L2 直接 | Argus + V4L2 | Argus + Holoscan | 各有生態 |
| 開源程度 | ★★★★★ | ★★★ | ★★★ | ★★ | RPi5 最開源 |
| 驅動品質 | mainline clean | BSP 補丁多 | NVIDIA maintained | NVIDIA maintained | RPi5 最乾淨 |
| API 學習曲線 | 中等 | 低 | 高 | 很高 | Orange Pi 最低 |
| 社群資源 | ★★★★★ | ★★ | ★★★★ | ★★ | RPi5 社群最豐富 |
media-ctl -d /dev/media0 -p 查看 pipeline topology