全志 芯片 Linux MIPI CSI摄像头接口开发指南 VIN DVP CSI MIPI V4l2

时间:2022-12-29 11:56:09

1 前言

1.1 文档简介

介绍 VIN(video input)驱动配置,API 接口和上层使用方法。

1.2 目标读者

camera 驱动开发、维护人员和应用开发人员。

1.3 适用范围

​ 表 1-1: 适用产品列表

内核版本 驱动文件
Linux-4.9 drivers/media/platform/sunxi_vin/*.c
Linux-5.4 drivers/media/platform/sunxi_vin/*.c

2 模块介绍

2.1 模块功能介绍

  1. Video input 主要由接口部分(CSI/MIPI)和图像处理单元(ISP/VIPP)组成;

  2. CSI/MIPI 部分主要实现视频数据的捕捉;

  3. ISP 实现 sensor raw data 数据的处理,包括 lens 补偿、去坏点、gain、gamma、de-mosaic、de-noise、color matrix 等以及一些 3A 的统计;

  4. VIPP 能对将图进行缩小、和打水印处理。VIPP 支持 bayer raw data 经过 ISP 处理后再缩小,也支持对一般的 YUV 格式的 sensor 图像直接缩小。

2.2 相关术语介绍

​ 表 2-1: 软件术语

相关术语 解释说明
ISP Image Signal Processor 图像信号处理
VIPP Video Input Post Processor 图像输入后处理
MIPI Mobile Industry Processor Interface 移动工业处理接口
CCI Camera Control Interface 摄像头控制接口
TDM Time division multiplexing ISP 时分复用
MCLK Master clock(From AP to camera)摄像头主时钟
PCLK Pixel clock(From camera to AP,Sampling clock for data-bus)像素时钟
YUV Color Presentation(Y for luminance,U&V for Chrominance)图像数据格式

2.3 驱动框架介绍

全志 芯片 Linux MIPI CSI摄像头接口开发指南 VIN DVP CSI MIPI V4l2

​ 图 2-1: 驱动框图

VIN 驱动可以分为 Kernel 层、Video Input Framework、Device Driver 层。

2.3.1 Kernel 层

  1. V4l2 Framework;

  2. Linux 内核视频驱动第二版(Video for Linux Two );

  1. 适用于收音机、视频编解码、视频捕获以及视频输出设备驱动;

  2. 提供/dev/videoX 节点,应用通过该节点进行相应视频流和控制操作;

  1. Media Device Framework;

  2. Linux 多媒体设备框架;

  1. 适用于管理设备拓扑结构;

  2. 提供/dev/mediaX 节点,通过该节点应用可以获取媒体设备拓扑结构,并能够通过 API 控制子设备间数据流向。

2.3.2 Video Input Framework 层

  1. Video Control : 视频命令处理(分辨率协商,数据格式处理,Buffer 管理等);

  2. Runtime Handle : 运行时管理(Pipeline 管理,系统资源管理,中断调度等);

  3. Event Process : 事件管理(如上层调用,中断等事件的接收与分发);

  4. Config Handle : 配置管理(如硬件拓扑结构,模组自适应列表等)。

2.3.3 Device Driver 层

  1. Camera Modules : 模组驱动(图像传感器,对焦电机,闪光灯等驱动);

  2. Camera Interfac : 接口驱动(MIPI、Sub-Lvds 、HiSpi、Bt656、Bt601、Bt1120、DC等);

  3. Image Signal Processor : 图像处理器驱动(基本处理模块驱动,3A 统计驱动);

  4. Video Input Post Processor : 视频输入后处理(Scaler,OSD 等)。

2.4 模块配置介绍

2.4.1 kernel menuconfig 配置

  1. 首先,进入 Device Drivers,选择 Multimedia support ,然后依次打开 Cameras/video grabbers support 、Media Controller support 和 SUNXI platform devices, 如下图所示。

    全志 芯片 Linux MIPI CSI摄像头接口开发指南 VIN DVP CSI MIPI V4l2

    ​ 图 2-2: Device Drivers 选项配置

  2. 其次,进入 SUNXI platform devices,选择 sunxi video input (camera csi/mipi isp vipp)driver 和 v4l2 new driver for SUNXI,如下图所示。

    全志 芯片 Linux MIPI CSI摄像头接口开发指南 VIN DVP CSI MIPI V4l2

    ​ 图 2-3: Device Drivers 选项配置

  3. 最后,sunxi video input (camera csi/mipi isp vipp)driver 目录下的其他选项需要根据实际产品需求进行开关,如:使用闪光灯、对焦马达、打开 vin log、使用 IOMMU 如下图所示。

    全志 芯片 Linux MIPI CSI摄像头接口开发指南 VIN DVP CSI MIPI V4l2

    ​ 图 2-4: Device Drivers 选项配置

2.4.2 Device Tree 配置说明

设备树文件的配置是该 SoC 所有方案的通用配置,对于 ARM64 CPU 而言,设备树的路径为:kernel/{KERNEL_VERSION}/arch/arm64/boot/dts/sunxi/sun*.dtsi。

设备树文件的配置是该 SoC 所有方案的通用配置,对于 ARM32 CPU 而言,设备树的路径为:kernel/{KERNEL_VERSION}/arch/arm/boot/dts/sun*.dtsi。

板级设备树 (board.dts) 路径:

/device/config/chips/{IC}/configs/{BOARD}/KERNEL_VERSION/board.dts。

在 sun*.dtsi* 文件中,配置了该 SoCCSI 控制器的通用配置信息,一般不建议修改,由 CSI 驱动维护者维护,如果需要修改配置请修改板级设备树 board.dts,板级设备树里面的内容会覆盖sun.dtsi 对应的信息。

vind 配置

&vind0 {
    vind0_clk = <336000000>;
    vind0_isp = <300000000>;
    status = "okay";
    
    tdm0:tdm@0 {
    	work_mode = <0>;
    };
    
    isp00:isp@0 {
    	work_mode = <0>;
    };
    
    scaler00:scaler@0 {
    	work_mode = <0>;
    };
    
    scaler10:scaler@4 {
    	work_mode = <0>;
    };
    
    scaler20:scaler@8 {
    	work_mode = <0>;
    };
    
    scaler30:scaler@12 {
    	work_mode = <0>;
    };
    
    actuator0:actuator@0 {
        device_type = "actuator0";
        actuator0_name = "ad5820_act";
        actuator0_slave = <0x18>;
        actuator0_af_pwdn = <>;
        actuator0_afvdd = "afvcc-csi";
        actuator0_afvdd_vol = <2800000>;
        status = "disabled";
    };
    flash0:flash@0 {
        device_type = "flash0";
        flash0_type = <2>;
        flash0_en = <>;
        flash0_mode = <>;
        flash0_flvdd = "";
        flash0_flvdd_vol = <>;
        status = "disabled";
    };
    sensor0:sensor@0 {
        device_type = "sensor0";
        sensor0_mname = "gc2053_mipi";
        sensor0_twi_cci_id = <1>;
        sensor0_twi_addr = <0x6e>;
        sensor0_mclk_id = <0>;
        sensor0_pos = "rear";
        sensor0_isp_used = <1>;
        sensor0_fmt = <1>;
        sensor0_stby_mode = <0>;
        sensor0_vflip = <0>;
        sensor0_hflip = <0>;
        sensor0_iovdd-supply = <&reg_aldo2>;
        sensor0_iovdd_vol = <1800000>;
        sensor0_avdd-supply = <&reg_bldo2>;
        sensor0_avdd_vol = <2800000>;
        sensor0_dvdd-supply = <&reg_dldo2>;
        sensor0_dvdd_vol = <1200000>;
        sensor0_power_en = <>;
        sensor0_reset = <&pio PA 18 1 0 1 0>;
        sensor0_pwdn = <&pio PA 19 1 0 1 0>;
        sensor0_sm_hs = <>;
        sensor0_sm_vs = <>;
        flash_handle = <&flash0>;
        act_handle = <&actuator0>;
        status = "okay";
    };
    sensor1:sensor@1 {
        device_type = "sensor1";
        sensor1_mname = "imx386_mipi_2";
        sensor1_twi_cci_id = <0>;
        sensor1_twi_addr = <0x20>;
        sensor1_mclk_id = <1>;
        sensor1_pos = "front";
        sensor1_isp_used = <1>;
        sensor1_fmt = <1>;
        sensor1_stby_mode = <0>;
        sensor1_vflip = <0>;
        sensor1_hflip = <0>;
        sensor1_iovdd-supply = <&reg_aldo2>;
        sensor1_iovdd_vol = <1800000>;
        sensor1_avdd-supply = <&reg_bldo2>;
        sensor1_avdd_vol = <2800000>;
        sensor1_dvdd-supply = <&reg_dldo2>;
        sensor1_dvdd_vol = <1200000>;
        sensor1_power_en = <>;
        sensor1_reset = <&pio PA 20 1 0 1 0>;
        sensor1_pwdn = <&pio PA 21 1 0 1 0>;
        sensor1_sm_hs = <>;
        sensor1_sm_vs = <>;
        flash_handle = <>;
        act_handle = <>;
        status = "okay";
    };
    vinc00:vinc@0 {
        vinc0_csi_sel = <0>;
        vinc0_mipi_sel = <0>;
        vinc0_isp_sel = <0>;
        vinc0_isp_tx_ch = <0>;
        vinc0_tdm_rx_sel = <0>;
        vinc0_rear_sensor_sel = <0>;
        vinc0_front_sensor_sel = <0>;
        vinc0_sensor_list = <0>;
        work_mode = <0x0>;
        status = "okay";
    };
    vinc01:vinc@1 {
        vinc1_csi_sel = <2>;
        vinc1_mipi_sel = <0xff>;
        vinc1_isp_sel = <1>;
        vinc1_isp_tx_ch = <1>;
        vinc1_tdm_rx_sel = <1>;
        vinc1_rear_sensor_sel = <0>;
        vinc1_front_sensor_sel = <0>;
        vinc1_sensor_list = <0>;
        status = "disabled";
    };
    vinc02:vinc@2 {
        vinc2_csi_sel = <2>;
        vinc2_mipi_sel = <0xff>;
        vinc2_isp_sel = <2>;
        vinc2_isp_tx_ch = <2>;
        vinc2_tdm_rx_sel = <2>;
        vinc2_rear_sensor_sel = <0>;
        vinc2_front_sensor_sel = <0>;
        vinc2_sensor_list = <0>;
        status = "disabled";
    };
    vinc03:vinc@3 {
        vinc3_csi_sel = <0>;
        vinc3_mipi_sel = <0xff>;
        vinc3_isp_sel = <0>;
        vinc3_isp_tx_ch = <0>;
        vinc3_tdm_rx_sel = <0>;
        vinc3_rear_sensor_sel = <1>;
        vinc3_front_sensor_sel = <1>;
        vinc3_sensor_list = <0>;
        status = "disabled";
    };
    …………
};

其中:

status 是 vin 驱动的总开关,对应的是 media 设备,使用 vin 时必须设为 okay;

vind0_clk 是 vin 模块的时钟,实际使用时可以根据 sensor 的帧率和分辨率来设置;

vind0_isp 是 isp 模块时钟,实际使用时可以根据 sensor 的帧率和分辨率来设置;

vind0_clk 表示 csi clk,计算公式:帧率 x (vts)x (hts)x 1(wdr 则为 2) / 8 / 1(双 pixel则为 2) / 1000000,向上取整,单位为 MH;vind0_isp 表示 isp clk,计算公式:帧率 x 宽 x 高 x 1.2 / 1000000,向上取整,单位为 MH;其中有些 ic 是没有 isp_clk,csi_clk 和isp_clk 都是设置在 vind0_clk。那么 vind0_clk 设置为 csi_clk 和 isp_clk 中最大的数值;

work_mode: 0:online mode 1:offline mode, 根据使用需求配置;

flash0_type: 0:FLASH_RELATING, 1:FLASH_EN_INDEPEND, 2:FLASH_POWER

flash0_en: flash enable gpio, type = 0 of 1

flash0_mode: flash mode gpio, type = 0 of 1

flash0_flvdd: flash module io power handle string, pmu power supply, type = 2

flash0_flvdd_vol: flash module io power voltage, pmu power supply, type = 2

status: 是否使用 flash, disable 代表关,okay 代表开

actuator0_name: vcm name

actuator0_slave: vcm iic slave address

actuator0_af_pwdn: vcm power down gpio

actuator0_afvdd: vcm power handle string, pmu power supply

actuator0_afvdd_vol: vcm power voltage, pmu power supply

status: vcm if used, disable 代表关,okay 代表开

device_type: sensor type sensor0_mname: sensor name

sensor0_twi_cci_id:sensor 所使用的 twi 或者 cci 的 id。

sensor0_twi_addr:sensor 的 twi 地址

sensor0_mclk_id:sensor 所使用的 mclk 的 id。

sensor0_pos:sensor 的位置,前置还是后置,主要用在平板上。

sensor0_isp_used: not use isp 1:use isp

sensor0_fmt: 0:yuv 1:bayer raw rgb

sensor0_stby_mode: not shut down power at standby 1:shut down power at standby

sensor0_vflip: flip in vertical direction 0:disable 1:enable

sensor0_hflip: flip in horizontal direction 0:disable 1:enable

sensor0_iovdd-supply: camera module io power handle string, pmu power supply

sensor0_iovdd_vol: camera module io power voltage, pmu power supply

sensor0_avdd-supply: camera module analog power handle string, pmu power supply

sensor0_avdd_vol: camera module analog power voltage, pmu power supply

sensor0_dvdd-supply: camera module core power handle string, pmu power supply

sensor0_dvdd_vol: camera module core power voltage, pmu power supply

sensor0_power_en: camera module power enable gpio

sensor0_reset: camera module reset gpio

sensor0_pwdn: camera module pwdn gpio sensor0_sm_hs: camera module sm_hs

gpio sensor0_sm_vs: camera module sm_vs gpio status: open or close sensor de

vice flash/actautor/sensor 节点用于对应的外设的开关和配置。这些节点的配置一般需要参

考对应方案的原理图和外设的 data sheet 来完成。

vinc0_csi_sel:表示该 pipeline 上 parser 的 id,必须配置,且为有效 id。

vinc0_mipi_sel:表示该 pipeline 上 mipi(sublvds/hispi)的 id,不使用时配置为 0xff。

vinc0_isp_sel:表示该 pipeline 上 isp 的 id,必须配置,当 isp 为空时,这个 isp 只是表示路由不做 isp 的效果处理。

vinc0_isp_tx_ch 表示该 pipeline 上 isp 的 ch,必须配置,默认为 0。当 sensor 是 bt656 多通道或者 WDR 出 RAW 时,该 ch 可以配置 0~3 的值。

vinc0_tdm_rx_sel: 表示该 pipeline 上 tdm rx 的 ch,必须配置,默认为 0。当不使用 tdm功能时,配置为 0xff;

vinc0_rear_sensor_sel 表示该 pipeline 上使用的后置 sensor 的 id。

vinc0_front_sensor_sel 表示该 pipeline 上使用的前置 sensor 的 id。

vinc0_sensor_list 表示是否使用 sensor_list 来时适配不同的模组,1 表示使用,0 表示不使用。

work_mode: 0:online mode 1:offline mode, 根据使用需求配置;只有 vinc0/4/8/12 可以配置。

status:vipp 的使能开关,okay or disable。

2.5 源码模块结构

驱动路径位于 drivers/media/platform/sunxi-vin 目录。

sunxi-vin:.
├── Kconfig
├── Makefile
├── modules
│   ├── actuator
│   │   ├── actuator.c     ;vcm driver的一般行为
│   │   ├── actuator.h     ;vcm driver的头文件
│   │   ├── ad5820_act.c   ;具体vcm driver型号实现
│   │   ├── an41908a_act.c ;具体vcm driver型号实现
│   │   ├── dw9714_act.c   ;具体vcm driver型号实现
│   │   ├── Makefile       ;编译文件
│   ├── flash
│   │   ├── flash.c ;led补光灯控制实现
│   │   ├── flash.h ;led补光灯驱动头文件
│   └── sensor
│   ├── ar0238.c      ;具体的sensor驱动
│   ├── camera_cfg.h  ;camera ioctl扩展命令头文件
│   ├── camera.h      ;camera公用结构体头文件
│   ├── gc030a_mipi.c ;具体的sensor驱动
│   ├── gc0310_mipi.c ;具体的sensor驱动
│   ├── gc5024_mipi.c ;具体的sensor驱动
│   ├── imx179_mipi.c ;具体的sensor驱动
│   ├── imx214.c      ;具体的sensor驱动
│   ├── imx219.c      ;具体的sensor驱动
│   ├── imx317_mipi.c ;具体的sensor驱动
│   ├── Makefile      ;驱动的编译文件
│   ├── nvp6134     ;具体的dvp sensor驱动
│   │   ├── acp.c
│   │   ├── acp_firmup.c
│   │   ├── acp_firmup.h
│   │   ├── acp.h
│   │   ├── common.h
│   │   ├── csi_dev_nvp6134.c
│   │   ├── csi_dev_nvp6134.h
│   │   ├── eq.c
│   │   ├── eq_common.c
│   │   ├── eq_common.h
│   │   ├── eq.h
│   │   ├── eq_recovery.c
│   │   ├── eq_recovery.h
│   │   ├── Makefile
│   │   ├── nvp6134c.c ;具体的sensor驱动实现
│   │   ├── type.h
│   │   ├── video.c
│   │   └── video.h
│   ├── nvp6158 ;具体的dvp sensor驱动
│   │   ├── audio.c ;音频部分实现
│   │   ├── audio.h ;音频部分头文件接口
│   │   ├── coax_protocol.c
│   │   ├── coax_protocol.h
│   │   ├── coax_table.h
│   │   ├── common.h
│   │   ├── Makefile
│   │   ├── modules.builtin
│   │   ├── modules.order
│   │   ├── motion.c
│   │   ├── motion.h
│   │   ├── nvp6158c.c ;具体的sensor驱动实现
│   │   ├── nvp6158_drv.c
│   │   ├── nvp6158_drv.h
│   │   ├── nvp6168_eq_table.h
│   │   ├── video_auto_detect.c
│   │   ├── video_auto_detect.h
│   │   ├── video.c
│   │   ├── video_eq.c
│   │   ├── video_eq.h
│   │   ├── video_eq_table.h
│   │   ├── video.h
│   ├── rn6854m_mipi.c ;具体的sensor驱动实现
│   ├── sensor-compat-ioctl32.c
│   ├── sensor_helper.c ;驱动函数接口的实现
│   ├── sensor_helper.h ;驱动函数接口的定义
├── modules.builtin
├── modules.order
├── platform
│   ├── platform_cfg.h ;vin平台配置文件
│   ├── sun50iw10p1_vin_cfg.h ;不同平台配置文件
│   ├── sun50iw3p1_vin_cfg.h ;不同平台配置文件
│   ├── sun50iw6p1_vin_cfg.h ;不同平台配置文件
│   ├── sun50iw9p1_vin_cfg.h ;不同平台配置文件
│   ├── sun8iw12p1_vin_cfg.h ;不同平台配置文件
│   ├── sun8iw15p1_vin_cfg.h ;不同平台配置文件
│   ├── sun8iw16p1_vin_cfg.h ;不同平台配置文件
│   └── sun8iw19p1_vin_cfg.h ;不同平台配置文件
├── top_reg.c
├── top_reg.h
├── top_reg_i.h
├── top_reg.o
├── utility
│   ├── bsp_common.c
│   ├── bsp_common.h
│   ├── bsp_common.o
│   ├── cfg_op.c ;读取ini文件的实现函数
│   ├── cfg_op.h ;读取ini文件的实现函数
│   ├── config.c ;sensor电压、通道选择、i2c地址等信息读取函数
│   ├── config.h ;sensor电压、通道选择、i2c地址等信息读取函数头文件
│   ├── vin_io.h ;vin模块寄存器操作头文件
│   ├── vin_os.c
│   ├── vin_os.h
│   ├── vin_supply.c
│   ├── vin_supply.h
├── vin.c
├── vin-cci
│   ├── bsp_cci.c ;底层cci bsp函数
│   ├── bsp_cci.h ;底层cci bsp函数头文件
│   ├── cci_helper.c ;cci 帮助函数,供sensor驱动调用
│   ├── cci_helper.h ;cci 帮助函数头文件
│   ├── csi_cci_reg.c ;cci硬件底层实现
│   ├── csi_cci_reg.h ;cci硬件底层实现头文件
│   ├── csi_cci_reg_i.h ;cci 寄存器资源头文件
│   ├── Kconfig
│   ├── sunxi_cci.c ;cci 平台驱动源文件
│   ├── sunxi_cci.h ;cci 平台驱动头文件
├── vin-csi
│   ├── parser_reg.c   ;CSI控制函数
│   ├── parser_reg.h   ;CSI控制函数头文件
│   ├── parser_reg_i.h ;CSI 寄存器值
│   ├── sunxi_csi.c    ;csi 子模块驱动原文件
│   ├── sunxi_csi.h    ;csi 子模块驱动头文件
├── vin.h
├── vin-isp
│   ├── isp500
│   │   ├── isp500_reg_cfg.c
│   │   ├── isp500_reg_cfg.h
│   │   ├── isp500_reg_cfg.o
│   │   └── isp500_reg.h
│   ├── isp520
│   │   ├── isp520_reg_cfg.c
│   │   ├── isp520_reg_cfg.h
│   │   └── isp520_reg.h
│   ├── isp521
│   │   ├── isp521_reg_cfg.c
│   │   ├── isp521_reg_cfg.h
│   │   └── isp521_reg.h
│   ├── isp522
│   │   ├── isp522_reg_cfg.c
│   │   ├── isp522_reg_cfg.h
│   │   └── isp522_reg.h
│   ├── isp_default_tbl.h
│   ├── sunxi_isp.c
│   ├── sunxi_isp.h
│   └── sunxi_isp.o
├── vin-mipi
│   ├── bsp_mipi_csi.c ;底层mipi bsp函数
│   ├── bsp_mipi_csi.h ;底层mipi bsp函数头文件
│   ├── bsp_mipi_csi_null.c ;底层mipi bsp空函数
│   ├── bsp_mipi_csi_v1.c   ;底层mipi bsp函数--v1
│   ├── combo_common.h
│   ├── combo_csi
│   │   ├── combo_csi_reg.c
│   │   ├── combo_csi_reg.h
│   │   └── combo_csi_reg_i.h
│   ├── combo_rx
│   │   ├── combo_rx_reg.c
│   │   ├── combo_rx_reg.h
│   │   ├── combo_rx_reg_i.h
│   │   └── combo_rx_reg_null.c
│   ├── dphy
│   │   ├── dphy.h ;mipi dphy头文件
│   │   ├── dphy_reg.c ;mipi dphy底层实现函数
│   │   ├── dphy_reg.h ;mipi dphy底层实现函数头文件
│   │   └── dphy_reg_i.h ;mipi dphy 寄存器资源头文件
│   ├── protocol
│   │   ├── protocol.h ;mipi协议层头文件
│   │   ├── protocol_reg.c ;mipi协议层底层实现
│   │   ├── protocol_reg.h ;mipi协议层底层实现头文件
│   │   └── protocol_reg_i.h
│   ├── protocol.h
│   ├── sunxi_mipi.c
│   ├── sunxi_mipi.h
├── vin-stat
│   ├── vin_h3a.c ;3A控制接口函数
│   ├── vin_h3a.h ;3A控制接口函数头文件
├── vin-tdm
│   ├── tdm_reg.c ;TDM寄存器控制函数
│   ├── tdm_reg.h
│   ├── tdm_reg_i.h
│   ├── vin_tdm.c
│   └── vin_tdm.h
├── vin_test
│   ├── mplane_image
│   │   ├── csi_test_mplane.c ;camera抓图测试用例
│   │   └── Makefile ;测试用例编译文件
│   ├── sunxi_camera_v2.h
│   └── sunxi_display2.h
├── vin-video
│   ├── dma_reg.c ;csi dma寄存器控制函数
│   ├── dma_reg.h ;csi dma寄存器控制函数
│   ├── dma_reg_i.h ;csi dma 寄存器值定义头文件
│   ├── vin_core.c ;vin模块核心
│   ├── vin_core.h ;vin模块核心头文件
│   ├── vin_video.c ; 数据格式处理、pipe通道选择、Buffer管理等函数
│   ├── vin_video.h ;数据格式处理、pipe通道选择、Buffer管理等函数头文件
└── vin-vipp
    ├── sunxi_scaler.c ;图像压缩处理函数
    ├── sunxi_scaler.h ;图像压缩处理函数头文件
    ├── vipp_reg.c ;vipp寄存器控制函数
    ├── vipp_reg.h ;vipp寄存器控制函数头文件
    ├── vipp_reg_i.h ;vipp寄存器具体描述头文件

3 V4L2 接口描述

3.1 VIDIOC_QUERYCAP

3.1.1 Parameters

Capability of csi driver(struct v4l2_capability * capability)
struct v4l2_capability {
    __u8 driver[16];    /* i.e. "bttv" */
    __u8 card[32];      /* i.e. "Hauppauge WinTV" */
    __u8 bus_info[32];  /* "PCI:" + pci_name(pci_dev) */
    __u32 version;      /* should use KERNEL_VERSION() */
    __u32 capabilities; /* Device capabilities */
    __u32 reserved[4];
};

3.1.2 Returns

Success:0; Fail: Failure Number

3.1.3 Description

获取驱动的名称、版本、支持的 capabilities 等,如 V4L2_CAP_STREAMIN,V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE 等。

3.2 VIDIOC_ENUM_INPUT

3.2.1 Parameters

input(struct v4l2_input *inp)
struct v4l2_input {
    __u32 index;    /* Which input */
    __u8 name[32];  /* Label */
    __u32 type;     /* Type of input */
    __u32 audioset; /* Associated audios (bitfield) */
    __u32 tuner;    /* Associated tuner */
    v4l2_std_id std;
    __u32 status;
    __u32 capabilities;
    __u32 reserved[3];
};

3.2.2 Returns

Success:0; Fail: Failure Number

3.2.3 Description

获取驱动支持的 input index。目前驱动只支持 input index = 0 或 index = 1。

Index = 0 表示 primary csi device

Index = 1 表示 secondary csi device

应用输入 index 参数,驱动返回 type。对于 VIN 设备来说,type 为 V4L2_INPUT_TYPE_CAMERA。

3.3 VIDIOC_S_INPUT

3.3.1 Parameters

input(struct v4l2_input *inp)
The same as VIDIOC_ENUM_INPUT

3.3.2 Returns

Success:0; Fail: Failure Number

3.3.3 Description

通过 inp.index 设置当前要访问的 csi device 为 primary device 还是 secondary device。

Index = 0 (双摄像头配置中,一般对应后置摄像头。若只有一个摄像头设备,则 index 固定为0)

Index = 1(双摄像头配置中,一般对应前置摄像头)

调用该接口后,实际上会对 csi device 进行初始化工作。

在 A133 平台:Index 在 video0、1 时固定要设为 0;在 video2、3 要设为 1。

3.4 VIDIOC_G_INPUT

3.4.1 Parameters

input(struct v4l2_input *inp)
The same as VIDIOC_ENUM_INPUT

3.4.2 Returns

Success:0; Fail: Failure Number

3.4.3 Description

获取 inp.index,判断当前设置的 csi device 为 primary device 还是 secondary device。

Index = 0 (双摄像头配置中,一般对应后置摄像头。若只有一个摄像头设备,则 index 固定为0)

Index = 1(双摄像头配置中,一般对应前置摄像头)

3.5 VIDIOC_S_PARM

3.5.1 Parameters

Parameter(struct v4l2_streamparm *parms)
struct v4l2_streamparm {
    enum v4l2_buf_type type;
    union {
        struct v4l2_captureparm capture;
        struct v4l2_outputparm output;
        __u8 raw_data[200]; /* user-defined */
    } parm;
};
struct v4l2_captureparm {
    __u32 capability; /* Supported modes */
    __u32 capturemode; /* Current mode */
    struct v4l2_fract timeperframe; /* Time per frame in .1us units */
    __u32 extendedmode; /* Driver-specific extensions */
    __u32 readbuffers; /* # of buffers for read */
    __u32 reserved[4];
};

3.5.2 Returns

Success:0; Fail: Failure Number

3.5.3 Description

CSI 作为输入设备,只关注 parms.type 和 parms. capture。

应用使用时,parms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;

其中通过设定 parms->capture.capturemode(V4L2_MODE_VIDEO 或 V4L2_MODE_IMAGE),

实现视频或图片的采集。通过设定 parms->capture.timeperframe,可以设置帧率。

3.6 VIDIOC_G_PARM

3.6.1 Parameters

Parameter(struct v4l2_streamparm *parms)
The same as VIDIOC_S_PARM

3.6.2 Returns

Success:0; Fail: Failure Number

3.6.3 Description

应用使用时,parms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;

通过 parms->capture.capturemode 返回当前是 V4L2_MODE_VIDEO 或 V4L2_MODE_IMAGE;

通过 parms->capture.timeperframe, 返回当前设置的帧率。

3.7 VIDIOC_ENUM_FMT

3.7.1 Parameters

V4L2 format(struct v4l2_fmtdesc * fmtdesc)
struct v4l2_fmtdesc {
    __u32 index; /* Format number */
    enum v4l2_buf_type type; /* buffer type */
    __u32 flags;
    __u8 description[32]; /* Description string */
    __u32 pixelformat; /* Format fourcc */
    __u32 reserved[4];
};

3.7.2 Returns

Success:0; Fail: Failure Number

3.7.3 Description

获取驱动支持的 V4L2 格式。

应用输入 type,index 参数,驱动返回 pixelformat 。对于 VIN 设备来说,type 为V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE。

3.8 VIDIOC_TRY_FMT

3.8.1 Parameters

Video type, format and size(struct v4l2_format * fmt)
struct v4l2_format {
    enum v4l2_buf_type type;
    union {
        struct v4l2_pix_format pix;
        struct v4l2_pix_format_mplane pix_mp;
        struct v4l2_window win;
        struct v4l2_vbi_format vbi;
        struct v4l2_sliced_vbi_format sliced;
        __u8 raw_data[200];
    } fmt;
};
struct v4l2_pix_format {
    __u32 width;
    __u32 height;
    __u32 pixelformat;
    enum v4l2_field field;
    __u32 bytesperline; /* for padding, zero if unused */
    __u32 sizeimage;
    enum v4l2_colorspace colorspace;
    __u32 priv; /* private data, depends on pixelformat */
};

3.8.2 Returns

Success:0; Fail: Failure Number

3.8.3 Description

根据捕捉视频的类型、格式和大小,判断模式、格式等是否被驱动支持。不会改变任何硬件设置。

对于 VIN 设备,type 为 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE。使用 struct v4l2_pix_format_mplane 进行参数传递。

应用程序输入 struct v4l2_pix_format_mplane 结构体里面的 width、height、pixelformat、field 等参数,驱动返回最接近的 width、height;若 pixelformat、field 不支持,则默认选择驱动支持的第一种格式。

3.9 VIDIOC_S_FMT

3.9.1 Parameters

Video type, format and size(struct v4l2_format * fmt)
The same as VIDIOC_TRY_FMT

3.9.2 Returns

Success:0; Fail: Failure Number

3.9.3 Description

设置捕捉视频的类型、格式和大小,设置之前会调用 VIDIOC_TRY_FMT。

对于 VIN 设备,type 为 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE。使用 struct v4l2_pix_format_mplane 进行参数传递。应用程序输入 width、height、pixelformat、field 等,驱动返回最接近的 width、height; 若 pixelformat、field 不支持,则默认选择驱动支持的第一种格式。

应用程序应该以驱动返回的 width、height、pixelformat、field 等作为后续使用传递的参数。对于 OSD 设备,type 为 V4L2_BUF_TYPE_VIDEO_OVERLAY。使用 struct v4l2_window进行参数传递。

应用程序输入水印的个数、窗口位置和大小、bitmap 地址、bitmap 格式以及 global_alpha 等。驱动保存这些参数,并在 VIDIOC_OVERLAY 命令传递使能命令时生效。

3.10 VIDIOC_G_FMT

3.10.1 Parameters

Video type, format and size(struct v4l2_format * fmt)
The same as VIDIOC_TRY_FMT

3.10.2 Returns

Success:0; Fail: Failure Number

3.10.3 Description

获取捕捉视频的 width、height、pixelformat、field、bytesperline、sizeimage 等参数。

3.11 VIDIOC_OVERLAY

3.11.1 Parameters

Overlay on/off(unsigned int i)

3.11.2 Returns

Success:0; Fail: Failure Number

3.11.3 Description

传递 1 表示使能,0 表示关闭。设置使能时会更新 osd 参数,使之生效。

3.12 VIDIOC_REQBUFS

3.12.1 Parameters

Buffer type ,count and memory map type(struct v4l2_requestbuffers * req)
struct v4l2_requestbuffers {
    __u32 count;
    enum v4l2_buf_type type;
    enum v4l2_memory memory;
    __u32 reserved[2];
};

3.12.2 Returns

Success:0; Fail: Failure Number

3.12.3 Description

v4l2_requestbuffers 结构中定义了缓存的数量,驱动会据此申请对应数量的视频缓存。多个缓存可以用于建立 FIFO,来提高视频采集的效率。这些 buffer 通过内核申请,申请后需要通过 mmap 方法,映射到 User 空间。

Count:定义需要申请的 video buffer 数量;

Type:对于 VIN 设备,为 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;

Memory:目前支持 V4L2_MEMORY_MMAP、V4L2_MEMORY_USERPTR、V4L2_MEMORY_DMABUF 方式。

应用程序传递上述三个参数,驱动会根据 VIDIOC_S_FMT 设置的格式计算供需要 buffer 的大小,并返回 count 数量。

3.13 VIDIOC_QUERYBUF

3.13.1 Parameters

Buffer type ,index and memory map type(struct v4l2_buffer *buf)
struct v4l2_buffer {
    __u32 index;
    enum v4l2_buf_type type;
    __u32 bytesused;
    __u32 flags;
    enum v4l2_field field;
    struct timeval timestamp;
    struct v4l2_timecode timecode;
    __u32 sequence;
    
    /* memory location */
    enum v4l2_memory memory;
    union {
        __u32 offset;
        unsigned long userptr;
        struct v4l2_plane *planes;
    } m;
    __u32 length;
    __u32 input;
    __u32 reserved;
};

3.13.2 Returns

Success:0; Fail: Failure Number

3.13.3 Description

通过 struct v4l2_buffer 结构体的 index,访问对应序号的 buffer,获取到对应 buffer 的缓存信息。主要利用 length 信息及 m.offset 信息来完成 mmap 操作。

3.14 VIDIOC_DQBUF

3.14.1 Parameters

Buffer type ,index and memory map type(struct v4l2_buffer *buf)
struct v4l2_buffer is the same as VIDIOC_QUERYBUF

3.14.2 Returns

Success:0; Fail: Failure Number

3.14.3 Description

将 driver 已经填充好数据的 buffer 出列,供应用使用。

应用程序根据 index 来识别 buffer,此时 m.offset 表示 buffer 对应的物理地址。

3.15 VIDIOC_QBUF

3.15.1 Parameters

Buffer type ,index and memory map type(struct v4l2_buffer *buf)

3.15.2 Returns

Success:0; Fail: Failure Number

3.15.3 Description

将 User 空间已经处理过的 buffer,重新入队,移交给 driver,等待填充数据。

应用程序根据 index 来识别 buffer。

3.16 VIDIOC_STREAMON

3.16.1 Parameters

Buffer type(enum v4l2_buf_type *type)

3.16.2 Returns

Success:0; Fail: Failure Number

3.16.3 Description

此处的 buffer type 为 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE。运行此 IOCTL, 将 buffer 队列中所有 buffer 入队,并开启 CSIC DMA 硬件中断,每次中断便表示完成一帧 buffer 数据的填入。

3.17 VIDIOC_STREAMOFF

3.17.1 Parameters

Buffer type(enum v4l2_buf_type *type)

3.17.2 Returns

Success:0; Fail: Failure Number

3.17.3 Description

此处的 buffer type 为 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE。运行此 IOCTL,停止捕捉视频,将 frame buffer 队列清空,以及 video buffer 释放。

3.18 VIDIOC_QUERYCTRL

3.18.1 Parameters

Control id and value(struct v4l2_queryctrl *qc)
struct v4l2_queryctrl {
    __u32 id;
    enum v4l2_ctrl_type type;
    __u8 name[32]; /* Whatever */
    __s32 minimum; /* Note signedness */
    __s32 maximum;
    __s32 step;
    __s32 default_value;
    __u32 flags;
    __u32 reserved[2];
};

3.18.2 Returns

Success:0; Fail: Failure Number

3.18.3 Description

应用程序通过 id 参数,驱动返回需要调节参数的 name,minmum,maximum,default_value 以及步进 step。(由 v4l2 conctrols framework 完成)目前可能支持的 id 请参考 VIDIOC_S_CTRL。

3.19 VIDIOC_S_CTRL

3.19.1 Parameters

Control id and value(struct v4l2_queryctrl *qc)
The same as VIDIOC_QUERYCTRL

3.19.2 Returns

Success:0; Fail: Failure Number

3.19.3 Description

应用程序通过 id,value 等参数,对 camera 驱动对应的参数进行设置。

驱动内部会先调用 vidioc_queryctrl,判断 id 是否支持,value 是否在 minimum 和 maximum 之间。(由 v4l2 conctrols framework 完成)目前可能支持的 id 和 value 参考附件。

3.20 VIDIOC_G_CTRL

3.20.1 Parameters

Control id and value(struct v4l2_queryctrl *qc)
The same as VIDIOC_QUERYCTRL

3.20.2 Returns

Success:0; Fail: Failure Number

3.20.3 Description

应用程序通过 id,驱动返回对应 id 当前设置的 value。

3.21 VIDIOC_ENUM_FRAMESIZES

3.21.1 Parameters

index,type,format(struct v4l2_frmsizeenum)
enum v4l2_frmsizetypes {
    V4L2_FRMSIZE_TYPE_DISCRETE = 1,
    V4L2_FRMSIZE_TYPE_CONTINUOUS = 2,
    V4L2_FRMSIZE_TYPE_STEPWISE = 3,
};

struct v4l2_frmsize_discrete {
    __u32 width; /* Frame width [pixel] */
    __u32 height; /* Frame height [pixel] */
};

struct v4l2_frmsize_stepwise {
    __u32 min_width;   /* Minimum frame width [pixel] */
    __u32 max_width;   /* Maximum frame width [pixel] */
    __u32 step_width;  /* Frame width step size [pixel] */
    __u32 min_height;  /* Minimum frame height [pixel] */
    __u32 max_height;  /* Maximum frame height [pixel] */
    __u32 step_height; /* Frame height step size [pixel] */
};

struct v4l2_frmsizeenum {
    __u32 index;        /* Frame size number */
    __u32 pixel_format; /* Pixel format */
    __u32 type;         /* Frame size type the device supports. */
    union {             /* Frame size */
        struct v4l2_frmsize_discrete discrete;
        struct v4l2_frmsize_stepwise stepwise;
	};
	__u32 reserved[2]; /* Reserved space for future use */
};

3.21.2 Returns

Success:0; Fail: Failure Number

3.21.3 Description

根据应用传进来的 index,pixel_format,驱动返回 type,并根据 type 填写 discrete 或 step-wise 的值。Discrete 表示分辨率固定的值;stepwise 表示分辨率有最小值和最大值,并根据step 递增。上层根据返回的 type,做对应不同的操作。

3.22 VIDIOC_ENUM_FRAMEINTERVALS

3.22.1 Parameters

Index,format,size,type(struct v4l2_frmivalenum)
enum v4l2_frmivaltypes {
    V4L2_FRMIVAL_TYPE_DISCRETE = 1,
    V4L2_FRMIVAL_TYPE_CONTINUOUS = 2,
    V4L2_FRMIVAL_TYPE_STEPWISE = 3,
};
struct v4l2_frmival_stepwise {
    struct v4l2_fract min;  /* Minimum frame interval [s] */
    struct v4l2_fract max;  /* Maximum frame interval [s] */
    struct v4l2_fract step; /* Frame interval step size [s] */
};
struct v4l2_frmivalenum {
    __u32 index;        /* Frame format index */
    __u32 pixel_format; /* Pixel format */
    __u32 width;        /* Frame width */
    __u32 height;       /* Frame height */
    __u32 type;         /* Frame interval type the device supports. */
    union {             /* Frame interval */
        struct v4l2_fract discrete;
        struct v4l2_frmival_stepwise stepwise;
    };
    __u32 reserved[2]; /* Reserved space for future use */
};

3.22.2 Returns

Success:0; Fail: Failure Number

3.22.3 Description

应用程序通过 pixel_format、width、height、驱动返回 type,并根据 type 填写

V4L2_FRMIVAL_TYPE_DISCRETE、V4L2_FRMIVAL_TYPE_CONTINUOUS 或V4L2_FRMIVAL_TYPE_STEPWISE。Discrete 表示支持单一的帧率;stepwise 表示支持步进的帧率。

3.23 VIDIOC_ISP_EXIF_REQ

作用: 得到当前照片的 EXIF 信息,填写到相应的编码域中。目的:对于 raw sensor 尽量填写正规的 EXIF 信息,yuv sensor 该 IOCTRL 也可以使用,不过驱动中填写的也是固定值。相关参数:

struct v4l2_fract {
    __u32 numerator;
    __u32 denominator;
};

struct isp_exif_attribute {
    struct v4l2_fract exposure_time;
    struct v4l2_fract shutter_speed;
    __u32 aperture;
    __u32 focal_length;
    __s32 exposure_bias;
    __u32 iso_speed;
    __u32 flash_fire;
    __u32 brightness;
};

struct v4l2_fract exposure_time;
曝光时间:分数类型,例如numerator = 1,denominator = 200,则表示1/200秒的曝光时间。

struct v4l2_fract shutter_speed;
快门速度:分数类型,例如numerator = 1,denominator = 200,则表示1/200秒的快门速度。(实际上和曝光时间数值相同)

__u32 aperture;
光圈大小:FNumber,例如aperture = 22,则表示,光圈大小为2.2,即FNumber = 22/10;

__u32 focal_length;
焦距:例如focal_length = 1400,则表示焦距为14mm,即FocalLength = 1400/100( mm);

__s32 exposure_bias;
曝光补偿:范围 -4~4

__u32 iso_speed;
感光速度:50~3200

__u32 flash_fire;
闪光灯是否开启:flash_fire = 1 表示闪光灯开启,flash_fire = 0 表示闪光灯未开启。

__u32 brightness;
图像亮度:0~255.

使用示例:
int V4L2CameraDevice::getExifInfo(struct isp_exif_attribute *exif_attri)
{
    int ret = -1;
    if (mCameraFd == NULL)
    {
	    return 0xFF000000;
    }
    ret = ioctl(mCameraFd, VIDIOC_ISP_EXIF_REQ, exif_attri);
    return ret;
}

4 模块使用范例

4.1 测试 demo

模块使用的 demo 的代码位于 drivers/media/platform/sunxi-vin/vin_test/mplane_image;此目录下可以直接 make 生成 demo;把 demo 推到机器里面执行便可以获取指定 video 节点的图像。推荐在 pc 上创建 bat 批处理文件,使用 adb 命令完成一系列抓图的动作,bat 内容参考如下,不同机器请注意修改 push 进去的路径:

del .\result\*.bin
adb root
adb remount
adb shell "mkdir /vendor/extsd/"
adb shell "mkdir /vendor/extsd/result"
adb shell rm /vendor/extsd/result/*.bin
adb push demo路径\csi_test_mplane /vendor/extsd/csi_test1
adb shell chmod 777 /vendor/extsd/csi_test1
adb shell "cd /vendor/extsd/ && ./csi_test1 0 0 1920 1080 ./result 1 20000 60 0"
adb shell ls /vendor/extsd/result
adb pull /vendor/extsd/result
pause

最后会在 bat 指令的文件夹生成 result 文件夹里面保存二进制的图像数据 *.bin 文件;可用 RawViewer 等软件查看图像数据。demo 参数说明:0 0 1920 1080 ./result 1 20000 60 0,分别表示 video0,set_input index0,目标分辨率宽,目标分辨率高,bin 文件保存路径、图像格式(如 NV21,具体含义可以看 demo 代码的 s_fmt 参数)、采集帧数(帧数大于 10000 即为常开节点)、目标帧率、和是否开启 wdr。

4.2 调用流程

全志 芯片 Linux MIPI CSI摄像头接口开发指南 VIN DVP CSI MIPI V4l2

​ 图 4-1: CSI 调用流程

5 FAQ

5.1 调试方法

5.1.1 调试节点

全志 芯片 Linux MIPI CSI摄像头接口开发指南 VIN DVP CSI MIPI V4l2

​ 图 5-1: vi 节点

当系统打开 DEBUG_FS 编译宏时,可以 cat /sys/kernel/debug/mpp/vi 查看;否则可以

cat /sys/devices/platform/soc@2900000/2000800.vind/vi。

vi 节点保存的是当前或上一次工作(当前没有工作)的状态。下面对 vi 节点的关键信息进行说明。

CSI_TOP、CSI_ISP 分别是对应 CSI、和 ISP 的工作频率;input 一行表示 CSI 接收到的图片尺寸,fmt 表示输入数据的格式;

output 表示 CSI 出尺寸,如果使用了缩放或者裁剪,那么输入输出尺寸会不一致,fmt 表示数据的输出格式;

最后一行分别表示平均帧间隔、最大帧间隔、最小帧间隔,可以计算得出帧率,调试帧率时可以参考。

5.1.2 settle time

方式一:修改对应 sensor 驱动中的 sensor_probe 函数,可以添加或修改 info->time_hs 的值即可。

全志 芯片 Linux MIPI CSI摄像头接口开发指南 VIN DVP CSI MIPI V4l2

​ 图 5-2: info->time_hs

方式二:通过 mipi 子设备的 settle_time 节点在线进行修改,settle_time 节点路径:/sys/devices/platform/soc/5800800.vind/5810100.mipi。

进入节点路径后,可以看到当前目录下存在 settle_time 节点:

全志 芯片 Linux MIPI CSI摄像头接口开发指南 VIN DVP CSI MIPI V4l2

​ 图 5-3: settle time 节点

可以通过 cat、echo 命令,对 settle_time 节点进行读写操作:

全志 芯片 Linux MIPI CSI摄像头接口开发指南 VIN DVP CSI MIPI V4l2

​ 图 5-4: settle time 节点读写

调整策略:settle time 的值慢慢增大调整,调大直到不能出图,再取一个略低于最大值的数值即可。调整范围:0x00-0xff。

5.1.3 信号状态

介绍如何观测 SOC 主控的接收数据的信号状态,分别对 MIPI 和并口做出说明。

5.1.3.1 MIPI

MIPI 传输模式有两种:

LP(Low-Power)模式:用于传输控制信号,最高速率 10 MHz。

HS(High-Speed)模式:用于高速传输数据,以 MIPI DPHY V1.1 版本为例,速率范围 [80Mbps - 1.5Gbps] per Lane。

可以通过查看 user manual MIPI PHY 部分寄存器,观测 SOC 识别到的 clock lane 和 data lane 的 LP、HS 状态。

5.1.3.2 并口

对于并口接口的 sensor,可以查看 user manual CSI PARSER 部分的 parser signal 寄存器,观测 sensor 端 PCLK、DATA 的信号状态。以此判断 parser 是否有识别到 sensor 端发送的数据。

5.2 常见问题

5.2.1 I2C 不通

如下图打印:

全志 芯片 Linux MIPI CSI摄像头接口开发指南 VIN DVP CSI MIPI V4l2

​ 图 5-5: i2c 不通

【分析步骤一】:确认供电、MCLK、i2c 上拉等外围电路信号是否正常。使用万用表测量板子上AVDD、DVDD、IOVDD 供电电压、MCLK 频率、幅度、RESET、PWDN 的电平是否符合要求。

【分析步骤二】:确认 i2c 地址,TWI 通道是否和原理图一致。

【分析步骤三】:以上都正常就用示波器或者逻辑分析仪测量分析主控发出 i2c 波形是否正确、有无回应;最后可以考虑 sensor 损坏或者接口错位等问题。

5.2.2 sensor 不出图

【分析步骤一】:确认 chip id 和 datasheet 上一致。

在对应 sensor 驱动的 sensor_detect 函数中读 chip id 寄存器,这一步也能检验 i2c 的读写是否正确。

【分析步骤二】:确认配置已经配置到 sensor 里。

可以把写进去的寄存器读出来和写入值对比是否一致。

【分析步骤三】:确认配置正确并且 sensor 已经输出图像。

和原厂确认寄存器配置、用示波器测量 sensor 端的 mipi 数据 lane 和时钟 lane 波形,分析是否正在发送数据。

【分析步骤四】:确认 SOC 是否接收到 sensor 数据。

  1. mipi 的 clock lane 存在两种工作模式,一种是连续时钟模式,传输过程不会切换 LP 状态;另一种是非连续时钟信号模式,每传输完一帧图像数据,帧 blanking 时将会切换为 LP 状态。目前大部分 MIPI sensor 一般都是非连续时钟模式。

  2. 如果 sensor 是连续时钟模式,要保证 MIPI 在 sensor 之前初始化,需要在 sensor 驱动 sensor_probe() 中配置 info->stream_seq = MIPI_BEFORE_SENSOR;

  3. 如果 sensor 是非连续时钟模式,可以通过判断 SOC 识别到的 LP、HS 模式状态是否在不断切换,来间接判断 SOC 的 MIPI 的接收状态。

  4. 查看 user manual MIPI PHY 部分寄存器,观测 clock lane 和 data lane 的 LP、HS 状态是否有在不断切换,有则说明 MIPI 已经接收到了 sensor 发送的数据。如果没有切换则说明 MIPI 没有正确接收 sensor 数据。此时应该检查 MIPI 相关配置是否正确。

【分析步骤五】:尝试修改 settle time。

如果可以确定 sensor 已经在正确发送数据,只是 MIPI 这边一直接收不到导致无法出图,可以尝试修改 settle time(参考调试方法章节)。

5.2.3 已出图但画面是绿色或者粉红色

一般是 YUYV 顺序反了,可以修改 sensor 驱动中 sensor_formats 结构体的 mbus_code 参数,修改 YUV 顺序即可。

5.2.4 I2c 已通,但是读所有 sensor 寄存器值都为 0

【分析步骤一】检查 i2c 通讯 addr 和 data 的位宽。

检查 sensor 驱动中 cci_drv 结构体中定义的值是否符合 datasheet 要求。

【分析步骤二】检查 i2c 通讯数据大小端是否不一致。

可以在读 sensor id 时把地址高低位相反来快速验证一下。

5.2.5 画面旋转 180 度

可以修改 board.dts 里面的 hflip 和 vflip 来解决,如果画面和人眼成 90 度的话,只能通过修改 sensor 配置来解决(只有部分 sensor 支持)。

5.2.6 没有 video 节点

【问题解析】没有加载 ko 或者 ko 加载失败。

【分析步骤一】检查模块加载顺序是否正确。

lsmod 看一下模块是否加载正确,如果报的错误是 [VIN_ERR]registering gc2355_mipi, No such device! 则表明 sensor 模块 gc2355_mipi 没有加载。

【分析步骤二】检查 board.dts 文件配置是否配置了 vind0,且 status 为 okay。

【分析步骤三】如果是加载失败检查加载失败的原始是 i2c 不通还是没有 ko。

i2c 不通参考前面的分析,没有 ko 请检查是否有对应的驱动并且在 Makefile 中使能了编译。