V4L2 subdev、ov5640.c
s_power、s_stream、s_ctrl…media-ctl -p -d /dev/media0 # 列出所有實體與連結 v4l2-ctl --list-devices # 對應的 /dev/videoX v4l2-ctl -d /dev/v4l-subdev0 --list-ctrls # 列出感測器 controls
ov5640.c 這類 subdev 驅動不是「直接被使用者呼叫」,而是掛在 media graph 上由管線控制器驅動。它的核心回呼(v4l2_subdev_ops)對應感測器硬體狀態:
| subdev op | 觸發時機 | OV5640 內部行為 |
|---|---|---|
| init_cfg / set_fmt | media-ctl 設定格式 | 切解析度/時序 table |
| s_power(1) | 開電源 | 上電時序、跑 init table |
| s_stream(1) | 開始串流 | 設 MIPI 輸出、開始出圖 |
| s_ctrl | v4l2-ctl 改 control | 寫對應 register(曝光/增益/白平衡) |
一個完整的相機管線是「圖」不是「鏈」:
每個節點在 kernel 是 struct media_entity;連結 struct media_link。使用者透過 /dev/media0 與 media-ctl 操作圖,透過 /dev/v4l-subdevN 與 subdev 溝通,透過 /dev/videoN 拿資料。
media-ctl -p -d /dev/media0
v4l2-ctl --list-devices
v4l2-ctl -d /dev/v4l-subdev0 --list-ctrls
cat /sys/class/video4linux/video0/name # device name readlink -f /sys/class/video4linux/video0/device # 對應 DT 節點
| 現象 | 可能原因 | 檢查 |
|---|---|---|
media-ctl -p 只有感測器沒有 video | 管線後端未 probe / ISP 驅動沒載入 | dmesg 看 csi/isp 錯誤 |
--list-ctrls 沒列出曝光/增益 | 驅動沒實作該 control / 模式不同 | 切到另一解析度再列 |
| 改 control 回傳 EINVAL | 值超出 min/max 或格式不符 | 看 --list-ctrls 的範圍 |
| video 節點拿不到 buffer | 管線 link 未建 / 格式不符 | media-ctl 建 link 並統一格式 |
/dev/video0 誤當感測器——感測器是 /dev/v4l-subdev*,兩者 API 不同;② 在沒有平台 ISP 的板卡上想找「ISP 節點」——H618/H616 多半沒有,別浪費時間;③ 用 v4l2-ctl -d /dev/video0 控制感測器——那會設定 video 節點而非 subdev。readlink -f /sys/class/video4linux/video0/device # 指向 DT 節點 cat /sys/class/video4linux/video0/name # 節點名稱 cat /sys/bus/i2c/devices/3-003c/name # 感測器 i2c device name
media-ctl -p 的輸出與預期不符,先看 /sys 確認驅動真的綁定到硬體。綁定成功才談管線。--list-ctrls 找出曝光、增益、白平衡的 id/範圍/單位。ov5640.c 的 s_stream,讀它做了哪三件事。場景:Orange Pi 5(RK3588)probe 成功但 v4l2-ctl --list-devices 沒出現預期的 video device,需要從 /sys 追蹤驅動綁定鏈。
cat /sys/class/video4linux/video0/name readlink -f /sys/class/video4linux/video0/device ls -la /sys/bus/platform/devices/*/video4linux/
ls /sys/bus/i2c/devices/
cat /sys/bus/i2c/devices/3-003c/name # 應為 "ov5640"
readlink -f /sys/bus/i2c/devices/3-003c/drivermedia-ctl -p -d /dev/media0 2>/dev/null | grep "entity"
# 正常應有 sensor + csi + (isp) + video = 3~5 entitiesv4l2-ctl --list-devices 沒出現 video device 時,問題通常不在驅動本身,而在 DT 的 media controller 設定——RK3588 需要 DT 同時啟用 sensor subdev + CSI receiver + video device 三個 entity。RK3588 的 RGA(Raster Graphic Acceleration)是一個常被誤解的模組:
| 模組 | 介面 | media graph 內? | 用途 |
|---|---|---|---|
| ISP3 | V4L2 subdev | ✅ 是 | RAW → YUV 管線 |
| RGA | /dev/rga IOCTL | ❌ 否 | 即時旋轉/縮放/color convert |
| CIF | V4L2 video device | ✅ 是 | Allwinner MIPI 接收 |
容易忽略的邊界案例:如果你在 GStreamer 管線中用 rga element,它在底層走的是 /dev/rga 而非 V4L2 media graph——所以 media-ctl -p 看不到 RGA 的設定。若 RGA 的格式與 ISP 輸出不匹配,GStreamer 會靜默失敗而非報錯。
rga_test(Rockchip 工具)測試 RGA 是否能正確轉換格式,再回頭查 GStreamer 管線。| 症狀 | 可能原因 | 解決方案 |
|---|---|---|
media-ctl -p 只有 sensor 沒有 csi/video | DT 未啟用 CSI receiver 或 video device 節點 | 在 DT overlay 中加入 csi2 + video device 節點 |
--list-ctrls 只有 brightness 沒有 exposure | 驅動未實作 V4L2_CID_EXPOSURE | 查 ov5640.c 的 ov5640_ctrls 陣列確認是否包含 |
| subdev 有 controls 但設值回 EINVAL | 值超出 min/max/step 範圍 | 先 --list-ctrls 看 min/max/step/default |
video device 存在但 media-ctl -p 無 video entity | media controller 與 V4L2 device 未綁定 | 確認 DT 中 video device 節點有 ports 和 port/endpoint |
RK3588 ISP node 存在但 media-ctl -l 失敗 | ISP subdev 未 probe 或 lane 數不符 | dmesg 搜 rkisp 確認 probe;檢查 CSI lane 數 DT 設定 |
media-ctl -p 的輸出。/sys/class/video4linux/ 的資訊,寫一支 script 自動產出「video device → DT 節點 → 驅動」的對照表。v4l2-ctl -d /dev/v4l-subdev0 與 v4l2-ctl -d /dev/video0 對同一個 control(如 exposure)的差異,解釋為什麼 API 不同。把單元 4 的 subdev 知識做成可交付的盤點工具:自動建立「video device → subdev → DT 節點 → 驅動」完整對照表。這是跨平台移植、多人協作除錯時的「單一事實來源」。
for d in /sys/class/video4linux/*; do name=$(basename $d) devname=$(cat $d/name) dt=$(readlink -f $d/device) echo "$name | $devname | $dt" done
media-ctl -p -d /dev/media0 | grep -E "entity|type|device node" | head -30
v4l2-ctl -d /dev/v4l-subdev0 --list-ctrls
#!/bin/bash echo "===== 平台相機節點盤點表 $(date) =====" echo "--- video devices ---" v4l2-ctl --list-devices echo "--- i2c devices bound to ov5640 ---" ls -la /sys/bus/i2c/devices/ | grep -i ov echo "--- driver ---" readlink -f /sys/bus/i2c/devices/*/driver 2>/dev/null | grep -i ov
camera_inventory.sh,跑一次就產出完整盤點表。把輸出存進 repo,任何人接手都能在 5 分鐘內看懂這片板卡的相機系統架構。| 步驟 | 指令 | 通過判據 |
|---|---|---|
| 1. 節點存在性 | ls /dev/v4l-subdev* /dev/video* | 節點存在 |
| 2. 驅動綁定 | readlink -f /sys/bus/i2c/devices/*/driver | 指向 ov5640 驅動 |
| 3. entity 數量 | media-ctl -p -d /dev/media0 | sensor + csi + (isp) + video 齊全 |
| 4. controls 可用 | v4l2-ctl -d /dev/v4l-subdev0 --list-ctrls | 有 exposure/gain/white_balance |
| 5. 控制生效 | -c exposure=2000 後 -C exposure | 讀回與設定一致 |
| 面向 | Orange Pi | RPi5 | Orin Nano | Thor |
|---|---|---|---|---|
| 框架 | V4L2 + media controller | libcamera | tegracam + Argus | Holoscan + GXF |
| 感測器驅動 | ov5640.c(mainline) | libcamera 驅動 + IPA | NVIDIA 封閉驅動 | NVIDIA 封閉驅動 |
| subdev 節點 | /dev/v4l-subdevN | libcamera 抽象(無直接節點) | 內部抽象 | 內部抽象 |
| controls | V4L2_CID_* | libcamera controls | Argus SensorMode | Holoscan 參數 |
| 可移植性 | Linux 標準,最通用 | RPi 專屬但開源 | NVIDIA 專屬 | NVIDIA 新世代 |
- [ ] 我能跑出 camera_inventory.sh 並產出完整盤點表。 - [ ] 我能指出 video 節點與 subdev 節點的 API 差異。 - [ ] 我已從 /sys 追蹤出 OV5640 的驅動綁定鏈。 - [ ] 我能列出本平台感測器的全部 controls 與範圍。 - [ ] 我了解 libcamera / Argus / V4L2 之間的抽象層差異。 - [ ] 我能從「media graph 不完整」反推是驅動還是 DT 問題。
V4L2 subdev 的控制介面是 register 的高階抽象。以下是以 OV5640 為例的位元級操作序列:
| 步驟 | V4L2 控制 | register 對應 | 操作 | 預期值 |
|---|---|---|---|---|
| 1. 查 controls | v4l2-ctl -l | — | v4l2-ctl -d /dev/v4l-subdev0 -l | 列出所有控制項 |
| 2. 讀曝光值 | exposure | 0x3500/0x3501/0x3502 | v4l2-ctl -d subdev0 --get-ctrl=exposure | 依場景 |
| 3. 寫曝光值 | exposure | 同上 | v4l2-ctl -d subdev0 --set-ctrl=exposure=500 | 值已設定 |
| 4. 驗證 register | i2cget | 0x3500~0x3502 | i2cget -y 3 0x3c 0x3500 | 對應 high byte |
| 5. 查 media graph | media-ctl -p | — | media-ctl -p -d /dev/media0 | entities + links |
| 6. 建 link | media-ctl -l | — | media-ctl -l "...:0->...:0[1]" | link 設為 active |
決策樹 A:media graph 不完整
media-ctl -p 有 sensor entity 嗎? ├─ 無 → DT 未描述 sensor 節點 │ ├─ 檢查 DT overlay 是否含 i2c + sensor │ └─ 檢查 compatible 字串是否匹配驅動 ├─ 有但缺 link → 驅動未建 link │ ├─ 手動建:media-ctl -l "..." │ └─ 檢查 DT 的 port/endpoint 描述 └─ 有 link 但缺 format → 需手動設定 └─ media-ctl -V "...:0[fmt:SRGGB10_1X10/1920x1080]"
決策樹 B:controls 找不到
v4l2-ctl -l 無控制項? ├─ subdev 節點不存在 → 驅動未 probe │ └─ dmesg 看 probe 失敗原因 ├─ subdev 存在但無 controls → 驅動未暴露 │ └─ 檢查 ov5640.c 的 .s_ctrl 實作 └─ controls 有但 set 失敗 → register 被鎖 └─ 檢查 AEC/AGC auto 模式是否覆蓋手動
| 步驟 | 指令 | 預期輸出 | 判讀標準 |
|---|---|---|---|
| 1. 列出 subdev | ls /dev/v4l-subdev* | subdev0..N | 數量與 DT 一致 |
| 2. 查 controls | v4l2-ctl -d /dev/v4l-subdev0 -l | 列出 V4L2_CID_* | 含 exposure/gain/... |
| 3. 讀 media graph | media-ctl -p -d /dev/media0 | entities + links | sensor → csi → video |
| 4. 設定 format | media-ctl -V "...:0[fmt:SRGGB10_1X10/1920x1080]" | 格式設定成功 | match sensor 能力 |
| 5. 建 link | media-ctl -l "...:0->...:0[1]" | link 設為 active | 正確的 pad 端點 |
| 6. 驗證控制 | v4l2-ctl -d subdev0 --set-ctrl=exposure=500 | 值已設定 | 回讀確認 |
| 面向 | Orange Pi | RPi5 | Orin Nano | Thor | 推薦 |
|---|---|---|---|---|---|
| 驅動框架 | V4L2 subdev | libcamera | NVIDIA 自有 | Holoscan | 底層→V4L2 |
| subdev 節點 | /dev/v4l-subdevN | libcamera 抽象 | 內部抽象 | 內部抽象 | 除錯→Orange Pi |
| controls | V4L2_CID_* | libcamera controls | Argus SensorMode | Holoscan 參數 | 底層→V4L2 |
| media controller | ✅ 開放 | libcamera 抽象 | 封閉 | 封閉 | 學習→Orange Pi |
| 可移植性 | Linux 標準 | RPi 專屬但開源 | NVIDIA 專屬 | NVIDIA 新世代 | 通用→V4L2 |
- [ ] 確認所有 /dev/v4l-subdev* 節點存在 - [ ] 用 v4l2-ctl -l 列出全部 controls 與範圍 - [ ] 用 media-ctl -p 確認完整 media graph - [ ] 手動建 link 並設定 format - [ ] 用 v4l2-ctl 設定 exposure 並回讀驗證 - [ ] 追蹤 /sys 下的驅動綁定鏈 - [ ] 產出「platform inventory」(subdev/video/controls/media) - [ ] 確認 libcamera / Argus / V4L2 的抽象差異 - [ ] 驗證 DT overlay 描述與實際 media graph 一致 - [ ] 用 dmesg 追蹤 probe 回呼序列