第1篇|从零搭骨架:DriveOS/SIPL 相机模组适配需要哪些文件?
目标:看完后,知道适配一个新相机模组时该创建/修改哪些文件、每类文件负责什么、验证路径是什么。
开场:不要一上来就改寄存器,先把代码架构搭对
很多工程师第一次接触 DriveOS/SIPL 相机适配,会直接问:
sensor 初始化寄存器表写在哪里?
这个问题不算错,但顺序错了。
在 SIPL 里,一个相机模组能跑起来,至少需要三类东西先对上:
- Query 配置:告诉 SIPL "这个平台/模组/传感器是谁";
- devblk 驱动库:告诉 SIPL "具体生命周期怎么执行";
- TransportLink/SerDes 初始化:告诉系统"远端 serializer/deserializer 链路怎么拉起来"。
如果这三层没搭好,寄存器表写得再认真,也可能根本不会被执行。
一、SIPL 适配的最小文件地图
以 ISX031 + MAX96717F + MAX96712 为例,一个可维护的适配通常包含以下文件/目录:
text
nvsipl/
query/
database/
isx031_max96717f/
isx031.json
isx031_max96717f.json
isx031_max96717f_platform.json
database/
serdes/
max96712_max96717f.json 或已有 serdes 配置
devblk/
cameramodule/
MAX96712cameramodule/
CNvMTransportLink_Max96712_96717.cpp
isx031_max96717f/
CNvMMAX96712_96717F_ISX031.cpp
cdi_isx031.c
cdi_isx031.h
Makefile 或构建入口
你可以把它理解为:
#mermaid-svg-zA9CX5KKOYx6Vboj{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zA9CX5KKOYx6Vboj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zA9CX5KKOYx6Vboj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zA9CX5KKOYx6Vboj .error-icon{fill:#552222;}#mermaid-svg-zA9CX5KKOYx6Vboj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zA9CX5KKOYx6Vboj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zA9CX5KKOYx6Vboj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zA9CX5KKOYx6Vboj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zA9CX5KKOYx6Vboj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zA9CX5KKOYx6Vboj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zA9CX5KKOYx6Vboj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zA9CX5KKOYx6Vboj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zA9CX5KKOYx6Vboj .marker.cross{stroke:#333333;}#mermaid-svg-zA9CX5KKOYx6Vboj svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zA9CX5KKOYx6Vboj p{margin:0;}#mermaid-svg-zA9CX5KKOYx6Vboj .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-zA9CX5KKOYx6Vboj .cluster-label text{fill:#333;}#mermaid-svg-zA9CX5KKOYx6Vboj .cluster-label span{color:#333;}#mermaid-svg-zA9CX5KKOYx6Vboj .cluster-label span p{background-color:transparent;}#mermaid-svg-zA9CX5KKOYx6Vboj .label text,#mermaid-svg-zA9CX5KKOYx6Vboj span{fill:#333;color:#333;}#mermaid-svg-zA9CX5KKOYx6Vboj .node rect,#mermaid-svg-zA9CX5KKOYx6Vboj .node circle,#mermaid-svg-zA9CX5KKOYx6Vboj .node ellipse,#mermaid-svg-zA9CX5KKOYx6Vboj .node polygon,#mermaid-svg-zA9CX5KKOYx6Vboj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zA9CX5KKOYx6Vboj .rough-node .label text,#mermaid-svg-zA9CX5KKOYx6Vboj .node .label text,#mermaid-svg-zA9CX5KKOYx6Vboj .image-shape .label,#mermaid-svg-zA9CX5KKOYx6Vboj .icon-shape .label{text-anchor:middle;}#mermaid-svg-zA9CX5KKOYx6Vboj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zA9CX5KKOYx6Vboj .rough-node .label,#mermaid-svg-zA9CX5KKOYx6Vboj .node .label,#mermaid-svg-zA9CX5KKOYx6Vboj .image-shape .label,#mermaid-svg-zA9CX5KKOYx6Vboj .icon-shape .label{text-align:center;}#mermaid-svg-zA9CX5KKOYx6Vboj .node.clickable{cursor:pointer;}#mermaid-svg-zA9CX5KKOYx6Vboj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zA9CX5KKOYx6Vboj .arrowheadPath{fill:#333333;}#mermaid-svg-zA9CX5KKOYx6Vboj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zA9CX5KKOYx6Vboj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zA9CX5KKOYx6Vboj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zA9CX5KKOYx6Vboj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zA9CX5KKOYx6Vboj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zA9CX5KKOYx6Vboj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zA9CX5KKOYx6Vboj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zA9CX5KKOYx6Vboj .cluster text{fill:#333;}#mermaid-svg-zA9CX5KKOYx6Vboj .cluster span{color:#333;}#mermaid-svg-zA9CX5KKOYx6Vboj div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-zA9CX5KKOYx6Vboj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zA9CX5KKOYx6Vboj rect.text{fill:none;stroke-width:0;}#mermaid-svg-zA9CX5KKOYx6Vboj .icon-shape,#mermaid-svg-zA9CX5KKOYx6Vboj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zA9CX5KKOYx6Vboj .icon-shape p,#mermaid-svg-zA9CX5KKOYx6Vboj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zA9CX5KKOYx6Vboj .icon-shape .label rect,#mermaid-svg-zA9CX5KKOYx6Vboj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zA9CX5KKOYx6Vboj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zA9CX5KKOYx6Vboj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zA9CX5KKOYx6Vboj :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 平台配置 platform json
模块配置 module json
传感器配置 sensor json
SerDes 配置
devblk driver so
CameraModule 生命周期
TransportLink 链路初始化
Sensor CDI
二、Query 文件:让平台"被找到"
1)platform json:声明平台名和启用哪些 link
目的:让 nvsipl_camera --platform-config xxx 能找到你的平台。
通常需要填:
- 平台名,例如
ISX031_MAX96717F_RGGB_CPHY_x4; - 使用哪些 deserializer block;
- 每个 block 下挂哪些 camera module;
- 默认 link mask / module mask;
- 目标 sensor/module 名称。
如果这里没配对,现象通常是:平台名解析失败,或者运行时根本没有走到你的驱动。
2)module json:声明 sensor + serializer + deserializer 拓扑
目的:告诉 SIPL 这个 camera module 由哪些设备组成。
通常需要填:
- camera module 名称,例如
ISX031_MAX96717F_RGGB; - sensor 名称,例如
ISX031; - serializer 名称,例如
MAX96717F; - deserializer 名称,例如
MAX96712; - I2C 地址、广播地址、link id、port 等拓扑信息。
这层配错,常见现象是:driver 库能加载,但 serializer presence 或 translator 阶段失败。
3)sensor json:声明真实视频流属性
目的:告诉 SIPL 传感器输出的数据长什么样。
通常需要填:
- 分辨率;
- 帧率;
- 输出格式,例如 YUV422 / RAW;
- data type;
- embedded line 数;
- 是否启用 embedded data type;
- trigger/sync 相关模式。
注意:对于黑盒模组,sensor json 不是"随便照抄已有 sensor"的地方。它必须和真实输出流一致。否则可能出现 VIDEO_LOCK 成功但 ICP 报错。
三、devblk driver:让 SIPL 能加载你的实现
Query 只告诉 SIPL "有什么设备",真正执行初始化的是 devblk driver so。
关键产物类似:
text
libnvsipl_devblk_drv_isx031_max96717f.so
它内部通常包含:
- CameraModule 实现:
CNvMMAX96712_96717F_ISX031.cpp - TransportLink 实现:
CNvMTransportLink_Max96712_96717.cpp - Sensor CDI:
cdi_isx031.c - SerDes CDI:
cdi_max96717f.c/cdi_max96712.c
CameraModule 文件要做什么?
它负责生命周期编排:
DetectModule():检测模组是否存在;InitModule():初始化模块;StartModule():启动数据流;PostSensorInit():sensor init 后检查 link/video 状态。
对于黑盒模组,这里要决定一个核心策略:
是否把 sensor 当作可完全编程设备,还是把它当作 vendor-fixed 模组,只走 link-only 初始化。
四、TransportLink:真正拉起 MAX96717F/MAX96712 链路
TransportLink 是本项目最关键的执行层。
它通常负责:
- 检查 broadcast serializer 是否在线;
- 设置 translator A/B,让远端 I2C 地址可达;
- 配置 MAX96712/MAX96717F 的链路模式;
- 配置 pipeline / data type / mapping;
- 配置 FSYNC 或触发相关路径;
- 检查
GMSL2_LINK_LOCK; - 检查
PCLKDET; - 检查
VIDEO_LOCK。
如果模组是厂商黑盒,还可能需要补充 vendor-specific serializer bring-up 序列。
五、Sensor CDI:不一定总是主角
在传统 sensor 适配中,cdi_xxx.c 里常常包含:
- 读 model id;
- 写默认寄存器;
- 配置 mode;
- start/stop streaming。
但在 vendor-fixed 模组中,sensor CDI 可能只需要保留接口,并对部分动作做 bypass/no-op。
原因是:
- sensor 内部配置可能已由厂商固化;
- 外部 I2C 不一定开放完整 sensor 编程面;
- 成功标准应转移到 SerDes 链路和视频锁定。
这就是本系列后面会反复强调的 link-only 思维。
六、适配新模组时的推荐创建顺序
建议不要从 driver 代码乱改,而按这个顺序搭:
- 创建/修改 query platform json,让平台名可被解析;
- 创建/修改 module json,明确 sensor/serializer/deserializer 拓扑;
- 创建/修改 sensor json,声明真实流属性;
- 确认 query so 能构建并被加载;
- 创建 devblk driver 目录与 CameraModule 框架;
- 接入 TransportLink,先跑通 presence/translator/link lock;
- 再处理 PCLKDET/VIDEO_LOCK;
- 最后处理 ICP/fps/drop 等业务层验证。
#mermaid-svg-0xODwsaxliWVhdbU{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-0xODwsaxliWVhdbU .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-0xODwsaxliWVhdbU .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-0xODwsaxliWVhdbU .error-icon{fill:#552222;}#mermaid-svg-0xODwsaxliWVhdbU .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-0xODwsaxliWVhdbU .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-0xODwsaxliWVhdbU .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-0xODwsaxliWVhdbU .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-0xODwsaxliWVhdbU .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-0xODwsaxliWVhdbU .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-0xODwsaxliWVhdbU .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-0xODwsaxliWVhdbU .marker{fill:#333333;stroke:#333333;}#mermaid-svg-0xODwsaxliWVhdbU .marker.cross{stroke:#333333;}#mermaid-svg-0xODwsaxliWVhdbU svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-0xODwsaxliWVhdbU p{margin:0;}#mermaid-svg-0xODwsaxliWVhdbU .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-0xODwsaxliWVhdbU .cluster-label text{fill:#333;}#mermaid-svg-0xODwsaxliWVhdbU .cluster-label span{color:#333;}#mermaid-svg-0xODwsaxliWVhdbU .cluster-label span p{background-color:transparent;}#mermaid-svg-0xODwsaxliWVhdbU .label text,#mermaid-svg-0xODwsaxliWVhdbU span{fill:#333;color:#333;}#mermaid-svg-0xODwsaxliWVhdbU .node rect,#mermaid-svg-0xODwsaxliWVhdbU .node circle,#mermaid-svg-0xODwsaxliWVhdbU .node ellipse,#mermaid-svg-0xODwsaxliWVhdbU .node polygon,#mermaid-svg-0xODwsaxliWVhdbU .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-0xODwsaxliWVhdbU .rough-node .label text,#mermaid-svg-0xODwsaxliWVhdbU .node .label text,#mermaid-svg-0xODwsaxliWVhdbU .image-shape .label,#mermaid-svg-0xODwsaxliWVhdbU .icon-shape .label{text-anchor:middle;}#mermaid-svg-0xODwsaxliWVhdbU .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-0xODwsaxliWVhdbU .rough-node .label,#mermaid-svg-0xODwsaxliWVhdbU .node .label,#mermaid-svg-0xODwsaxliWVhdbU .image-shape .label,#mermaid-svg-0xODwsaxliWVhdbU .icon-shape .label{text-align:center;}#mermaid-svg-0xODwsaxliWVhdbU .node.clickable{cursor:pointer;}#mermaid-svg-0xODwsaxliWVhdbU .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-0xODwsaxliWVhdbU .arrowheadPath{fill:#333333;}#mermaid-svg-0xODwsaxliWVhdbU .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-0xODwsaxliWVhdbU .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-0xODwsaxliWVhdbU .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0xODwsaxliWVhdbU .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-0xODwsaxliWVhdbU .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0xODwsaxliWVhdbU .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-0xODwsaxliWVhdbU .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-0xODwsaxliWVhdbU .cluster text{fill:#333;}#mermaid-svg-0xODwsaxliWVhdbU .cluster span{color:#333;}#mermaid-svg-0xODwsaxliWVhdbU div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-0xODwsaxliWVhdbU .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-0xODwsaxliWVhdbU rect.text{fill:none;stroke-width:0;}#mermaid-svg-0xODwsaxliWVhdbU .icon-shape,#mermaid-svg-0xODwsaxliWVhdbU .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0xODwsaxliWVhdbU .icon-shape p,#mermaid-svg-0xODwsaxliWVhdbU .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-0xODwsaxliWVhdbU .icon-shape .label rect,#mermaid-svg-0xODwsaxliWVhdbU .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0xODwsaxliWVhdbU .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-0xODwsaxliWVhdbU .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-0xODwsaxliWVhdbU :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Query平台可见
拓扑描述正确
Driver可加载
SerDes链路打通
Video Lock成功
业务流稳定
七、本篇小结
如果你是陌生工程师,请先记住:
- SIPL 相机适配不是"只写一个 sensor 驱动";
- query 决定"系统如何认识你";
- devblk driver 决定"系统如何执行你";
- TransportLink 决定"链路能否真正打通";
- 黑盒模组下,sensor CDI 可能不是主路径。
本篇 checklist
- 知道 query/platform/module/sensor json 分别负责什么
- 知道 devblk driver so 中通常包含哪些代码文件
- 知道为什么黑盒模组要优先看 TransportLink
- 能按推荐顺序搭建一个新模组适配骨架
下篇预告
下一篇我们只讲 Query:
如何从 0 到 1 创建平台 json、module json、sensor json,让
nvsipl_camera能识别你的新模组?
系列导航卡片
- 当前进度:第 1/6 篇(文件骨架)
- 下一篇:第2篇《Query 配置从 0 到 1:让平台名、模组和视频流被 SIPL 正确认识》
- 本系列主线:文件骨架 → Query 配置 → devblk 驱动 → TransportLink 链路 → 部署验证 → 复盘方法论