CSI-2 位元層、libcamera 堆疊、感測器選擇
MIPI CSI-2(Camera Serial Interface 2)由 MIPI Alliance 制定,是嵌入式相機最普遍的介面。它分四層,每一層解決一類問題:
| 層 | 職責 | 關鍵概念 | 除錯焦點 |
|---|---|---|---|
| PHY(D-PHY) | 電氣:差分訊號、時脈、兩種模式 | HS / LP、1.2V 差動 | 示波器看波形、眼圖 |
| Lane 管理 | 多 lane 對齊、去歪斜 | lane 數、byte clock | lane 數設定是否一致 |
| Low Level Protocol | 封包化:long/short packet | SOF/EOF、ECC、CRC | ECC 錯誤計數 |
| 應用層 | frame 資料與 metadata | pixel format、embedded data | 格式/尺寸匹配 |
| 項目 | 規格 | 工程意義 |
|---|---|---|
| 連接器 | 15-pin × 2(Camera 0 / 1) | 可同時接兩顆 |
| 每連接器 lane | 4-lane | OV5647 只用 2-lane |
| 最高資料率 | ~1.5 Gbps/lane | 決定最高解析度/幀率 |
| 時脈 | 感測器提供 HS clock | DDR:雙沿取樣 |
dmesg | grep -i -E "unicam|ov5647" 應無 error。
統計上約半數「相機沒畫面」源於排線——先排除再碰軟體。| 層 | 元件 | 你操作什麼 | 原始碼/文件位置 |
|---|---|---|---|
| 應用 | rpicam-still、picamera2 | 拍照、錄影、設控制 | /usr/bin、pypi |
| 框架 | libcamera | 曝光/增益/AWB、載入 tuning 檔 | libcamera.org(開源) |
| 內核 | unicam + ov5647.c | CSI 接收、感測器 register | drivers/media/platform/raspberrypi |
| 硬體 | OV5647 → BCM2712 ISP | RAW 產出與校正 | datasheet |
drivers/media/i2c/ 有無對應(ov5647/ov5640/ov9281 皆有 mainline 驅動)。| 感測器 | 解析度 | 快門 | RPi5 | 定位 |
|---|---|---|---|---|
| OV5647 | 5 MP | Rolling | 官方 v1 ✅ | 本課主例(公開 datasheet) |
| OV5640 | 5 MP | Rolling | 驅動 ✅ | 教育/客製板 |
| OV9281 | 1 MP | Global | 驅動 ✅ | 機器視覺 |
# 查看可用 overlay sudo dtoverlay -a | grep -E "ov5647|ov9281" # 檢查 FPC 後 CSI 錯誤 dmesg | grep -i -E "unicam|csi|ov5647" | tail -5
除錯「訊號層」問題時,D-PHY 的電氣參數是關鍵:
| 參數 | HS(高速) | LP(低功耗) |
|---|---|---|
| 訊號 | 差動(D±) | 單端(CMOS 1.2V) |
| 擺幅 | 約 200 mV(100–300) | 0–1.2 V |
| 用途 | 傳 pixel 資料 | 控制(BTA/reset) |
| 時脈 | DDR 雙沿 | 低速 |
libcamera 啟動時依 media graph 找出「感測器 + ISP」並組 Camera;tuning 檔在首次使用該 Camera 時載入。若 list-cameras 看得到相機,代表這一串都成功。
sudo dtoverlay -a | grep cam。dmesg | grep -i -E 'unicam|ov5647' 確認無 error。場景:RPi5 同時接 OV5647(Camera 0)與 OV9281(Camera 1),要同時錄影用於雙目視覺。
# 1. 確認兩顆都被 libcamera 偵測 rpicam-hello --list-cameras # 顯示:0: ov5647 1: ov9281 # 2. 用 picamera2 同時串流(雙 stream) python3 - <<'EOF' from picamera2 import Picamera2 import time cam0 = Picamera2(0) # OV5647 cam1 = Picamera2(1) # OV9281 cfg0 = cam0.create_video_configuration( main={"size": (1280, 720), "format": "RGB888"}) cfg1 = cam1.create_video_configuration( main={"size": (640, 480), "format": "RGB888"}) cam0.configure(cfg0) cam1.configure(cfg1) cam0.start() cam1.start() time.sleep(3) cam0.stop() cam1.stop() print("雙鏡頭串流完成") EOF # 3. 檢查 DMA buffer 分配 dmesg | grep -i "dma\|buffer\|cma" | tail -5
CSI-2 D-PHY 的 HS(High-Speed)與 LP(Low-Power)模式之間的切換,不是「瞬間」完成的:
| 症狀 | 可能原因 | 解決方案 |
|---|---|---|
| dmesg 出現「unicam: frame sync timeout」 | D-PHY HS 切換超時,排線訊號完整性差 | 更換短排線(≤10cm)、確認金手指接觸、用示波器量 HS 眼圖 |
| rpicam-hello --list-cameras 只看到一顆 | 另一顆的 I2C 位址衝突或 DT overlay 未啟用 | sudo i2cdetect -y 22 和 -y 10 分別檢查;確認 /boot/firmware/config.txt 有兩筆 dtoverlay |
| 雙鏡頭同時串流時帧率明顯下降 | DMA buffer/CMA 不足,ISP 管線排程瓶頸 | 加大 CMA(/boot/firmware/cmdline.txt 加 cma=256M)、降低單顆解析度 |
| Camera 1 預覽有畫面但色彩全錯 | OV9281 是黑白感測器,被誤判為彩色 | 確認 tuning 檔對應 OV9281(無 CCM 區塊);不要套 OV5647 的 tuning |
| 開機後 dmesg 無任何 ov5647 訊息 | DT overlay 未載入或 compatible 字串不匹配 | sudo dtoverlay -a | grep ov5647;檢查 /boot/firmware/config.txt 的 dtoverlay=ov5647 行 |
media-ctl -p -d /dev/media0 畫出完整的 media graph,標出每個 entity 的 role(source/sink)與 pad format。若把 OV5647 的 lane 數從 2 改成 4(假設硬體支援),media graph 會有何變化?場景:這是一顆全新的 OV5647 模組 + RPi5 開發板。目標是走完「硬體 → overlay → 媒體節點 → 第一張 RAW」的完整端到端流程,驗證整個相機生態鏈就緒。這個專案整合單元 1(CSI-2/生態)、3(I2C)、4(overlay/驅動)、5(出圖)的知識。
# 階段 0:硬體安裝(單元 1 排線 SOP) # 金手指朝彈片、插入到底、鎖扣壓平 # 階段 1:確認 overlay 就緒 sudo dtoverlay -a | grep -E "ov5647|ov9281" # 預期:ov5647 在清單中 # 階段 2:確認 probe 與媒體節點 dmesg | grep -i -E "ov5647|unicam|csi" | tail -10 # 預期:ov5647 0-0036: Probing / Chip ID 0x5647,無 error ls /dev/media* /dev/video* # 階段 3:I2C 驗證感測器 ID(單元 3) sudo i2cdetect -y 22 | grep 36 # 預期看到 0x36 sudo i2ctransfer -y 22 w2@0x36 0x30 0x0a r1 # 預期 0x56 sudo i2ctransfer -y 22 w2@0x36 0x30 0x0b r1 # 預期 0x47 # 階段 4:libcamera 偵測(單元 4/5) rpicam-hello --list-cameras # 預期:0 : ov5647 [2592x1944 10-bit RGGB] + Modes 清單 # 階段 5:產出第一張 RAW rpicam-still --raw --shutter 20000 --gain 1.0 --awb off --awbgains 1.0,1.0 -o first.dng ls -la first.dng # 預期:first.dng 存在(RAW 檔)
sudo dtoverlay -a | grep ov5647 確認 overlay 清單。dmesg | grep -i -E "unicam|ov5647|csi" 確認無 error(回看最後 10 行)。sudo i2cdetect -y 22 確認 0x36 回應。rpicam-hello --list-cameras 確認 camera 0 出現。| 面向 | RPi5 | Orange Pi | Orin Nano | Thor |
|---|---|---|---|---|
| CSI 連接器 | 15-pin ×2,4-lane | MIPI 排針,2-lane 常見 | 15-pin / 22-pin,GMSL 選配 | HSB(乙太網路感測器) |
| 感測器驅動來源 | mainline 內核(ov5647/5640/9281) | 廠商 BSP,版本雜 | NVIDIA 自帶 + 社群 | NVIDIA + Holoscan |
| overlay/DT 機制 | config.txt + dtoverlay | overlays + 手改 dtb | device tree + kernel patch | device tree + YAML 描述 |
| 框架 | libcamera(開源) | V4L2 / gst 陽春 | Argus(閉源) | Argus / Holoscan |
| 生態坑 | 排線品質敏感 | BSP 驅動版本混亂 | 感測器支援需 NDA | 新、文件少 |
| 步驟 | 操作 | 位元級細節 |
|---|---|---|
| 1. 讀 | sudo devmem2 0x7e801004 w | 讀取 CSI2_NAND2 設定暫存器,確認 bit[0] PHY_EN 狀態 |
| 2. 改 | OR 0x00000007 | bit[0]=1(PHY_EN) bit[1]=1(CSI_EN) bit[2]=1(IRQ_EN) |
| 3. 寫 | sudo devmem2 0x7e801004 w 0x00000007 | 啟用 CSI-2 PHY + 控制器 + 中斷 |
| 4. 驗證 | sudo devmem2 0x7e801004 w | 確認回讀值 bit[2:0] = 0b111 |
0x00000007 mask 保留 bit[2:0],其餘 bit 以 OR 方式合併,避免影響其他功能設定。決策樹 A:相機完全無畫面
相機無畫面 ├─ 檢查 A:dmesg 有無 ov5647 probe 訊息 │ ├─ 無 → overlay 未啟用 → /boot/firmware/config.txt 加 dtoverlay=ov5647 │ └─ 有 → probe 成功,繼續 ├─ 檢查 B:i2cdetect 0x3C 是否有回應 │ ├─ 無 → I2C 通道未開 / 排線問題 / 供電異常 │ └─ 有 → I2C 正常,繼續 ├─ 檢查 C:rpicam-hello --list-cameras 是否出現 camera 0 │ ├─ 無 → libcamera 管線未正確綁定 → 檢查 /etc/libcamera/ipa_rpi.yaml │ └─ 有 → 硬體層 OK,問題在應用層 └─ 檢查 D:測試擷取 RAW 是否為全黑 ├─ 全黑 → sensor 曝光設定異常 / MIPI 訊號未到達 ISP └─ 有資料 → 基本功能 OK
決策樹 B:i2cdetect 有回應但畫面異常
i2cdetect 有回應但畫面異常 ├─ 檢查 A:dmesg 有無 CSI error / frame sync error │ ├─ 有 → MIPI 時序問題 → 檢查 clock lane 頻率設定 │ └─ 無 → 繼續 ├─ 檢查 B:曝光時間是否合理 │ ├─ 0 或最大值 → AE 未收斂 → 檢查 tuning 檔案 │ └─ 正常 → 繼續 └─ 檢查 C:是否只在特定解析度下異常 ├─ 是 → 該解析度 lane 數/時序不匹配 → 調整 MIPI config └─ 否 → 軟體管線問題
| 面向 | RPi5 | Orange Pi | Orin Nano | Thor | 推薦 |
|---|---|---|---|---|---|
| CSI 介面 | 15-pin ×2, 4-lane | MIPI 排針, 2-lane | 15/22-pin, GMSL 可選 | HSB 乙太網路 | RPi5 最易上手 |
| 感測器驅動 | mainline 內核 | 廠商 BSP | NVIDIA + 社群 | NVIDIA + Holoscan | RPi5 mainline 最穩定 |
| Overlay 機制 | config.txt dtoverlay | overlays + dtb | device tree + patch | DT + YAML | RPi5 最簡潔 |
| 相機框架 | libcamera 開源 | V4L2 陽春 | Argus 閉源 | Argus / Holoscan | RPi5 生態最完整 |
| 多感測器 | 2 port 官方支援 | 1-2 port | 多 port + GMSL | 乙太網路天生分散 | Orin 規模最大 |
| 上手難度 | ★★☆ | ★★★ | ★★★★ | ★★★★★ | RPi5 入門首選 |
vcgencmd version ≥ 2024-01)/boot/firmware/config.txt 加入 dtoverlay=ov5647(或對應感測器)dmesg | grep ov5647 確認 probe 成功i2cdetect -y 1 確認 0x3C 出現rpicam-hello --list-cameras 確認 camera 0 列出rpicam-hello -k --nopreview -t 5000 --raw)