摄像头驱动与 ISP
本文档介绍 AC792N SDK 中摄像头(Camera)设备驱动与 ISP(图像信号处理器)子系统的整体架构、接口定义、数据流与控制流,涵盖从传感器(Sensor)采集、DVP/CSI2 接口传输、ISP 图像处理到视频帧输出的完整链路。
Purpose and Scope
本页面覆盖 AC792N SDK 中"摄像头驱动与 ISP"这一完整能力域,包括:
- 摄像头设备抽象层(
camera.h)——平台数据结构、设备枚举、ioctl 命令与驱动 API; - ISP 接口层(
isp.h)——ISP 工作模式、通用/定制配置命令、IOCTL 通道; - 视频链路相关头文件(
video.h、video_ioctl.h、videobuf.h、fb.h、dec_stream.h、usb_cam_dev.h)在链路中的角色; - 应用层示例(
isp_scenes.c、isp_tools.c)与具体传感器驱动(nt99141.c、TVP5150A_DVP.c)的接线方式。
以下相关主题属于兄弟页面,不在本页展开:视频编解码流(dec_stream)、帧缓冲显示(fb/LVGL 显示移植)、USB UVC 摄像头协议细节、WiFi 摄像头应用整体流程。
概述
在 AC792N 这类 SoC 上,摄像头子系统是"传感器 → 物理接口 → ISP → 视频管道"的串行链路。SDK 通过统一的设备模型(struct device_operations)把摄像头抽象为可挂载、可打开、可 ioctl 的标准设备,同时把 ISP 抽象为独立的通道化图像处理器。
核心设计意图:
- 接口与传感器解耦:应用层只面向
camera_init()/camera_driver_open()/camera_driver_ioctl()等统一 API,具体传感器(NT99141、TVP5150A 等)的差异被收敛到camera_platform_data平台数据与传感器驱动内部,更换传感器不需要改动上层业务。 - 接口类型统一:DVP(并行数字视频端口)、CSI2(MIPI 串行摄像头接口)、MCV(多通道视频)共用同一套
camera_platform_data,通过interface字段区分,并以内嵌 union 承载各自专用配置。 - ISP 通道化:ISP 支持录制(
ISP_MODE_REC)与拍照(ISP_MODE_IMAGE_CAPTURE)两种模式,通过isp_ioctl()下发isp_generic_cfg/ispt_customize_cfg,既可走通用参数(EV、白平衡、锐度、DRC),也可走工具/文件/专用定制通道,兼顾易用与灵活性。 - 裁剪与重挂载:摄像头提供 crop(裁剪)与 remount(重挂载)命令,支持在运行期调整输出尺寸。
架构
flowchart TD
subgraph sg_App["应用层 (sdk/apps/common/camera)"]
ISP_Tools["isp_tools.c / isp_scenes.c"]
Sensor_NT["nt99141.c 传感器驱动"]
Sensor_TVP["TVP5150A_DVP.c 传感器驱动"]
App["业务应用 (wifi_camera 等)"]
end
subgraph sg_Driver["驱动接口层 (sdk/include_lib/driver/device/video)"]
CameraH["camera.h 摄像头设备接口"]
IspH["isp.h ISP 接口"]
VideoH["video.h / video_ioctl.h"]
Videobuf["videobuf.h 视频缓冲"]
FbH["fb.h 帧缓冲"]
DecStream["dec_stream.h 解码流"]
UsbCam["usb_cam_dev.h USB 摄像头"]
end
subgraph sg_Hw["硬件链路"]
DVP["DVP 并行接口 (DVP0/DVP1)"]
CSI2["CSI2 MIPI 接口 (x0~x4 lane)"]
MCV["MCV 多通道视频"]
ISP["ISP 图像信号处理器"]
SensorHW["CMOS 传感器 (NT99141/TVP5150A)"]
end
App --> CameraH
App --> IspH
ISP_Tools --> IspH
Sensor_NT --> CameraH
Sensor_TVP --> CameraH
CameraH -->|"camera_platform_data.interface"| DVP
CameraH -->|"camera_platform_data.interface"| CSI2
CameraH -->|"camera_platform_data.interface"| MCV
DVP --> SensorHW
CSI2 --> SensorHW
DVP --> ISP
CSI2 --> ISP
ISP --> Videobuf
ISP --> FbH
Videobuf --> DecStream
UsbCam --> VideoH
架构说明:
- 应用层通过
camera.h暴露的设备接口打开摄像头、下发 ioctl;通过isp.h暴露的接口配置 ISP 图像参数(场景、EV、白平衡等)。isp_scenes.c/isp_tools.c封装了常用场景参数,是应用与 ISP 之间的便捷桥梁。 - 驱动接口层是 SDK 提供给应用的头文件集合,
camera.h与isp.h是核心;video.h/video_ioctl.h定义视频流设备;videobuf.h描述视频缓冲管理;fb.h面向显示;dec_stream.h面向解码流;usb_cam_dev.h面向 USB UVC 摄像头。 - 硬件链路中,传感器通过 DVP 或 CSI2 把原始 Bayer 数据送入 ISP;ISP 完成降噪、锐化、色彩校正(CCM)、Gamma、DRC 等处理后输出标准视频帧,进入 videobuf/fb 管道。
摄像头驱动层(camera.h)
设备标签与接口类型
camera.h 通过 VIDEO_TAG 宏为不同视频源打标签,并定义物理接口枚举:
#define VIDEO_TAG_CAMERA VIDEO_TAG('c', 'a', 'm', 'e')
#define VIDEO_TAG_UVC VIDEO_TAG('u', 'v', 'c', ' ')
#define VIDEO_TAG_MASS VIDEO_TAG('m', 'a', 's', 's')
#define ENDPOINT_NUM 5
#define CAMERA_DEVICE_NUM 13
#define CSI2_X0_LANE 0
#define CSI2_X1_LANE 1
#define CSI2_X2_LANE 2
#define CSI2_X3_LANE 3
#define CSI2_X4_LANE 4
#define DVP0_INTERFACE 0
#define DVP1_INTERFACE 1
#define CSI2_INTERFACE 2
#define MCV0_INTERFACE 4 //修改序号需要修改跟之相关的逻辑(非作者本人勿动)
#define MCV1_INTERFACE 5
#define MCV2_INTERFACE 6
#define MCV3_INTERFACE 7
来源:camera.h
设计意图:interface 字段用整数枚举区分物理传输方式——DVP 是并行总线(PCLK/HSYNC/VSYNC + 数据线),CSI2 是 MIPI 串行差分总线(最多 4 条 data lane),MCV 是多通道视频端口。枚举值 0/1/2/4~7 之间预留了 3(原 UVC 接口,被注释掉),注释特别警告 MCV 序号与相关逻辑耦合,修改需谨慎。
camera_platform_data:传感器平台配置
这是把一块具体传感器接到 SoC 上的"接线说明书":
struct camera_platform_data {
char *iic_sel;
u8 xclk_gpio;
u8 reset_gpio;
u8 pwdn_gpio;
u8 power_value;
u32 interface;
bool (*online_detect)();
union {
struct {
u32 pclk_gpio;
u32 hsync_gpio;
u32 vsync_gpio;
u8 group_port; //DVP0 0: PD9~PE2 1: PA4~PA11 DVP1 0: PB0_PB7 1: PB8_PB15
u8 reverse; //0: 正序 1: 反序
u8 shift; //数据位偏移量
u8 timing_mode; //时序选择 0:DVP 1:BT601 2:VSYNC 3:BT656
u8 scan_mode; //扫描模式 0:逐行扫描(default) 1:奇场数据 2:偶场数据
u8 width_mode; //位宽选择 0:全位宽(8/10bit) 1: 4bit 2: 2bit 3: 1bit
u32 h_blank; //水平消隐后肩周期数, 默认填0
u32 v_blank; //垂直消隐后肩行数, 默认填0
u32 data_gpio[10];
} dvp;
struct {
u8 data_lane_num;
u8 clk_rmap;
u8 clk_inv;
u8 d0_rmap;
u8 d0_inv;
u8 d1_rmap;
u8 d1_inv;
u8 d2_rmap;
u8 d2_inv;
u8 d3_rmap;
u8 d3_inv;
u8 tval_hstt;
u8 tval_stto;
} csi2;
};
};
来源:camera.h
结构设计要点:
- 公共字段:
iic_sel(传感器寄存器读写用的 I2C 控制器选择)、xclk_gpio(主时钟输出脚)、reset_gpio/pwdn_gpio(复位/掉电控制)、power_value(供电电压档位)、interface(选择 DVP/CSI2/MCV)、online_detect()(在线检测回调,用于热插拔判断)。 - 联合体:DVP 与 CSI2 配置互斥存放。DVP 需要声明 PCLK/HSYNC/VSYNC 引脚、端口分组(
group_port)、数据位序(reverse)、位偏移(shift)、时序模式(BT601/BT656/VSYNC)、扫描模式(逐行/奇偶场)、位宽(8/10/4/2/1 bit)以及最多 10 根数据 GPIO;CSI2 需要声明 lane 数、时钟与各 lane 的映射(rmap)与极性反转(inv)、以及tval_hstt/tval_stto时序参数。 - 配套宏
CAMERA_PLATFORM_DATA_BEGIN(data)/CAMERA_PLATFORM_DATA_END()用于以静态 const 方式简洁地初始化平台数据。
摄像头 ioctl 命令与驱动 API
命令集合
摄像头驱动以 CAMERA_CMD_BASE (0x00400000) 为基址定义运行期控制命令:
#define CAMERA_CMD_BASE 0x00400000
#define CAMERA_GET_ISP_SRC_SIZE (CAMERA_CMD_BASE + 1)
#define CAMERA_GET_ISP_SIZE (CAMERA_CMD_BASE + 2)
#define CAMERA_SET_CROP_SIZE (CAMERA_CMD_BASE + 3)
#define CAMERA_CROP_TRIG (CAMERA_CMD_BASE + 4)
#define CAMERA_NEED_REMOUNT (CAMERA_CMD_BASE + 5)
#define CAMERA_GET_SENSOR_ID (CAMERA_CMD_BASE + 6)
#define CAMERA_GET_CAPTURE_RAW (CAMERA_CMD_BASE + 7)
#define CAMERA_SET_TEST_KICK (CAMERA_CMD_BASE + 8)
#define CAMERA_GET_TEST_DONE (CAMERA_CMD_BASE + 9)
来源:camera.h
| 命令 | 方向 | 用途 |
|---|---|---|
CAMERA_GET_ISP_SRC_SIZE | 查询 | 获取 ISP 输入(传感器原始)尺寸 |
CAMERA_GET_ISP_SIZE | 查询 | 获取 ISP 输出尺寸 |
CAMERA_SET_CROP_SIZE | 设置 | 设置裁剪窗口尺寸 |
CAMERA_CROP_TRIG | 触发 | 触发裁剪生效 |
CAMERA_NEED_REMOUNT | 查询/设置 | 请求视频设备重挂载(尺寸变更后重建管道) |
CAMERA_GET_SENSOR_ID | 查询 | 读取传感器 ID(用于识别 sensor 型号) |
CAMERA_GET_CAPTURE_RAW | 查询 | 获取 RAW 抓拍缓冲 |
CAMERA_SET_TEST_KICK | 触发 | 触发产测动作 |
CAMERA_GET_TEST_DONE | 查询 | 查询产测完成状态 |
这些命令通过 camera_driver_ioctl() 统一下发,业务代码无需关心具体寄存器,做到了"应用层只发语义命令、驱动层负责翻译成硬件操作"。
驱动 API
extern const struct device_operations camera_dev_ops;
int camera_init(const char *name, void *camera_data);
void *camera_driver_open(int id, struct camera_device_info *info);
int camera_driver_close(void *_camera);
int camera_driver_force_close(void *_camera);
int camera_driver_ioctl(void *_camera, u32 cmd, void *arg);
来源:camera.h
camera_dev_ops:标准设备操作表(open/close/ioctl 等),供系统设备框架挂载camera设备节点。camera_init(name, camera_data):注册一个摄像头设备,name是设备名,camera_data指向camera_platform_data。camera_driver_open(id, info):按id(0~CAMERA_DEVICE_NUM-1)打开摄像头,返回驱动句柄;info(struct camera_device_info)回传当前帧率与分辨率(fps、sen_width、sen_height、width、height、real_fps)。camera_driver_close/camera_driver_force_close:正常关闭与强制关闭(后者用于异常路径兜底)。camera_driver_ioctl(handle, cmd, arg):下发上述命令集。
camera_device_info 结构(camera.h#L79-L86)把传感器尺寸(sen_width/sen_height)与输出尺寸(width/height)分开描述——这正是 ISP 裁剪能力的体现:传感器输出可以大于应用需要的最终尺寸。
ISP 接口层(isp.h)
工作模式
enum isp_mode {
ISP_MODE_NONE = 0x0,
ISP_MODE_REC,
ISP_MODE_IMAGE_CAPTURE,
};
enum {
ISP_CFG_MODE_GENERIC = 0x0,
ISP_CFG_MODE_CUSTOMIZE,
};
来源:isp.h
ISP_MODE_REC:录制模式,面向视频流实时处理(预览/录像)。ISP_MODE_IMAGE_CAPTURE:拍照模式,面向静态图像质量优先。- 配置模式
ISP_CFG_MODE_GENERIC(通用参数)与ISP_CFG_MODE_CUSTOMIZE(定制参数)决定isp_ioctl走哪套数据结构。
命令集
通用命令(3A/图像基础参数):
enum isp_generic_cmd {
ISP_SET_INPUT_SIZE = 0x4A4C0000,
ISP_SET_OUTPUT_SIZE,
ISP_SET_MODE,
ISP_SET_EV,
ISP_SET_WB,
ISP_SET_SHP,
ISP_SET_DRC,
ISP_GET_LV,
ISP_GET_FREQ,
ISP_GET_SEN_STATUS,
ISP_GET_VISGNAL,
ISP_GET_SEN_SIZE,
ISP_GET_ISP_SIZE,
};
来源:isp.h
特殊命令(图像画质细调):
enum isp_special_cmd {
ISP_SET_CCM,
ISP_SET_NR,
ISP_SET_SHPN,
ISP_SET_SATURATION,
ISP_SET_GAMMA,
ISP_SET_BRIGHTNESS,
ISP_SET_CONTRAST,
};
来源:isp.h
定制模式来源:
#define ISP_CUSTOMIZE_MODE_TOOL 0x1
#define ISP_CUSTOMIZE_MODE_FILE 0x2
#define ISP_CUSTOMIZE_MODE_SPECIAL 0x3
来源:isp.h
数据结构与 IOCTL
isp_generic_cfg 是通用配置的载体——一条结构同时携带命令字、通道号、3A 参数与输入/输出/传感器三组格式:
struct isp_pix_format {
u32 fps;
u16 width;
u16 height;
};
struct isp_generic_cfg {
u32 cmd;
u8 channel;
u8 mode;
u8 sen_status;
u8 vsignal;
s8 ev;
u8 white_blance;
u8 sharpness;
u8 drc;
s32 lv;
struct isp_pix_format in_fmt;
struct isp_pix_format out_fmt;
struct isp_pix_format sen_fmt;
};
来源:isp.h
ispt_customize_cfg 则用于传递不定长的定制数据块(如从 ISP 工具导出的寄存器表、参数文件),带版本号与 CRC 校验:
struct ispt_customize_cfg {
u8 mode;
u8 channel;
u8 cmd;
u8 *data;
int len;
u16 version;
u16 crc;
void *private;
};
来源:isp.h
IOCTL 命令宏与导出函数:
#define ISP_IOCTL_SET_GENERIC_CFG _IOW('I', 0, struct isp_generic_cfg)
#define ISP_IOCTL_GET_GENERIC_CFG _IOR('I', 1, struct isp_generic_cfg)
#define ISP_IOCTL_SET_CUSTOMIZE_CFG _IOW('I', 2, struct ispt_customize_cfg)
#define ISP_IOCTL_GET_CUSTOMIZE_CFG _IOR('I', 3, struct ispt_customize_cfg)
#define ISP_IOCTL_SET_FPS _IOW('I', 4, int)
s32 isp0_mount(void *arg);
void isp_dump_reg();
int isp_delete(int channel);
s32 isp0_ioctrl(void *parm, u32 cmd);
int isp_ioctl(u32 cmd, void *arg);
来源:isp.h
设计意图:ISP_IOCTL_SET_GENERIC_CFG 走通用路径(适合日常调节),ISP_IOCTL_SET_CUSTOMIZE_CFG 走定制路径(适合产线校准/ISP 工具联调)。isp0_ioctrl / isp0_mount 是通道 0 的设备回调,isp_ioctl 是应用层统一入口;isp_dump_reg() 用于调试时导出寄存器;isp_delete(channel) 用于销毁指定 ISP 通道。
核心流程
摄像头打开与 ISP 配置流程
sequenceDiagram
participant App as 业务应用
participant Cam as camera 驱动 (camera_dev_ops)
participant Plat as camera_platform_data
participant Sen as 传感器驱动 (nt99141/TVP5150A)
participant ISP as ISP 通道 (isp0)
participant VB as videobuf 视频管道
App->>Cam: camera_init("cam0", &platform_data)
Cam->>Plat: 读取 iic_sel/xclk_gpio/reset_gpio/interface
App->>Cam: camera_driver_open(id, &info)
Cam->>Sen: 上电 (xclk/reset/pwdn) + I2C 初始化
Sen-->>Cam: 回读 sensor ID 确认
Cam->>ISP: 按 interface 配置 DVP/CSI2 时序
ISP-->>Cam: 建立 ISP 通道 (in/out/sen fmt)
Cam-->>App: 返回句柄 + camera_device_info(fps/width/height)
App->>ISP: isp_ioctl(ISP_IOCTL_SET_GENERIC_CFG, {cmd=ISP_SET_MODE, mode=ISP_MODE_REC})
App->>ISP: isp_ioctl(ISP_IOCTL_SET_GENERIC_CFG, {cmd=ISP_SET_EV/ISP_SET_WB/ISP_SET_SHP/ISP_SET_DRC})
ISP->>VB: 输出处理后的视频帧
VB-->>App: 预览/录像消费帧
App->>Cam: camera_driver_ioctl(handle, CAMERA_SET_CROP_SIZE, ...)
App->>Cam: camera_driver_ioctl(handle, CAMERA_CROP_TRIG, ...)
Cam->>ISP: 更新输出尺寸
App->>Cam: camera_driver_close(handle)
流程说明:
- 注册:应用调用
camera_init()传入camera_platform_data,驱动据此完成 GPIO/I2C 资源登记,但不立即上电。 - 打开:
camera_driver_open()触发传感器上电(xclk_gpio输出主时钟、reset_gpio释放复位、pwdn_gpio解除掉电),通过iic_sel指定的 I2C 控制器初始化传感器寄存器,并回读 sensor ID 校验。 - ISP 建链:驱动依据
interface字段配置 DVP(PCLK/HSYNC/VSYNC/数据线 GPIO、时序模式、扫描模式、位宽)或 CSI2(lane 数、映射、极性)时序,建立 ISP 通道,填入in_fmt(传感器格式)、out_fmt(输出格式)。 - 参数下发:应用通过
isp_ioctl()下发录制/拍照模式、EV、白平衡、锐度、DRC 等参数;isp_scenes.c/isp_tools.c提供的封装可一次性套用某个场景的整套参数。 - 运行期调整:需要变更分辨率时,先
CAMERA_SET_CROP_SIZE设置裁剪窗口,再CAMERA_CROP_TRIG触发,必要时通过CAMERA_NEED_REMOUNT让视频设备重建管道。 - 关闭:
camera_driver_close()停止 ISP 通道、释放缓冲;异常场景用camera_driver_force_close()兜底。
运行期 ioctl 决策流
flowchart TD
Start([camera_driver_ioctl]) --> Cmd{"命令分类"}
Cmd -->|"查询类 (GET_*)"| Q["读取 ISP 尺寸/传感器 ID/RAW 缓冲"]
Cmd -->|"裁剪类 (SET_CROP/CROP_TRIG)"| C["更新裁剪窗口并触发 ISP 重算输出"]
Cmd -->|"重挂载类 (NEED_REMOUNT)"| R["通知视频管道重建"]
Cmd -->|"产测类 (TEST_KICK/TEST_DONE)"| T["触发/查询产测流程"]
Q --> Done([返回])
C --> Done
R --> Done
T --> Done
视频链路相关头文件角色
摄像头输出并不直接送给应用,而是汇入视频管道。SDK 在 sdk/include_lib/driver/device/video/ 下提供了配套头文件:
| 头文件 | 角色 | 与摄像头/ISP 的关系 |
|---|---|---|
video.h | 视频设备抽象(open/close/ioctl/流控) | 消费 ISP 输出的视频帧,是 CAMERA_NEED_REMOUNT 后重建的对象 |
video_ioctl.h | 视频 ioctl 命令定义 | 定义取流、缓冲队列等命令 |
videobuf.h | 视频帧缓冲管理 | 承载 ISP 输出帧,供预览/编码消费 |
fb.h | 帧缓冲(显示) | 把 ISP 帧送到屏幕显示路径 |
dec_stream.h | 解码流 | 摄像头 RAW 抓拍(CAMERA_GET_CAPTURE_RAW)相关 |
usb_cam_dev.h | USB UVC 摄像头设备 | 与 VIDEO_TAG_UVC 对应,属独立 UVC 链路 |
注:上述头文件为设备接口层组成部分;本页聚焦摄像头驱动与 ISP 本身,视频编解码与显示细节见对应兄弟页面。
使用示例
示例 1:定义摄像头平台数据(DVP 传感器接线)
以 DVP 接口为例,通过平台宏声明 camera_platform_data,声明 I2C、时钟、复位、掉电引脚与 DVP 时序参数:
CAMERA_PLATFORM_DATA_BEGIN(camera_platform_data)
.iic_sel = "iic0",
.xclk_gpio = 25,
.reset_gpio = 26,
.pwdn_gpio = 27,
.power_value = 0,
.interface = DVP0_INTERFACE,
.online_detect = NULL,
.dvp = {
.pclk_gpio = ...,
.hsync_gpio = ...,
.vsync_gpio = ...,
.group_port = 0, // DVP0: 0=PD9~PE2 1=PA4~PA11
.reverse = 0, // 0: 正序 1: 反序
.shift = 0, // 数据位偏移量
.timing_mode = 0, // 0:DVP 1:BT601 2:VSYNC 3:BT656
.scan_mode = 0, // 0:逐行扫描 1:奇场 2:偶场
.width_mode = 0, // 0:全位宽(8/10bit) 1:4bit 2:2bit 3:1bit
.h_blank = 0,
.v_blank = 0,
},
CAMERA_PLATFORM_DATA_END()
结构定义来源:camera.h;具体传感器(NT99141、TVP5150A)的实例见 nt99141.c 与 TVP5150A_DVP.c
示例 2:注册并打开摄像头
// 注册摄像头设备
camera_init("cam0", (void *)&camera_platform_data);
// 打开摄像头,获取当前分辨率/帧率
struct camera_device_info info;
void *cam = camera_driver_open(0, &info);
// info.width / info.height / info.fps / info.real_fps 可用
// 下发 ioctl(例如查询 ISP 输出尺寸或设置裁剪)
u32 w = 0, h = 0;
camera_driver_ioctl(cam, CAMERA_GET_ISP_SIZE, &w);
// 关闭
camera_driver_close(cam);
API 声明来源:camera.h 与 camera.h#L79-L86
示例 3:下发 ISP 通用配置
struct isp_generic_cfg cfg = {0};
cfg.cmd = ISP_SET_MODE;
cfg.channel = 0;
cfg.mode = ISP_MODE_REC; // 录制模式
cfg.in_fmt = (struct isp_pix_format){ .fps = 30, .width = 640, .height = 480 };
cfg.out_fmt = (struct isp_pix_format){ .fps = 30, .width = 640, .height = 480 };
isp_ioctl(ISP_IOCTL_SET_GENERIC_CFG, &cfg);
// 调节曝光/白平衡/锐度/DRC
cfg.cmd = ISP_SET_EV; cfg.ev = 0; isp_ioctl(ISP_IOCTL_SET_GENERIC_CFG, &cfg);
cfg.cmd = ISP_SET_WB; cfg.white_blance = 0; isp_ioctl(ISP_IOCTL_SET_GENERIC_CFG, &cfg);
cfg.cmd = ISP_SET_SHP; cfg.sharpness = 0; isp_ioctl(ISP_IOCTL_SET_GENERIC_CFG, &cfg);
cfg.cmd = ISP_SET_DRC; cfg.drc = 0; isp_ioctl(ISP_IOCTL_SET_GENERIC_CFG, &cfg);
结构体与命令定义来源:isp.h;更便捷的场景化封装见 isp_scenes.c 与 isp_tools.c
配置选项
camera_platform_data 字段
| 字段 | 类型 | 默认/取值 | 说明 |
|---|---|---|---|
iic_sel | char * | "iic0" 等 | 传感器寄存器访问使用的 I2C 控制器 |
xclk_gpio | u8 | 平台相关 | 传感器主时钟(XCLK)输出 GPIO |
reset_gpio | u8 | 平台相关 | 传感器复位 GPIO |
pwdn_gpio | u8 | 平台相关 | 传感器掉电控制 GPIO |
power_value | u8 | 平台相关 | 供电档位 |
interface | u32 | DVP0_INTERFACE(0) / DVP1_INTERFACE(1) / CSI2_INTERFACE(2) / MCVx_INTERFACE(4~7) | 物理接口类型 |
online_detect | bool (*)() | NULL | 在线检测回调(热插拔场景) |
dvp.pclk_gpio | u32 | 平台相关 | DVP 像素时钟引脚 |
dvp.hsync_gpio / dvp.vsync_gpio | u32 | 平台相关 | 行/场同步引脚 |
dvp.group_port | u8 | 0/1 | DVP0: 0=PD9~PE2, 1=PA4~PA11;DVP1: 0=PB0~PB7, 1=PB8~PB15 |
dvp.reverse | u8 | 0 | 数据位序:0 正序 / 1 反序 |
dvp.shift | u8 | 0 | 数据位偏移量 |
dvp.timing_mode | u8 | 0 | 时序:0 DVP / 1 BT601 / 2 VSYNC / 3 BT656 |
dvp.scan_mode | u8 | 0 | 扫描:0 逐行 / 1 奇场 / 2 偶场 |
dvp.width_mode | u8 | 0 | 位宽:0 全位宽(8/10bit) / 1 4bit / 2 2bit / 3 1bit |
dvp.h_blank / dvp.v_blank | u32 | 0 | 水平/垂直消隐后肩(默认 0) |
dvp.data_gpio[10] | u32[] | 平台相关 | 最多 10 根数据 GPIO |
csi2.data_lane_num | u8 | 1~4 | MIPI data lane 数量 |
csi2.clk_rmap / clk_inv | u8 | 0 | 时钟引脚映射/极性反转 |
csi2.d0_rmap~d3_rmap | u8 | 0 | 各 lane 引脚映射 |
csi2.d0_inv~d3_inv | u8 | 0 | 各 lane 极性反转 |
csi2.tval_hstt / tval_stto | u8 | 0 | CSI2 时序参数(HS 建立/退出时间) |
isp_generic_cfg 常用字段
| 字段 | 类型 | 说明 |
|---|---|---|
cmd | u32 | 通用命令(ISP_SET_* / ISP_GET_*) |
channel | u8 | ISP 通道号 |
mode | u8 | ISP_MODE_NONE / ISP_MODE_REC / ISP_MODE_IMAGE_CAPTURE |
sen_status / vsignal | u8 | 传感器状态/视频信号标志(查询回填) |
ev | s8 | 曝光补偿 |
white_blance | u8 | 白平衡档位 |
sharpness | u8 | 锐度 |
drc | u8 | 动态范围压缩强度 |
lv | s32 | 亮度电平(查询回填) |
in_fmt / out_fmt / sen_fmt | struct isp_pix_format | 输入/输出/传感器 帧格式(fps/width/height) |
API 参考
int camera_init(const char *name, void *camera_data)
注册一个摄像头设备。
- 参数:
name设备名;camera_data指向struct camera_platform_data的指针。 - 返回:0 成功,负值失败。
- 说明:通常在系统初始化阶段调用,每个摄像头实例调用一次。
void *camera_driver_open(int id, struct camera_device_info *info)
按设备号打开摄像头并完成传感器上电与 ISP 建链。
- 参数:
id设备号(0~CAMERA_DEVICE_NUM-1);info输出参数,回填fps、sen_width、sen_height、width、height、real_fps。 - 返回:摄像头驱动句柄;失败返回 NULL。
- 说明:打开后即可通过返回句柄执行 ioctl。
int camera_driver_close(void *_camera) / int camera_driver_force_close(void *_camera)
关闭摄像头。force_close 用于异常/抢占场景强制释放。
- 参数:
_camera由camera_driver_open返回的句柄。 - 返回:0 成功,负值失败。
int camera_driver_ioctl(void *_camera, u32 cmd, void *arg)
下发摄像头控制命令。
- 参数:
_camera句柄;cmd取CAMERA_GET_ISP_SRC_SIZE、CAMERA_SET_CROP_SIZE、CAMERA_CROP_TRIG、CAMERA_NEED_REMOUNT、CAMERA_GET_SENSOR_ID、CAMERA_GET_CAPTURE_RAW、CAMERA_SET_TEST_KICK、CAMERA_GET_TEST_DONE等;arg命令参数指针。 - 返回:0 成功,负值失败。
int isp_ioctl(u32 cmd, void *arg)
ISP 统一控制入口。
- 参数:
cmd取ISP_IOCTL_SET_GENERIC_CFG、ISP_IOCTL_GET_GENERIC_CFG、ISP_IOCTL_SET_CUSTOMIZE_CFG、ISP_IOCTL_GET_CUSTOMIZE_CFG、ISP_IOCTL_SET_FPS;arg对应结构体指针(isp_generic_cfg/ispt_customize_cfg/int)。 - 返回:0 成功,负值失败。
- 说明:内部根据
cmd路由到isp0_ioctrl等通道回调。
s32 isp0_mount(void *arg) / int isp_delete(int channel)
ISP 通道挂载与销毁。isp0_mount 在设备打开时建立通道 0;isp_delete(channel) 释放指定通道资源。
void isp_dump_reg()
调试接口,导出当前 ISP 寄存器状态(配合 ISP_CUSTOMIZE_MODE_TOOL 联调使用)。
故障模式、边界情况与并发
传感器识别失败
camera_driver_open() 内部会通过 iic_sel 指定的 I2C 回读传感器 ID。若接线错误、供电异常或 I2C 控制器选择错误,回读失败将导致打开失败(返回 NULL)。建议:
- 核对
iic_sel与硬件上传感器 SDA/SCL 实际挂载的 I2C 控制器; - 核对
xclk_gpio是否输出有效主时钟(多数 CMOS 传感器无时钟不响应 I2C); - 核对
reset_gpio/pwdn_gpio电平极性是否符合传感器手册。
DVP 时序错配
DVP 场景下 group_port、reverse、shift、timing_mode、scan_mode、width_mode 任一配置错误都会导致花屏或无图。timing_mode 需与传感器输出格式匹配(如 BT656 只支持特定传感器),scan_mode 用于隔行传感器,逐行传感器必须保持默认 0。h_blank / v_blank 默认填 0,只有传感器输出带特殊消隐需求时才需要调整。
CSI2 极性/映射错误
CSI2 场景下 clk_inv / d0_inv~d3_inv 与 rmap 必须与 PCB 布线一致;data_lane_num 与实际接线的 lane 数一致。tval_hstt / tval_stto 影响 HS 建立/退出时序,高速模式不稳定时可微调。这类问题通常表现为"能识别 sensor 但取流失败/花屏"。
裁剪与重挂载的时序约束
CAMERA_SET_CROP_SIZE 只设置参数,必须再发 CAMERA_CROP_TRIG 才生效;尺寸变更后视频管道需要重建,应用必须处理 CAMERA_NEED_REMOUNT,否则可能出现取流尺寸与缓冲不匹配(越界/撕裂)。裁剪尺寸不能超出 ISP 输出能力。
并发与资源竞争
- 多个摄像头设备(最多
CAMERA_DEVICE_NUM13 个、ENDPOINT_NUM5 个端点)共享 ISP 与视频管道资源,通道号(channel)必须唯一,重复挂载同一通道可能导致 ISP 状态错乱。 - ISP 参数下发与取流并行时,建议在帧回调外(或临界区)下发
isp_ioctl,避免参数在帧处理中途切换造成短暂画质跳变。 - 异常退出场景应使用
camera_driver_force_close()兜底,避免残留占用导致后续打开失败。 MCVx_INTERFACE序号与驱动内部逻辑强耦合(源码注释明确"非作者本人勿动"),自行修改枚举值可能破坏多通道路由。
产测路径
CAMERA_SET_TEST_KICK / CAMERA_GET_TEST_DONE 用于产线测试(如坏点、动态范围测试),测试期间摄像头可能暂停正常取流,业务应避免并发取流。
性能与运维
- 带宽:DVP 并行接口在 8/10bit 全位宽下占用较多 GPIO 与总线带宽;CSI2 通过 lane 数可扩展带宽(
CSI2_X0_LANE~CSI2_X4_LANE),高速场景优先 CSI2。 - 帧率控制:
ISP_IOCTL_SET_FPS与isp_pix_format.fps共同决定输出帧率;camera_device_info.real_fps反映实际帧率,可用于诊断帧率不足(排除时钟、带宽、曝光过长问题)。 - 调试手段:
isp_dump_reg()导出 ISP 寄存器;ISP_IOCTL_GET_GENERIC_CFG回读当前参数(含lv亮度、sen_status、vsignal),用于确认 3A 是否收敛。 - 定制参数管理:
ispt_customize_cfg携带version与crc,用于区分和校验 ISP 工具导出的参数版本,避免旧参数覆盖新参数;三种来源TOOL/FILE/SPECIAL对应联调、量产固化与特殊场景注入。 - 传感器驱动维护:新传感器接入时,在
sdk/apps/common/camera/下新建类似nt99141.c的驱动文件(寄存器初始化 + 平台数据 + 注册),并在应用初始化处调用camera_init()即可,无需改动驱动框架。
扩展点
- 新增传感器:参照 nt99141.c / TVP5150A_DVP.c 提供传感器驱动与
camera_platform_data实例,通过camera_init()挂载。 - ISP 场景封装:在 isp_scenes.c 中扩展场景表(室内/室外/夜视等),通过 isp_tools.c 提供快捷接口,业务只需按场景切换。
- 定制 ISP 参数:使用
ISP_IOCTL_SET_CUSTOMIZE_CFG+ISP_CUSTOMIZE_MODE_*,可注入 ISP 工具产出的寄存器表、量产校准文件或特殊效果参数。 - 在线检测:实现
online_detect回调可支持摄像头热插拔(配合CAMERA_NEED_REMOUNT重建管道)。 - 视频管道接入:ISP 输出汇入 videobuf/fb/dec_stream 链路,接入编码器、显示或网络推流(如 wifi_camera 应用),扩展点在视频设备层。
测试
仓库内相关测试/验证主要体现为:
- 传感器驱动验证:
nt99141.c(CMOS 数字传感器)与TVP5150A_DVP.c(模拟转数字 DVP 传感器)两套真实驱动作为接入范例,覆盖了 I2C 初始化、平台数据定义与camera_init注册的完整路径。 - ISP 场景验证:
isp_scenes.c的场景参数集合用于验证不同光照下的画质表现;isp_tools.c提供与 ISP 工具联调的基础设施(寄存器读写/参数导入导出)。 - 应用集成验证:
sdk/apps/wifi_camera工程的tx_camera_cWF.c展示摄像头取流 + WiFi 推流的端到端用法;sdk/apps/wifi_camera/board/wl83/AC792N_WIFI_CAMERA.cbp(Code::Blocks 工程文件)展示板级接线与工程组织。
相关链接
- camera.h — 摄像头设备接口
- isp.h — ISP 接口
- video.h / video_ioctl.h / videobuf.h — 视频管道接口
- isp_scenes.c — ISP 场景配置
- isp_tools.c — ISP 工具封装
- nt99141.c — NT99141 传感器驱动
- TVP5150A_DVP.c — TVP5150A 传感器驱动
- 兄弟页面:视频编解码流(dec_stream)、帧缓冲显示(fb/LVGL)、USB UVC 摄像头、WiFi 摄像头应用