單元 6 · Sensor Bring-up 與除錯

上電、clock、register dump、決策樹

6.1 Bring-up 四件事

檢查項驗證工具
電源AVDD/DVDD/DOVDD 到位示波器/電表
ClockXCLK/MCLK 有輸出示波器 / dmesg
I2Ci2cdetect + 讀 IDi2c-tools
MIPIdmesg 無 CSI 錯誤、media 有資料dmesg / media-ctl

6.2 上電時序(OV5640 需求)

AVDD/DOVDD 穩定XCLK/MCLKRESET 釋放I2C 可通MIPI 輸出
最常見錯誤:RESET 未釋放就下 I2C → register「看似能寫但沒生效」。Orange Pi 的 RESET/PWDN 腳位由板卡與驅動管理,先確認 GPIO 設定正確。

6.3 用 dmesg 追線索

常見除錯指令
dmesg | grep -i -E "ov5640|csi|mipi|v4l2|probe"
cat /sys/kernel/debug/gpio | grep -i reset
dmesg 訊號意義
ov5640 ... probe success驅動 probe 成功
probe failure / failed to read chip idI2C/clock/電源問題
CSI: no dataMIPI 沒資料 → 感測器沒輸出

6.4 Register dump 實作

透過 controls 與 i2c 讀
v4l2-ctl -d /dev/v4l-subdev0 -C exposure     # 讀曝光 control
v4l2-ctl -d /dev/v4l-subdev0 -C analogue_gain
for r in 0x3500 0x3501 0x3502 0x3503; do
  echo -n "$r: "; sudo i2ctransfer -y 3 w2@0x3c ${r:2:2} ${r:4:2} r1
done

6.5 Bring-up 決策樹

「沒畫面」決策樹
1. dmesg 有 ov5640 probe?
   ├─ error ─→ 電源/clock/reset/位址(I2C 0x3c?)
   └─ ok ─┐
2. i2cdetect 看到 0x3c?讀到 0x5640?
   ├─ 否 ─→ I2C 位址/上電問題
   └─ 是 ─┐
3. v4l2-ctl 取到幀?
   ├─ 否 ─→ media 管線/格式(media-ctl 檢查)
   └─ 是 ─→ 基本 bring-up ✅
Orange Pi 特別注意:各板卡 BSP 的節點/位址/格式都不同——先確認你板卡「已知可用組合」,否則決策樹第一步就會卡住。

6.7 深入:上電時序與 clock 驗證

電源穩定MCLK/XCLKRESET 釋放I2C 可通MIPI 輸出
最常見錯誤:RESET 未釋放就下 I2C → register「看似能寫但沒生效」。先確認 GPIO/時序,再碰 register。
dmesg 追線索
dmesg | grep -i -E "ov5640|probe|csi|mipi|v4l2"

6.9 深入原理:上電時序與 PLL/clock 的位元細節

Bring-up 最常卡在「register 能寫但影像不出」——通常不是 register 錯,而是 時序或 clock 沒到位。OV5640 的 clock 由 XCLK 輸入,內部經 PLL 產生感測器主時脈:

Register欄位意義
0x3035PLL 分頻設定MIPI 模式下的 clock 計算
0x3036PLL 倍頻決定感測器內部時脈
0x3106clock 源開關內部 clock 啟用
0x3108reset 控制軟體 reset / 切模式

上電時序的位元級規則:① AVDD/DOVDD 先穩定 → ② XCLK 必須在 RESET 釋放「之前或同時」開始 → ③ RESET 釋放後要等 t_PW_UP(OV5640 datasheet 約數 ms)才能下 I2C → ④ 之後讀 ID。違反任一順序,感測器可能「不回應」或「回應但 register 寫不進去」。

驅動會幫你:mainline ov5640.cs_power/__power_on 內已實作完整時序。手動 bring-up 只是為了理解「如果沒驅動,該怎麼自己來」。

6.10 完整 Worked Example:從零到有的一條龍 bring-up

步驟 1|確認電源與 clock 硬體
cat /sys/kernel/debug/gpio | grep -i -E "reset|pwdn"   # GPIO 狀態
cat /sys/kernel/debug/clk/clk_summary | grep -i xclk    # clock 有無 enable
步驟 2|確認 probe 與 ID
dmesg | grep -i ov5640
sudo i2cdetect -y 3
sudo i2cget -y 3 0x3c 0x300a   # 0x56
步驟 3|讀 PLL 與上電狀態
for r in 0x3035 0x3036 0x3106 0x3108; do
  echo -n "$r: "; sudo i2ctransfer -y 3 w2@0x3c ${r:2:2} ${r:4:2} r1
done
步驟 4|建管線取幀
media-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=YUYV \
  --stream-mmap=3 --stream-count=1 --stream-to=f.yuv
完成標準:從 GPIO/clock 一路驗證到「取到一幀」。每一關都過才代表 bring-up 完成,不是「register 能寫」就結束。

6.11 疑難排解決策樹:深入版

節點失敗點追查
電源AVDD/DVDD/DOVDD 電壓不在規格電表量模組 pin、看電源樹 DT
ClockXCLK 無輸出或頻率錯示波器量 XCLK;對照 DT 的 clock-frequency
ResetRESET 沒釋放GPIO debug 檔、DT reset-gpios 高低電位
I2CID 讀不到/讀錯回單元 3 決策樹
MIPIdmesg 有 CSI no-data檢查 lane count / 對齊、感測器 MIPI 輸出 register
Media管線沒連media-ctl -p 對照
常見錯誤與陷阱:① 用錯 XCLK 頻率(OV5640 需要 6–27 MHz,通常 24 MHz)——PLL 算錯會整批時序不對;② RESET 腳高/低電位搞反(active-low 是常態);③ 誤以為「register 能讀」=「硬體全對」——讀寫只證明 I2C 通,不證明電源/clock/時序對;④ 換了板卡卻沿用舊 bus 編號。

6.12 練習

  1. 實作「GPIO→clock→ID→取幀」四步,輸出每一步的證據(指令輸出)。
  2. 讀取 PLL register 群,對照你板卡的 XCLK 頻率寫出計算過程。
  3. 模擬「RESET 未釋放」情境,記錄 register 讀寫的現象。
  4. 把 dmesg 的 probe 流程整理成一份檢查表,貼進你的 bring-up SOP。

6.13 回顧練習:完整 Bring-up 演練

  1. dmesg 確認 probe 成功、讀到 ID。
  2. media-ctl 確認管線。
  3. v4l2-ctl 取到幀。

6.14 進階真實情境 Worked Example:從 dmesg 追蹤到 PLL 計算錯誤

場景:Orange Pi Zero 3(Allwinner H618)接 OV5640,dmesg 有 probe 成功但取流時全黑。從 dmesg 追到 PLL 設定錯誤。

步驟 1|抓 dmesg 中的 clock 相關訊息
dmesg | grep -i -E "ov5640|clock|pll|xclk|rate"
# 找到: ov5640 3-003c: xclk (24000000 Hz) ...
步驟 2|讀 PLL register 並手算
for r in 0x3035 0x3036 0x3106; do
  h=${r:2:2}; l=${r:4:2}
  echo -n "$r: "; sudo i2ctransfer -y 3 w2@0x3c 0x$h 0x$l r1
done
步驟 3|對照 datasheet 計算 MIPI clock
# OV5640 PLL: PLL_multiplier / PLL_prediv / sys_divider
# 若算出 MIPI clock 超過 D-PHY 上限 → 全黑
設計決策:Allwinner H618 的 CSI 接收器對 MIPI clock 更敏感——RK3588 通常有更寬的容忍範圍。H618 上 PLL 設定稍偏就可能全黑,而 RK3588 可能只是幀率異常。

6.15 深入原理擴充:Allwinner CIF vs RK3588 ISP3 的上電時序差異

項目Allwinner CIFRK3588 ISP3
上電序列AVDD → DOVDD → XCLK → RESET釋放AVDD → DOVDD → DVDD → XCLK → RESET釋放
Clock 啟用DT clock-frequency 直接驅動需額外設定 clock-output-names
Reset 極性通常 active-low依 DT reset-gpios 設定
probe 失敗後重試需完整 power cycle可 unbind/bind driver

容易忽略的邊界案例:RK3588 的 ISP3 支援「warm reset」(不重上電就重置感測器),但 Allwinner CIF 不支援——在 H618 上 probe 失敗後,必須完整斷電重來。這在量產環境的自動復位策略中會造成額外停機時間。

6.16 診斷式疑難排解表

症狀可能原因解決方案
dmesg 有 probe success 但 i2cdetect 沒 0x3cprobe 時 I2C 通但之後 bus 被其他裝置佔用重新掃描 I2C bus;檢查是否有其他驅動佔用同一 bus
XCLK 有輸出但 frequency 不對DT 的 clock-frequency 與實際不符用示波器量 XCLK;對齊 DT 設定(OV5640 需 24MHz)
RESET GPIO 狀態正確但 probe 失敗RESET 釋放後未等 t_PW_UP 就下 I2C在驅動中加入 delay(OV5640 約需 5ms)
RK3588 ISP3 probe 成功但取流 EBUSYISP 被其他 process 佔用(如 GStreamer 殘留)kill 所有 gst-launch 進程;檢查 fuser /dev/video0
H618 probe 成功但全黑PLL 計算錯誤導致 MIPI clock 超限讀 PLL register(0x3035/0x3036),對照 datasheet 計算

6.17 進階挑戰題

  1. 在 Allwinner H618 上模擬「RESET 未釋放」:用 gpio 工具手動拉低 reset GPIO,觀察 i2ctransfer 的回應變化。記錄每種症狀。
  2. 在 RK3588 上,用 media-ctl -p 找出 ISP3 的所有 pad,並手動設定 ISP 輸出格式為 NV12(而非 YUYV)。比較兩者的 sizeimage 差異。
  3. 設計一支 bring-up 自動化腳本:依序檢查電源→clock→I2C→ID→取流,每步回傳 pass/fail,最終產出一份 HTML 報告。

6.18 專案級 Worked Example:完整感光元件 bring-up 專案 — 從 DT overlay 到第一張圖

把單元 1–6 串成一個完整 bring-up 專案:從一片空白板卡開始,寫 DT overlay → probe → 建管線 → 取到第一張圖。這是「能獨立 bring-up 一顆感測器」的總驗收。

階段 1|硬體盤點(單元 1)
uname -a
sudo i2cdetect -l
ls /dev/video* /dev/v4l-subdev* 2>/dev/null
階段 2|寫 DT overlay(單元 6)
/dts-v1/;
/plugin/;
&i2c3 {
  status = "okay";
  ov5640: ov5640@3c {
    compatible = "ovti,ov5640";
    reg = <0x3c>;
    clocks = <&clk_cam0>;
    clock-frequency = <24000000>;
    reset-gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
    pinctrl-0 = <&camera_pwr_en>;
  };
};
階段 3|probe + 讀 ID(單元 3)
sudo dtoverlay ov5640.dtbo
sudo reboot
dmesg | grep -i -E "ov5640|probe"
sudo i2cget -y 3 0x3c 0x300a   # 0x56
階段 4|建管線取第一張圖(單元 5)
media-ctl -d /dev/media0 -r
media-ctl -d /dev/media0 -l "'ov5640 3-003c':0->'csi2':0[1]"
media-ctl -d /dev/media0 -V "'ov5640 3-003c':0[fmt:UYVY8_2X8/1280x720]"
v4l2-ctl -d /dev/video0 --set-fmt-video=width=1280,height=720,pixelformat=YUYV \
  --stream-mmap=3 --stream-count=1 --stream-to=first.yuv
ls -l first.yuv   # 1,843,200 bytes
專案完成標準:四階段全過 = 你已具備獨立 bring-up 能力。把每階段輸出存成 bringup_log.txt,這是你團隊「已知可用組合」文件的第一筆資料。

6.19 量測/驗證 SOP:bring-up 全流程驗收

階段驗證項目通過判據
1. 電源AVDD/DVDD/DOVDD 電壓電表量測符合 datasheet(單元 6.1)
2. ClockXCLK 頻率示波器量到 ~24 MHz
3. ResetRESET 極性與釋放GPIO debug 顯示 high(active-low)
4. I2Ci2cdetect + 讀 ID0x3c 出現,讀回 0x56/0x40
5. Mediamedia-ctl entity 與 linksensor+csi+video 齊全
6. 出圖v4l2-ctl 取幀取得正確 sizeimage 的幀
SOP 紀律:bring-up 是「依序過關」,不是「找到一個就結束」。電源 → clock → reset → I2C → media → 出圖,每一關的證據(指令輸出)都要留存,才能讓下一個人複製你的成功。

6.20 平台間對照:Sensor Bring-up

面向Orange PiRPi5Orin NanoThor
overlay 機制dtbo + dtoverlayconfig.txt dtoverlayDevice tree + board configDevice tree + Holoscan
XCLK 來源板卡 clock 樹RPi 專屬 clock感測器電源板感測器電源板
probe 日誌dmesg(全開放)dmesg + libcamera logdmesg(部分封閉)dmesg + Holoscan log
錯誤重試unbind/bind 驅動重載 libcamera重開 service重開 pipeline
除錯深度完全可見(register 層)高但被抽象低(封閉)低(封閉)
核心領悟:Orange Pi 的 bring-up 是最「裸露」的——所有失敗都看得見、也可全手動操作。這正是練習 bring-up 的最佳平台;在 NVIDIA 平台,這些細節被封裝起來,學習成本反而更高。

6.21 互動式檢核清單:本單元進階驗收

checklist
- [ ] 我能從零寫出一個 OV5640 的最小 DT overlay。
- [ ] 我能依序驗證電源 → clock → reset → I2C → media → 出圖。
- [ ] 我已產出帶指令輸出的 bringup_log.txt。
- [ ] 我能從 dmesg 分辨 probe 失敗的根因類別。
- [ ] 我理解 t_PW_UP 為何是「register 寫不進去」的隱藏殺手。
- [ ] 我能把 bring-up 知識應用於不同 SoC(RK3588 vs H618)。

6.22 Register 位元級完整工作流

Sensor bring-up 的「讀→改→寫→驗證」是驅動工程師的核心技能。以下是完整的位元級序列:

步驟暫存器/位址位元欄位操作預期值
1. 確認電源GPIO debugAVDD/DVDD levelcat /sys/kernel/debug/gpio | grep powerhigh(已上電)
2. 確認 resetGPIO debugreset levelcat /sys/kernel/debug/gpio | grep resethigh(已釋放)
3. 讀 sensor ID0x300A + 0x300B[7:0]i2cget -y 3 0x3c 0x300a; i2cget ... 0x300b0x56 + 0x40
4. 驗證 PLL0x3035[7:4]i2cget ... 0x3035依 DT clock
5. 建 media link/dev/media0media-ctl -l "...:0->...:0[1]"link active
6. 設定 format/dev/media0media-ctl -V "...:0[fmt:SRGGB10_1X10/1920x1080]"格式設定成功
7. 取流驗證/dev/video0v4l2-ctl --stream-mmap=1 --stream-count=1成功產出檔案
位元級關鍵: bring-up 的每一步都有「通過/失敗」的明確判據。0x300A=0x56 是 I2C 通的鐵證;dmesg "probe success" 是驅動綁定的鐵證;sizeimage 正確是管線正常的鐵證。

6.23 多層疑難排解決策樹

決策樹 A:probe 失敗

決策樹 A
dmesg | grep "probe"
├─ "probe failed" → 依錯誤:
│  ├─ "no chip id" → I2C 通但 ID 錯
│  │  ├─ 嘗試其他 I2C 位址(0x3c/0x36)
│  │  └─ 確認感測器型號(OV5640 vs OV9281)
│  ├─ "clk prepare failed" → clock 未就緒
│  │  └─ 檢查 DT clock-frequency 設定
│  ├─ "reset" → reset GPIO 問題
│  │  └─ 檢查 reset-gpios 極性(active-low/high)
│  └─ "power" → 電源異常
│     └─ 量測 AVDD/DVDD/DVDD18 電壓
└─ "probe success" → 驅動綁定成功
   └─ 檢查 /dev/video* 是否存在

決策樹 B:probe 成功但無圖

決策樹 B
v4l2-ctl --stream-mmap=1 --stream-count=1
├─ 無輸出 → media-ctl 未建 link
│  └─ 依序:media-ctl -l → media-ctl -V → v4l2-ctl
├─ 全黑 → sensor 無曝光
│  ├─ 手動曝光:v4l2-ctl --set-ctrl=exposure=500
│  └─ 驗證:i2cget 0x3500~0x3502
├─ 斜圖 → format 錯誤
│  └─ 檢查 bytesperline 與 Bayer order
└─ 全白 → 過曝
   └─ 減少 analog gain:v4l2-ctl --set-ctrl=gain=16

6.24 量測驗證完整 SOP

步驟指令預期輸出判讀標準
1. dmesg probedmesg | grep -i "ov5640\|probe""probe success"無 error/warning
2. I2C 讀 IDi2cget -y 3 0x3c 0x300a0x56感測器正常
3. media graphmedia-ctl -psensor → csi → video完整管線
4. 設定 formatmedia-ctl -VSRGGB10/1920x1080正確格式
5. 建 linkmedia-ctl -llink active正確 pad
6. 取一幀v4l2-ctl --stream-mmap=1 --stream-count=1成功sizeimage 正確
7. 連續取流v4l2-ctl --stream-mmap=4 --stream-count=100100 幀無 error穩定無掉幀

6.25 四平台終極對照

面向Orange PiRPi5Orin NanoThor推薦
bring-up 難度中(完全手動)低(libcamera)低(封裝好)低(封裝好)學習→Orange Pi
除錯深度完全可見低(封閉)低(封閉)除錯→Orange Pi
DT overlaydtbo + dtoverlayconfig.txtBoard configHoloscanOrange Pi 最透明
dmesg完全開放完整部分封閉部分封閉Orange Pi 最佳
probe 日誌dmesgdmesg + libcameradmesg(部分)dmesg + HoloscanOrange Pi 最詳細

6.26 完整 Bring-up 專案 Checklist

checklist
- [ ] 確認 SoC 型號與 DT overlay
- [ ] 量測 AVDD/DVDD/DVDD18 電壓
- [ ] 確認 reset GPIO 極性與時序
- [ ] 讀取 0x300A + 0x300B 確認 ID
- [ ] dmesg 確認 "probe success"
- [ ] 用 media-ctl -p 確認完整管線
- [ ] 設定 format + 建 link
- [ ] v4l2-ctl 取一幀驗證 sizeimage
- [ ] 產出 bringup_log.txt(含所有指令輸出)
- [ ] 用「電源→clock→reset→I2C→media→出圖」序列除錯
- [ ] 確認 t_PW_UP 時序(reset 後等 10ms 再 I2C)
- [ ] 驗證 bring-up 可重現(重啟後複製流程)
看完這單元你應該能說出:
  • Bring-up 四件事。
  • 用 dmesg 追 probe/CSI 錯誤。
  • 透過 controls 與 i2c 讀 register。
  • 照決策樹排解。

延伸閱讀