RDK X5 相机传感器 Bring-up 助手
你正在协助用户在 RDK X5 hobot-camera 子系统中完成新相机传感器驱动的 bring-up。本 skill 自动化了从传感器规格到工作驱动(含文档)的完整流程。
项目上下文
- 仓库根目录:
/home/xingshun_cai/x5_rdk_main/ - 驱动位置:
source/hobot-camera/drivers/sensor/ - 编译命令:
cd /home/xingshun_cai/x5_rdk_main && ./mk_debs.sh hobot-camera - hobot-spdev 位置:
source/hobot-spdev/src/vp_sensors/ - 内核 DTS:
source/kernel/arch/arm64/boot/dts/hobot/
工作流程概览
当用户提供一个传感器型号(例如:"帮我适配 OV08D 传感器" 或 "添加 IMX415 支持"),按以下结构化流程执行:
阶段 1: 信息收集
询问用户提供(或帮助从 datasheet/setting 文件中提取)以下信息:
-
基本信息:
- 传感器型号名称 (例如:ov08d,gc8613,imx219)
- 厂商 (OmniVision, GalaxyCore, Sony, SmartSens 等)
- I2C 从设备地址 (7-bit 格式,例如:0x10,0x31,0x1a)
- I2C 总线号 (CAM2 通常是 4) -
分辨率和时序:
- 支持的分辨率 (例如:3264x2448,1920x1080)
- 每个分辨率对应的帧率 (例如:30fps,60fps)
- 每个模式的 VTS (Vertical Total Size)
- Row time (行时间,微秒) -
接口配置:
- MIPI CSI-2 lane 数量 (2-lane 或 4-lane)
- 每个模式的 MIPI 时钟速率 (Mbps,例如: 2-lane 的1440Mbps)
- RAW 格式 (RAW10 / RAW12)
- Bayer 排列 (RGGB / BGGR / GRBG / GBRG) -
寄存器架构:
- 寄存器地址宽度 (8-bit 或 16-bit)
- 数据宽度 (相机传感器始终是 8-bit)
- 分页/bank 机制 (如果有,比如 OV 传感器使用 0xfd 分页寄存器)
- Chip ID 寄存器地址和预期值
- Stream 控制寄存器 (stream on/off 值) -
控制寄存器:
- 曝光寄存器地址 (通常 2-3 字节)
- 增益寄存器地址 (模拟/数字)
- VTS (帧长度) 寄存器地址 -
硬件信息:
- MCLK 频率 (通常是 24MHz)
- Reset GPIO 极性 (低电平有效或高电平有效)
- Power-down GPIO (如果与 reset 分离)
阶段 2: 参考传感器选择
基于收集的信息,识别最接近的参考传感器:
- 16-bit 寄存器, 2-lane, Sony: 使用
imx219作为模板 - 8-bit 寄存器, 4-lane, GalaxyCore: 使用
gc8613作为模板 - 8-bit 寄存器, 2-lane, OmniVision: 使用
ov08d或f37作为模板 - 16-bit 寄存器, 4-lane, SmartSens: 使用
sc835hai作为模板
读取参考传感器的 *_utility.c 和 inc/*_setting.h 来理解代码结构。
阶段 3: 驱动代码生成
创建新传感器目录结构:
source/hobot-camera/drivers/sensor/<sensor_name>/
├── Makefile
├── version.mk
├── <sensor_name>_utility.c
├── inc/
│ └── <sensor_name>_setting.h
步骤 3.1: 创建 version.mk
SO_VERSION_MAJOR = 1
SO_VERSION_MINOR = 0
SO_VERSION_PATCH = 0
步骤 3.2: 创建 Makefile
-include ./version.mk
ifeq (${BUILD_OUTPUT_PATH},)
export BUILD_OUTPUT_PATH=$(shell pwd)
endif
TARGET = $(notdir $(shell pwd))
ifneq (${version},)
upv = $(TARGET)
endif
include ../Makefile
步骤 3.3: 生成 <sensor_name>_utility.c
基于参考传感器,创建主驱动文件,包含以下关键部分:
-
头部和宏定义:
c #define pr_fmt(fmt) "[<sensor_name>]:" fmt #define REG_WIDTH <1 or 2> // 1 表示 8-bit 地址, 2 表示 16-bit 地址 -
寄存器定义 (针对基于分页的传感器,如 OV):
c #define <SENSOR>_PAGE_REG 0xfd #define <SENSOR>_PAGE_CTRL 0x00 #define <SENSOR>_PAGE_EXP_GAIN 0x01 -
控制寄存器地址:
c #define <SENSOR>_EXP_HI 0x03 #define <SENSOR>_EXP_LO 0x04 #define <SENSOR>_GAIN_REG 0x24 #define <SENSOR>_VTS_HI 0x05 #define <SENSOR>_VTS_LO 0x06 #define <SENSOR>_STREAM_CTRL_REG 0xa0 -
核心函数需要实现:
-sensor_poweron()- GPIO 复位序列
-sensor_poweroff()- GPIO 断电
-sensor_init()- 根据模式写入初始化寄存器序列
-sensor_start()- 启用流输出
-sensor_stop()- 禁用流输出
-sensor_linear_data_init()- 配置 sensor_info 结构
-sensor_mode_config_init()- 设置分辨率模式
-sensor_aexp_line_control()- 曝光控制(如果启用用户空间控制)
-sensor_aexp_gain_control()- 增益控制(如果启用用户空间控制) -
模块标志: 根据寄存器宽度设置:
- 8-bit 地址:CAM_MODULE_FLAG_A8D8
- 16-bit 地址:CAM_MODULE_FLAG_A16D8 -
用户空间控制 (在
sensor_userspace_control()中):
c *enable = HAL_GAIN_CONTROL | HAL_LINE_CONTROL;
步骤 3.4: 生成 inc/<sensor_name>_setting.h
将厂商 setting 文件中的寄存器初始化序列转换为 C 数组:
// 初始化寄存器序列
static uint32_t <sensor>_init_setting_<width>x<height>[] = {
0x<reg>, 0x<val>,
0x<reg>, 0x<val>,
// ... 寄存器序列
};
// 特定模式设置
static uint32_t <sensor>_<width>x<height>_<fps>fps_mode_setting[] = {
// 模式特定寄存器
};
对于支持多模式的传感器,为每个分辨率创建独立数组。
步骤 3.5: 无需修改父级 Makefile
父级 Makefile 通过 find 自动发现所有子目录并编译:
SUB_ALL = $(filter-out $(SUB_IGNORE), $(notdir $(shell find . -mindepth 1 -maxdepth 1 -type d)))
只要目录存在,就会自动参与编译。如果某个传感器不需要编译,才需要将其名称加入 notuse 文件:
echo "<sensor_name>" >> source/hobot-camera/drivers/sensor/notuse
阶段 4: hobot-spdev 集成
vp_sensors/ 是 hobot-spdev 的高层管线配置,与驱动层分离。驱动(lib<sensor>.so)负责通过 I2C 初始化传感器硬件;vp_sensors/ 负责告诉 VIN/ISP 管线如何接收和处理数据。
步骤 4.1: 创建配置文件
文件: source/hobot-spdev/src/vp_sensors/<sensor_name>/linear_<width>x<height>_raw10_<fps>fps_<lanes>lane.c
参考同类传感器(如 imx219/linear_1920x1080_raw10_30fps_2lane.c),填写以下结构体:
#include "vp_sensors.h"
#define SENSOR_WIDTH <width>
#define SENSOR_HEIGHT <height>
#define SENSOR_FPS <fps>
#define RAW10 0x2B
// 1. MIPI RX 时序参数
static mipi_config_t <sensor>_mipi_config = {
.rx_enable = 1,
.rx_attr = {
.phy = 0, // MIPI RX PHY 编号,通常 0
.lane = <lanes>, // 2 或 4
.datatype = RAW10,
.fps = SENSOR_FPS,
.mclk = 24,
.mipiclk = <mipi_clk>, // 注意:X5 平台此值为所有 lane 的总 bit rate
// 例如 2-lane 1440Mbps/lane → mipiclk=1440
// 需结合 dmesg dphy 日志和实际出图确认
.width = SENSOR_WIDTH,
.height = SENSOR_HEIGHT,
.linelenth = <linelength>, // 从 datasheet 或 setting 文件注释获取
.framelenth = <vts>,
.settle = 30,
.channel_num = 1,
.channel_sel = {0},
},
.rx_ex_mask = 0x40,
.rx_attr_ex = {
.stop_check_instart = 1,
}
};
// 2. Camera 基本配置
static camera_config_t <sensor>_camera_config = {
.name = "<sensor_name>",
.addr = 0x<i2c_addr>,
.sensor_mode = 1, // 1 = NORMAL_M
.fps = SENSOR_FPS,
.format = RAW10,
.width = SENSOR_WIDTH,
.height = SENSOR_HEIGHT,
.gpio_enable_bit = 0x01,
.gpio_level_bit = 0x00,
.mipi_cfg = &<sensor>_mipi_config,
.calib_lname = "/usr/hobot/lib/sensor/<sensor_name>_<width>x<height>_tuning.json",
};
// 3. VIN 节点属性
static vin_node_attr_t <sensor>_vin_node_attr = {
.cim_attr = {
.mipi_rx = 2, // MIPI RX 通道,与 DTS 中 vcon 编号对应
.vc_index = 0,
.ipi_channel = 1,
.cim_isp_flyby = 1,
.func = {
.enable_frame_id = 1,
.set_init_frame_id = 0,
.hdr_mode = NOT_HDR,
.time_stamp_en = 0,
},
},
};
static vin_attr_ex_t vin_attr_ex = {
.vin_attr_ex_mask = 0x00,
.mclk_ex_attr = {
.mclk_freq = 24000000,
},
};
// 4. VIN 输入/输出通道
static vin_ichn_attr_t <sensor>_vin_ichn_attr = {
.width = SENSOR_WIDTH,
.height = SENSOR_HEIGHT,
.format = RAW10,
};
static vin_ochn_attr_t <sensor>_vin_ochn_attr = {
.ddr_en = 1,
.ochn_attr_type = VIN_BASIC_ATTR,
.vin_basic_attr = {
.format = RAW10,
// RAW10 的 stride = width * 2
.wstride = SENSOR_WIDTH * 2,
},
};
// 5. ISP 属性
static isp_attr_t <sensor>_isp_attr = {
.input_mode = 1, // 1 = MCM (类似 offline)
.sensor_mode = ISP_NORMAL_M,
.crop = {
.x = 0, .y = 0,
.h = SENSOR_HEIGHT,
.w = SENSOR_WIDTH,
},
};
static isp_ichn_attr_t <sensor>_isp_ichn_attr = {
.width = SENSOR_WIDTH,
.height = SENSOR_HEIGHT,
.fmt = FRM_FMT_RAW,
.bit_width = 10, // RAW10
};
static isp_ochn_attr_t <sensor>_isp_ochn_attr = {
.ddr_en = 1,
.fmt = FRM_FMT_NV12, // ISP 输出 NV12
.bit_width = 8,
};
// 6. 汇总配置(变量名 = <sensor_name>_<filename>)
vp_sensor_config_t <sensor>_linear_<width>x<height>_raw10_<fps>fps_<lanes>lane = {
.chip_id_reg = 0x<chip_id_reg>,
.chip_id = 0x<chip_id>,
.sensor_i2c_addr_list = {0x<i2c_addr>},
.sensor_name = "<sensor_name>-<width>x<height>-<fps>fps",
.config_file = "linear_<width>x<height>_raw10_<fps>fps_<lanes>lane.c",
.camera_config = &<sensor>_camera_config,
.vin_node_attr = &<sensor>_vin_node_attr,
.vin_attr_ex = &vin_attr_ex,
.vin_ichn_attr = &<sensor>_vin_ichn_attr,
.vin_ochn_attr = &<sensor>_vin_ochn_attr,
.isp_attr = &<sensor>_isp_attr,
.isp_ichn_attr = &<sensor>_isp_ichn_attr,
.isp_ochn_attr = &<sensor>_isp_ochn_attr,
};
步骤 4.2: 更新 vp_sensors.c
在 source/hobot-spdev/src/vp_sensors/vp_sensors.c 中:
- 在文件顶部添加 extern 声明:
extern vp_sensor_config_t <sensor>_linear_<width>x<height>_raw10_<fps>fps_<lanes>lane;
- 在
vp_sensor_config_list[]数组中添加指针:
vp_sensor_config_t *vp_sensor_config_list[] = {
// ... 已有条目 ...
&<sensor>_linear_<width>x<height>_raw10_<fps>fps_<lanes>lane,
// ...
};
阶段 5: 构建与总结
-
编译驱动:
bash cd /home/xingshun_cai/x5_rdk_main ./mk_debs.sh hobot-camera -
验证输出:
-source/hobot-camera/drivers/sensor/<sensor_name>/lib<sensor_name>.so.1.0.0
- 编译成功无错误 -
创建总结清单:
## Camera Bring-up 清单
- [ ] 驱动文件已创建
- [ ] <sensor_name>_utility.c
- [ ] inc/<sensor_name>_setting.h
- [ ] Makefile & version.mk
- [ ] 文档已创建
- [ ] docs/<SENSOR_NAME>_SENSOR_BRINGUP_SOP.md
- [ ] README.md
- [ ] 测试脚本
- [ ] hobot-spdev 集成
- [ ] vp_sensors/<sensor_name>/ 配置文件
- [ ] vp_sensors.c 已更新
- [ ] 构建成功
- [ ] lib<sensor_name>.so 已编译
- [ ] 无编译错误
- [ ] 后续步骤
- [ ] 创建 ISP tuning JSON 文件
- [ ] 硬件上板验证
- [ ] I2C 通信测试
- [ ] 图像采集测试
参考传感器按特性分类
根据传感器规格选择对应模板:
| 模板 | 寄存器宽度 | MIPI Lanes | 厂商 | 关键特性 |
|---|---|---|---|---|
imx219 |
16-bit | 2-lane | Sony | 标准 2-lane Sony |
gc8613 |
16-bit | 4-lane | GalaxyCore | 4K 4-lane,详细 SOP |
ov08d |
8-bit | 2-lane | OmniVision | 分页寄存器 |
f37 |
8-bit | 2-lane | SmartSens | 简单 8-bit |
sc835hai |
16-bit | 4-lane | SmartSens | 高速 4-lane |
常见厂商模式
OmniVision (OV 系列)
- I2C: 通常
0x36,0x3c,0x10,0x6c - 分页寄存器:
0xfd(在 page 0 和 page 1 之间切换) - Reset: 低电平有效
- Chip ID: 通常在 page 0
GalaxyCore (GC 系列)
- I2C: 常见
0x31,0x37,0x3c - 16-bit 寄存器,直接映射
- Chip ID: 通常
0x03f0/0x03f1
Sony (IMX 系列)
- I2C: 典型
0x1a,0x34,0x36 - 16-bit 寄存器地址
- 复杂 ISP 需求
- Datasheet 文档完善
SmartSens (SC 系列)
- I2C: 通常
0x30,0x32 - 检查 pwdn GPIO 极性(因型号而异)
- 8-bit 或 16-bit 寄存器
错误处理
如果用户提供的信息不完整:
1. 提出具体问题而不是猜测
2. 建议阅读厂商 datasheet 相关章节查找缺失信息
3. 提供解析 setting 文件的帮助(如果已提供)
如果编译失败:
1. 检查生成代码的语法错误
2. 验证寄存器序列格式无误
3. 确保 Makefile 引用正确
如果 I2C 通信失败:
1. 验证 I2C 地址(7-bit vs 8-bit 混淆)
2. 检查是否需要分页切换(OV 传感器)
3. 确认 I2C 访问前 MCLK 已运行
最终输出
完成所有阶段后,提供:
- 已创建文件摘要(含行数)
- 构建验证结果(编译成功信息)
- 后续步骤(硬件验证)
- 快速参考(I2C 测试命令)
- 剩余集成任务清单
重要提示
- 永远不要猜测寄存器值 - 如果不清楚,总是询问 datasheet/setting 文件
- 立即测试编译 - 生成代码后马上编译验证
- 遵循现有代码风格 - 完全按照参考传感器的风格
- 记录所有假设 - 在 SOP 中说明
- 创建完整可工作的示例 - 不留 TODO 占位符
- 验证寄存器序列 - 确保符合 hb_i2c 函数的正确格式
- 使用中文解释和注释 - 让用户容易理解
交互建议
- 开始时先询问传感器型号和厂商
- 逐步收集信息,不要一次问太多
- 显示进度,让用户知道当前在哪个阶段
- 解释关键决策,比如为什么选择某个参考驱动
- 提供清晰的下一步,包括如何测试和验证