單元 6 · Sensor Bring-up 與除錯

上電時序、PLL 位元級、MIPI、決策樹

6.1 上電時序(OV5647 需求)

電源域電壓時序要求
1AVDD(analog)2.8 V先穩定
2DOVDD(I/O)1.8 V可與 AVDD 同時或稍後
3DVDD(digital)1.5 V在 DOVDD 後
4XCLK24 MHz電源穩定後
5RESET 釋放XCLK 穩定後 ≥ 若干 ms
6I2CRESET 後才可通
最常見錯誤:RESET 未釋放就下 I2C → register「看似能寫但沒生效」。官方模組由 overlay 管理時序;客製板要自製:reset 腳位保持低位 → 上電 → XCLK → 釋放 reset → 等 → 下 I2C

6.2 PLL:從 XCLK 到位元流(位元級)

OV5647 由 XCLK(典型 24 MHz)經內部 PLL 產生主時脈。關鍵 register:

Register欄位典型值意義
0x3034PLL pre-divider0x18XCLK 輸入分頻
0x3035PLL divider0x31VCO 分頻
0x3036PLL multiplier0x69VCO 倍頻
0x3037PLL control0x11含 lock 狀態位元
工程檢查:改 PLL 前先讀 0x3037 記錄,改後回讀確認。PLL 錯 → 畫面 fps 異常或全黑。以 ov5647.c 的 ov5647_2lane_480Mbps init 表為唯一正確依據(不要自行亂配)。

6.3 MIPI 介面 register

Register功能典型值備註
0x4740MIPI 介面控制0x22
0x4741lane 數設定0x000x00 = 2-lane
0x4742clock/data 設定0x0b

lane 數若與 DT overlay 宣告不一致 → 串流失敗。這是「驅動 vs 硬體」不一致的典型。

6.4 media 管線完整走查

media-ctl -p -d /dev/media0(節錄)
- entity 3: ov5647 0-0036 (1 pad, 1 link)
    type V4L2 subdev
    pad0: Source [fmt:SGBRG10_1X10/2592x1944]

- entity 6: unicam (1 pad, 1 link)
    type V4L2 subdev
    pad0: Sink [fmt:SGBRG10_1X10/2592x1944]

看到感測器 pad 的格式 → 管線已設定。格式不匹配(source 與 sink)→ 串流失敗。

6.5 「相機沒畫面」完整決策樹

決策樹(自上而下)
1. rpicam-hello --list-cameras
   ├─ 空 ───────────────────────────────→ 步驟 A
   └─ 有 ─┐
2. i2cdetect -y 22 看到 0x36?
   ├─ 無 ─→ 步驟 B
   └─ 有 ─┐
3. 讀 0x300A/B = 0x56/0x47?
   ├─ 錯 ─→ 步驟 C
   └─ 對 ─┐
4. rpicam-hello 預覽
   ├─ 黑 ─→ 曝光 0?AE 關?鏡頭蓋?→ 單元 10
   └─ 有畫面 ── 基本 bring-up ✅

步驟 A(list 不到):dmesg | grep -i -E "ov5647|unicam|error"
   ├─ probe failure → 電源/clock/位址(檢查 DT)
   └─ 排線/連接器 → 重插、換排線

步驟 B(無 0x36):上電?RESET?位址(7-bit vs 8-bit)?匯流排對嗎(22/10)?

步驟 C(ID 錯):是別顆感測器?I2C 位址衝突?換過板子?

6.6 Register dump 完整範例

dump 曝光與 PLL 群
for r in 0x300a 0x300b 0x3034 0x3035 0x3036 0x3037          0x3500 0x3501 0x3502 0x3503 0x350a 0x350b; do
  h=${r:2:2}; l=${r:4:2}
  printf "%s: " "$r"; sudo i2ctransfer -y 22 w2@0x36 0x$h 0x$l r1
done

6.7 dmesg 關鍵訊號

dmesg 片段意義
ov5647 0-0036: Probing驅動開始 probe
ov5647: Chip ID 0x5647ID 讀取成功(若 log 有)
unicam: Failed to...CSI 收資料失敗
無任何 ov5647 訊息DT 沒掛 overlay / 驅動沒載

6.8 深入:OV5647 的完整 init sequence 概念

感測器開機後不是「能用」,而是需要驅動寫入一整串 init register(時序、解析度、增益、AWB…)。ov5647.c 內含 ov5647_2lane_480Mbps 等表格,就是這份 init。

工程意義:你不需要背這些值,但要理解「感測器從上電到出圖 = 上電時序 + init register」。若畫面異常,先確認「是否走完 init」——而不是懷疑某個 register 值。

6.9 深入:幀率與曝光行數的關係

曝光時間(行數)不能超過幀總行數(frame length)。若設的曝光 > 幀長,感測器會「卡在曝光」→ 幀率掉或全黑。

檢查曝光 vs 幀長
# 讀曝光 register
sudo i2ctransfer -y 22 w2@0x36 0x35 0x01 r1
sudo i2ctransfer -y 22 w2@0x36 0x35 0x02 r1
# 讀 frame length(0x380E/0x380F)
sudo i2ctransfer -y 22 w2@0x36 0x38 0x0e r1
常見症狀:曝光設太大 → 畫面「有時黑有時亮」或幀率掉一半。libcamera 會限制曝光範圍,但手動寫 register 時要自己小心。

6.10 練習:完整 Bring-up 演練

  1. 拔掉排線 → list-cameras,記錄「空」。
  2. 插回排線 → list-cameras,確認「有」。
  3. i2cdetect 讀 ID,確認 0x5647。
  4. rpicam-hello 預覽,確認畫面。
  5. 把每一步的 dmesg 記錄下來。
看完這單元你應該能說出:
  • 上電時序六步與 RESET 陷阱。
  • PLL register 位元級與檢查。
  • MIPI lane 設定一致性。
  • media 管線走查。
  • 完整 Bring-up 決策樹與 dmesg 判讀。

進階真實情境 Worked Example:從零開始的完整 Bring-up 除錯流程

場景:你拿到一塊新的 OV5647 客製板,接上 RPi5 後 list-cameras 為空。需要從零開始走完整決策樹。

完整除錯序列
# === 步驟 1:確認 overlay 是否載入 ===
sudo dtoverlay -a | grep ov5647
# 若空 → 加入 /boot/firmware/config.txt:
#   dtoverlay=ov5647
# 重開機

# === 步驟 2:dmesg 看 probe 狀態 ===
dmesg | grep -i -E "ov5647|unicam|error" | tail -20
# 預期看到 "ov5647 0-0036: Probing"
# 若看到 "probe failed" → 進入步驟 3

# === 步驟 3:I2C 掃描 ===
sudo i2cdetect -y 22
# 看到 0x36 → I2C 通
# 全空 → 檢查排線/電源

# === 步驟 4:讀 sensor ID ===
sudo i2ctransfer -y 22 w2@0x36 0x30 0x0a r1  # 應回 0x56
sudo i2ctransfer -y 22 w2@0x36 0x30 0x0b r1  # 應回 0x47

# === 步驟 5:PLL 暫存器快照 ===
for r in 0x3034 0x3035 0x3036 0x3037; do
  h=${r:2:2}; l=${r:4:2}
  printf "%s: " "$r"
  sudo i2ctransfer -y 22 w2@0x36 0x$h 0x$l r1
done

# === 步驟 6:出圖驗證 ===
rpicam-hello --list-cameras
rpicam-still --raw -o test.dng --shutter 20000 --gain 1
為什麼選這條路徑:這個序列嚴格遵循「自上而下、每次只改一個變數」的原則。先確認 overlay(最外層),再確認 I2C(中間層),再確認 register(底層),最後確認出圖。若跳步驟直接猜「可能是 ISP 問題」,會浪費大量時間在不相關的排查上。

深入原理擴充:OV5647 的 PLL 與 MIPI data rate 計算

OV5647 的 PLL 暫存器決定了 pixel clock 與 MIPI data rate,兩者不匹配會導致串流失敗:

大家以為沒問題但其實是陷阱:很多人以為「PLL 暫存器只要跟 init table 一致就好」,但 OV5647 的 PLL lock time(0x3037 的 lock 位元)需要數 ms。若 driver 在 PLL 未 lock 就開始 streaming,會出現「開機後前幾幀色彩異常」的症状——這在快速切換曝光參數時尤其明顯。

診斷式疑難排解表

症狀可能原因解決方案
probe 成功但 streaming 時 dmesg 出現 CSI errorMIPI data rate 與 ISP 接收速率不匹配對照 PLL 暫存器與 datasheet 的建議值;確認 lane 數一致
i2cdetect 掃到 0x36 但讀回 ID 全為 0xFF感測器在低功耗模式,需要 XCLK 才能回應確認 XCLK GPIO 已輸出 24MHz;用示波器量 XCLK 腳位
dmesg 出現「PLL not locked」PLL 暫存器配置錯誤或 XCLK 頻率偏差確認 XCLK 頻率(示波器);還原 PLL 暫存器到 init table 值
rpicam-hello 預覽前 1-2 秒色彩偏移PLL lock 延遲 + AWB 初始值不準在 tuning 檔中增加 AWB convergence delay;或等 AE/AWB 穩定後再擷取
換板子後完全沒畫面(但 dmesg 顯示 probe 成功)排線阻抗不匹配導致 MIPI HS 訊號劣化用已知良品排線交叉測試;量測 MIPI 差動阻抗

進階挑戰題

  1. 設計一個「自動 bring-up 測試」腳本:依序執行 overlay 確認 → I2C 掃描 → ID 讀取 → PLL dump → list-cameras → RAW 拍攝,每步驟若失敗即中斷並報告根因。
  2. 若 OV5647 的 XCLK 從 24MHz 改為 6MHz,PLL 暫存器需要如何調整?推導新的 multiplier/divider 組合。
  3. 研究 libcamera 的 ov5647.c 驅動中 ov5647_2lane_480Mbps init table 的每一行暫存器的作用,畫出「暫存器 → 功能」對照表。

延伸閱讀

專案級端到端 Worked Example:一鍵自動化 bring-up 專案

場景:生產線要驗證每塊客製板,不能靠人肉一步步打指令。本專案把單元 6 的決策樹寫成自動化腳本:依序驗證 overlay → I2C → ID → PLL → 出圖,任何一步失敗立即中斷並報出根因。整合單元 6(決策樹)、3(I2C)、4(overlay)、5(出圖)。

autobringup.sh:一鍵 bring-up
#!/bin/bash
set -e
BUS=22; ADDR=0x36
fail() { echo "✗ FAIL: $1"; exit 1; }
pass() { echo "✓ $1"; }

# 步驟 1:overlay 就緒
dtoverlay -a | grep -q ov5647 && pass "overlay 就緒" || fail "無 ov5647 overlay"

# 步驟 2:I2C 有回應
sudo i2cdetect -y $BUS | grep -q 36 && pass "I2C 0x36 回應" || fail "I2C 無回應"

# 步驟 3:讀感測器 ID
HI=$(sudo i2ctransfer -y $BUS w2@$ADDR 0x30 0x0a r1)
LO=$(sudo i2ctransfer -y $BUS w2@$ADDR 0x30 0x0b r1)
[ "$HI$LO" = "0x560x47" ] && pass "ID=$HI$LO" || fail "ID 錯誤=$HI$LO"

# 步驟 4:PLL 快照(記錄於 log)
for r in 3034 3035 3036 3037; do
  printf "PLL %s=%s\n" "$r" "$(sudo i2ctransfer -y $BUS w2@$ADDR 0x${r:0:2} 0x${r:2:2} r1)"
done

# 步驟 5:出圖驗證
rpicam-hello --list-cameras | grep -q ov5647 && pass "libcamera 偵測" || fail "list-cameras 空"
rpicam-still --raw --shutter 20000 --gain 1 -o /tmp/bringup.dng && pass "出圖 OK"
echo "=== bring-up 全部通過 ==="
專案規模與跨單元整合:這就是單元 6 決策樹的「可執行版本」:步驟 1-2 對應決策樹步驟 A/B、步驟 3 對應步驟 C、步驟 5 對應出圖。量產時把它掛進 CI 或生產線,每一塊板 30 秒內判定好壞。失敗訊息直接對應診斷表,維修人員不用懂原理也能定位。

量測/驗證 SOP:Bring-up 驗證

  1. 確認上電時序(AVDD→DOVDD→DVDD→XCLK→RESET)由 overlay 正確管理。
  2. 跑 autobringup.sh,逐項通過才放行。
  3. 手動檢查 dmesg:ov5647: Probing 與 Chip ID 訊息。
  4. 讀 PLL 四 register,與 ov5647.c init table 對照。
  5. 確認 MIPI lane 設定(0x4741=0x00 為 2-lane)與 DT data-lanes 一致。
  6. 存 bring-up log(含 PLL 快照與出圖 RAW 的 hash)。
判讀指標:任何一步失敗即中斷並報根因(腳本已含);PLL 值與 init table 不符 = 驅動被改過;出圖全黑 = 回單元 10 查曝光。Bring-up 通過標準 = 五步驟全綠。

平台間對照:上電時序與 PLL

面向RPi5Orange PiOrin NanoThor
上電管理overlay 的 reset/pwdn GPIOBSP 驅動自管tegracam + device treetegracam / Holoscan
XCLK 來源cam_clk(可調頻率)CLK 控制器sensor clock treeHSB 時脈
PLL 檢查i2ctransfer 讀 0x3034-0x3037同(register 相同)同(register 相同)同(register 相同)
RESET 未釋放即下 I2C上電順序在 BSP 黑箱需 NVIDIA driver 先載感測器經乙太、時序不同

互動式檢核清單


第 3 輪深度加深

① Register 位元級完整工作流:OV5647 診斷性暫存器 dump

暫存器範圍用途dump 指令範例
0x3000-0x3005感測器控制(stream on/off)for i in $(seq 0x3000 0x3005); do printf "0x%04X: " $i; i2cget -y 1 0x3C $i w; done
0x3500-0x3503AEC 曝光設定同上改範圍 0x3500-0x3503
0x3034-0x3037PLL 設定同上改範圍 0x3034-0x3037
0x3800-0x3821整合窗口同上改範圍
0x5001-0x501FISP 控制同上改範圍
SOP:把 dump 結果寫入 CSV,與已知 good register map 比對,快速定位差異位元。

② 多層疑難排解決策樹

決策樹 A:I2C scan 找不到感測器

I2C 找不到
├─ 檢查 A:GPIO 供電是否正常
│  ├─ cam0_reg/cam1_reg = 0V → 電源 IC 異常 / overlay 未設定 power GPIO
│  └─ 供電正常 → 繼續
├─ 檢查 B:排線方向與位置
│  ├─ 排線反插 → 重插正確方向
│  └─ 正確 → 繼續
├─ 檢查 C:I2C pull-up 是否存在
│  ├─ 無 pull-up → SCL/SDA 處於 floating → 加 2.2kΩ pull-up to 3.3V
│  └─ 有 pull-up → 繼續
└─ 檢查 D:嘗試另一個 I2C bus(GPIO 0/1 vs GPIO 2/3)
   ├─ 另一個 bus 有回應 → overlay 指定了錯誤的 I2C bus
   └─ 都無回應 → 排線 / 感測器硬體問題

決策樹 B:影像有嚴重 color cast

Color cast
├─ 檢查 A:AWB 是否啟用
│  ├─ 未啟用 → tuning 檔案中 AWB 模組關閉
│  └─ 已啟用 → 繼續
├─ 檢查 B:CCM (Color Correction Matrix) 是否為 identity
│  ├─ 是 → 需設定正確 CCM 係數
│  └─ 否 → 繼續
├─ 檢查 C:光源色溫是否在 AWB 覆蓋範圍
│  ├─ 不在 → AWB 演算法收斂失敗 → 加入該色溫範圍
│  └─ 在範圍內 → 繼續
└─ 檢查 D:感測器 IR filter 是否正確
   ├─ 無 IR filter → 近紅外光干擾 → 加 IR cut filter
   └─ 有 IR filter → CCM 矩陣需針對實際光源校正

③ 量測驗證完整 SOP:系統性 Register 掃描

  1. 工具:RPi5 + i2c-tools + Python script
  2. 步驟:
    a. dump 全部暫存器(0x0000-0x6xxx)存為 CSV
    b. 載入已知 good register map(CSV)
    c. diff 兩份 CSV,列出所有差異位元
    d. 對每個差異,標註暫存器功能(參考 datasheet)
  3. 判讀:0-5 個差異 = 正常(版本差異);>10 個差異 = 可能有初始化不完整
  4. 常見偏差:部分暫存器在不同 lighting mode 下值不同 → 非異常

④ 四平台終極對照

面向RPi5Orange PiOrin NanoThor推薦
除錯工具i2c-tools + dmesgi2c-tools + dmesgNV debug toolsNV debug + HoloscanRPi5 最直覺
Register dumpi2cget 逐個讀i2cgetNV 驅動內建NV 驅動內建RPi5 最透明
常見坑overlay 未生效BSP 版本不匹配NV closed source文件不足各平台有各自坑
社群除錯論壇活躍較少Jetson 專區新、少RPi5 + Jetson 社群最活躍

⑤ 完整 Bring-up 專案 Checklist