Tina Linux Camera开发指南

image-20221123145359081 image-20221123145359081 image-20221123145359081 image-20221123145359081 image-20221123145359081

Tina Linux Camera开发指南

1 概述

编写目的:介绍camera 模块在sunxi 平台上的开发流程。

适用范围:本文档目前适用于tina3.0 以上具备camera 的硬件平台。

2 模块介绍

2.1 模块功能介绍

用于接收并行或者mipi 接口的sensor 信号或者是bt656 格式的信号。

2.2 硬件介绍

目前Tina 系统的各平台camera 硬件接口、linux 内核版本以及camera 驱动框架如下表所示:

表2-1: 平台CSI 框架
平台支持接口是否具备ISP模块linux 内核版本camera 驱动框架
F35 并口csi、mipi 3.4 VFE
R16 并口csi 3.4 VFE
R18 并口csi 4.4 VFE
R30 并口csi 4.4 VFE
R40 并口csi 3.10 VFE
R311 mipi csi 4.9 VIN
MR133 mipi csi 4.9 VIN
R818 mipi csi 4.9 VIN
MR813 mipi csi 4.9 VIN
R528 并口csi 5.4 VIN
V536 并口csi、mipi 4.9 VIN
V533 并口csi、mipi 4.9 VIN
V831 并口csi、mipi 4.9 VIN
V833 并口csi、mipi 4.9 VIN
V851 并口csi、mipi 4.9 VIN
V853 并口csi、mipi 4.9 VIN

注意:

  1. 如果平台没有ISP 模块,那么将不支持RAW sensor(即sensor 只输出采集到的原始数据),文档中提到的RAW 等相关信息不用理会;

  2. 如果平台没有支持mipi 接口,文档中提到的mipi 相关信息忽略;

  3. 不同平台可能将使用不同的camera 驱动框架,这点注意区分;

2.3 源码结构介绍

2.3.1 linux3.4 VFE 框架

驱动路径位于linux-3.4/drivers/media/video/sunxi-vfe 下。

sunxi-vfe:.
│ bsp_common.c ;底层bsp共用的函数
│ bsp_common.h ;底层bsp共用函数头文件
│ config.c ;读取sys_config.fex的参数配置和isp参数
│ config.h ;读取sys_config.fex和isp参数函数的头文件
│ Kconfig
│ Makefile
│ platform_cfg.h ;区分各个平台的头文件
│ vfe.c ;v4l2驱动实现主体(包含视频接口和ISP部分)
│ vfe.h ;v4l2驱动头文件
│ vfe_os.c ;系统资源函数实现(pin,clock,memory)
│ vfe_os.h ;系统资源函数头文件
│ vfe_subdev.c ;sensor调用vfe资源函数
│ vfe_subdev.h ;sensor 调用vfe资源函数头文件

├─actuator
│ actuator.c ;vcm driver的一般行为
│ actuator.h ;vcm driver的头文件
│ dw9714_act.c ;具体vcm driver型号实现
│ Makefile

├─csi
│ bsp_csi.c ;底层csi bsp函数
│ bsp_csi.h ;底层csi bsp函数头文件
│ csi_reg.c ;csi硬件底层实现
│ csi_reg.h ;csi硬件底层实现头文件
│ csi_reg_i.h ;csi 寄存器资源头文件

├─device
│ camera.h ;camera公用结构体头文件
│ camera_cfg.h ;camera ioctl扩展命令头文件
│ Makefile
│ ov5640.c ;具体的sensor驱动

├─flash_light
│ flash.h ;led补光灯驱动头文件
│ flash_io.c ;led补光灯io控制实现
│ Makefile

├─lib
│ bsp_isp.h ;底层isp bsp函数头文件
│ bsp_isp_algo.h ;底层isp 算法bsp函数头文件
│ bsp_isp_comm.h ;底层isp共用函数头文件
│ isp_module_cfg.h ;isp里面各模块功能配置的头文件
│ libisp ;isp的函数库
│ lib_mipicsi2_v1 ;A31mipi库
│ lib_mipicsi2_v2 ;A80/A83mipi库
├─csi_cci
│ cci_helper.c ;cci 与设备相关初始化、注册以及通信等相关函数集实现
│ cci_helper.h ;cci 与设备相关初始化、注册以及通信等相关函数集实现头文件
│ bsp_cci.c ;cci 操作函数集实现
│ bsp_cci.h ;cci 操作函数集头文件
│ csi_cci_reg.c ;cci 底层实现
│ csi_cci_reg.h ;cci 底层实现头文件
│ csi_cci_reg_i.h ;cci寄存器资源头文件

├─mipi_csi
│ bsp_mipi_csi.c ;底层mipi bsp函数
│ bsp_mipi_csi.h ;底层mipi bsp函数头文件

└─utility
cfg_op.c ;读取ini文件的实现函数
cfg_op.h ;读取ini文件函数对应的头文件

2.3.2 linux3.10 VFE 框架

驱动路径位于linux-3.10/drivers/media/platform/sunxi-vfe 下。

sunxi-vfe:.
│ bsp_common.c ;底层bsp共用的函数
│ bsp_common.h ;底层bsp共用函数头文件
│ config.c ;读取sys_config.fex的参数配置和isp参数
│ config.h ;读取sys_config.fex和isp参数函数的头文件
│ Kconfig
│ Makefile
│ platform_cfg.h ;区分各个平台的头文件
│ vfe.c ;v4l2驱动实现主体(包含视频接口和ISP部分)
│ vfe.h ;v4l2驱动头文件
│ vfe_os.c ;系统资源函数实现(pin,clock,memory)
│ vfe_os.h ;系统资源函数头文件
│ vfe_subdev.c ;sensor调用vfe资源函数
│ vfe_subdev.h ;sensor 调用vfe资源函数头文件

├─actuator
│ actuator.c ;vcm driver的一般行为
│ actuator.h ;vcm driver的头文件
│ dw9714_act.c ;具体vcm driver型号实现
│ Makefile

├─csi
│ bsp_csi.c ;底层csi bsp函数
│ bsp_csi.h ;底层csi bsp函数头文件
│ csi_reg.c ;csi硬件底层实现
│ csi_reg.h ;csi硬件底层实现头文件
│ csi_reg_i.h ;csi 寄存器资源头文件

├─device
│ camera.h ;camera公用结构体头文件
│ camera_cfg.h ;camera ioctl扩展命令头文件
│ Makefile
│ ov5640.c ;具体的sensor驱动

├─flash_light
│ flash.h ;led补光灯驱动头文件
│ flash_io.c ;led补光灯io控制实现
│ Makefile

├─lib
│ bsp_isp.h ;底层isp bsp函数头文件
│ bsp_isp_algo.h ;底层isp 算法bsp函数头文件
│ bsp_isp_comm.h ;底层isp共用函数头文件
│ isp_module_cfg.h ;isp里面各模块功能配置的头文件
│ libisp ;isp的函数库
│ lib_mipicsi2_v1 ;A31mipi库
│ lib_mipicsi2_v2 ;A80/A83mipi库
├─csi_cci
│ cci_helper.c ;cci 与设备相关初始化、注册以及通信等相关函数集实现
│ cci_helper.h ;cci 与设备相关初始化、注册以及通信等相关函数集实现头文件
│ bsp_cci.c ;cci 操作函数集实现
│ bsp_cci.h ;cci 操作函数集头文件
│ csi_cci_reg.c ;cci 底层实现
│ csi_cci_reg.h ;cci 底层实现头文件
│ csi_cci_reg_i.h ;cci寄存器资源头文件

├─mipi_csi
│ bsp_mipi_csi.c ;底层mipi bsp函数
│ bsp_mipi_csi.h ;底层mipi bsp函数头文件

└─utility
cfg_op.c ;读取ini文件的实现函数
cfg_op.h ;读取ini文件函数对应的头文件

2.3.3 linux4.4 VFE 框架

驱动路径位于linux-4.4/drivers/media/platform/sunxi-vfe 下。

sunxi-vfe:.
│ bsp_common.c ;底层bsp共用的函数
│ bsp_common.h ;底层bsp共用函数头文件
│ config.c ;读取sys_config.fex的参数配置和isp参数
│ config.h ;读取sys_config.fex和isp参数函数的头文件
│ Kconfig
│ Makefile
│ platform_cfg.h ;区分各个平台的头文件
│ vfe.c ;v4l2驱动实现主体(包含视频接口和ISP部分)
│ vfe.h ;v4l2驱动头文件
│ vfe_os.c ;系统资源函数实现(pin,clock,memory)
│ vfe_os.h ;系统资源函数头文件
│ vfe_subdev.c ;sensor调用vfe资源函数
│ vfe_subdev.h ;sensor 调用vfe资源函数头文件

├─actuator
│ actuator.c ;vcm driver的一般行为
│ actuator.h ;vcm driver的头文件
│ dw9714_act.c ;具体vcm driver型号实现
│ Makefile

├─csi
│ bsp_csi.c ;底层csi bsp函数
│ bsp_csi.h ;底层csi bsp函数头文件
│ csi_reg.c ;csi硬件底层实现
│ csi_reg.h ;csi硬件底层实现头文件
│ csi_reg_i.h ;csi 寄存器资源头文件

├─device
│ camera.h ;camera公用结构体头文件
│ camera_cfg.h ;camera ioctl扩展命令头文件
│ Makefile
│ ov5640.c ;具体的sensor驱动

├─flash_light
│ flash.h ;led补光灯驱动头文件
│ flash_io.c ;led补光灯io控制实现
│ Makefile

├─lib
│ bsp_isp.h ;底层isp bsp函数头文件
│ bsp_isp_algo.h ;底层isp 算法bsp函数头文件
│ bsp_isp_comm.h ;底层isp共用函数头文件
│ isp_module_cfg.h ;isp里面各模块功能配置的头文件
│ libisp ;isp的函数库
│ lib_mipicsi2_v1 ;A31mipi库
│ lib_mipicsi2_v2 ;A80/A83mipi库
├─csi_cci
│ cci_helper.c ;cci 与设备相关初始化、注册以及通信等相关函数集实现
│ cci_helper.h ;cci 与设备相关初始化、注册以及通信等相关函数集实现头文件
│ bsp_cci.c ;cci 操作函数集实现
│ bsp_cci.h ;cci 操作函数集头文件
│ csi_cci_reg.c ;cci 底层实现
│ csi_cci_reg.h ;cci 底层实现头文件
│ csi_cci_reg_i.h ;cci寄存器资源头文件

├─mipi_csi
│ bsp_mipi_csi.c ;底层mipi bsp函数
│ bsp_mipi_csi.h ;底层mipi bsp函数头文件

└─utility
cfg_op.c ;读取ini文件的实现函数
cfg_op.h ;读取ini文件函数对应的头文件

2.3.4 linux4.4 VIN 框架

驱动路径位于linux-4.4/drivers/media/platform/sunxi-vin 下。

sunxi-vin:
│ vin.c ;v4l2驱动实现主体(包含视频接口和ISP部分)
│ vin.h ;v4l2驱动头文件
│ top_reg.c ;vin对各v4l2 subdev管理接口实现主体
│ top_reg.h ;管理接口头文件
│ top_reg_i.h ;vin模块接口层部分结构体

├─modules
│ ├─actuator
│ │ actuator.c ;vcm driver的一般行为
│ │ actuator.h ;vcm driver的头文件
│ │ dw9714_act.c ;具体vcm driver型号实现
│ │ Makefile
│ ├─flash
│ │ flash.h ;led补光灯驱动头文件
│ │ flash_io.c ;led补光灯io控制实现
│ ├─sensor
│ │ camera.h ;camera公用结构体头文件
│ │ camera_cfg.h ;camera ioctl扩展命令头文件
│ │ sensor_helper.c ;sensor公用操作接口函数文件
│ │ sensor_helper.h ;sensor公用操作接口函数头文件
│ │ Makefile
│ │ ov5640.c ;具体的sensor驱动

├─platform
│ platform_cfg.h ;平台相关的配置接口

├─utility
│ bsp_common.h ;底层公用的格式配置函数头文件
│ bsp_common.c ;底层公用的格式配置函数文件
│ cfg_op.h ;解析配置文件接口头文件
│ cfg_op.c ;解析配置文件接口函数实现主体
│ config.h ;解析设备树的函数头文件
│ config.c ;解析设备树的接口函数主体
│ sensor_info.h ;sensor列表信息头文件
│ sensor_info.c ;获取sensor列表信息函数主体
│ vin_io.h ;vin框架io操作接口头文件
│ vin_io.c ;vin框架io操作接口文件
│ vin_os.h ;vin框架系统操作接口头文件
│ vin_os.c ;vin框架系统操作接口文件
│ vin_supply.h ;vin框架设置时钟频率等接口头文件
│ vin_supply.c ;vin框架设置时钟频率等接口函数主体

├─vin-cci
│ cci_helper.c ;cci 与设备相关初始化、注册以及通信等相关函数集实现
│ cci_helper.h ;cci 与设备相关初始化、注册以及通信等相关函数集实现头文件
│ bsp_cci.c ;cci 操作函数集实现
│ bsp_cci.h ;cci 操作函数集头文件
│ csi_cci_reg.c ;cci 底层实现
│ csi_cci_reg.h ;cci 底层实现头文件
│ csi_cci_reg_i.h ;cci寄存器资源头文件
│ sunxi_cci.c ;cci 接口封装实现
│ sunxi_cci.h ;cci 接口封装头文件

├─vin-csi
│ bsp_csi.c ;csi 操作函数集实现
│ bsp_csi.h ;csi 操作函数集头文件
│ csi_reg.c ;csi 底层实现
│ csi_reg.h ;csi 底层实现头文件
│ csi_reg_i.h ;csi寄存器资源头文件
│ parser_reg.c ;csi 底层实现
│ parser_reg.h ;csi 底层实现头文件
│ parser_reg_i.h ;csi寄存器资源头文件
│ sunxi_csi.c ;csi 接口封装实现
│ sunxi_csi.h ;csi 接口封装头文件

├─vin-isp
│ bsp_isp.c ;isp操作函数集实现
│ bsp_isp.h ;isp操作函数集头文件
│ bsp_isp_comm.h ;isp结构体定义
│ isp_default_tbl.h ;isp默认配置列表
│ isp_platform_drv.h ;isp平台操作集头文件
│ isp_platform_drv.c ;isp平台操作集实现
│ sunxi_isp.h ;sunxi平台isp操作集头文件
│ sunxi_isp.c ;sunxi平台isp操作集实现

├─vin-mipi
│ bsp_mipi_csi.c ;底层mipi bsp函数
│ bsp_mipi_csi.h ;底层mipi bsp函数头文件
│ bsp_mipi_csi_v1.c ;sunxi平台底层mipi bsp接口函数
│ sunxi_mipi.c ;sunxi平台mipi实现
│ bsp_mipi_csi.h ;sunxi平台mipi实现头文件
│ combo_common.c ;combo common头文件
│ protocol.h ;protocol头文件
├─vin-stat
│ vin_h3a.c ;vin 3a操作函数
│ vin_h3a.h ;vin 3a操作函数头文件
│ vin_ispstat.c ;sunxi isp stat操作函数
│ vin_ispstat.h ;sunxi isp stat操作函数头文件

├─vin-video
│ dma_reg.c ;csi模块dma操作函数
│ dma_reg.h ;csi模块dma操作函数头文件
│ dma_reg_i.h ;csi dma寄存器资源头文件
│ vin_core.c ;vin video核心函数
│ vin_core.h ;vin video核心函数头文件
│ vin_video.c ;vin video设备接口函数
│ vin_video.h ;vin video设备接口函数头文件
├─vin-vipp
│ sunxi_scaler.c ;scaler 子设备操作函数集
│ sunxi_scaler.h ;caler 子设备操作函数头文件
│ vipp_reg.c ;vipp操作函数集
│ vipp_reg.h ;vipp操作函数集头文件
│ vipp_reg_i.h ;vipp操作函数集资源头文件

2.3.5 linux4.9 VIN 框架

驱动路径位于linux-4.9/drivers/media/platform/sunxi-vin 下。

sunxi-vin:
│ vin.c ;v4l2驱动实现主体(包含视频接口和ISP部分)
│ vin.h ;v4l2驱动头文件
│ top_reg.c ;vin对各v4l2 subdev管理接口实现主体
│ top_reg.h ;管理接口头文件
│ top_reg_i.h ;vin模块接口层部分结构体
├── modules
│ ├── actuator ;vcm driver
│ │ ├── actuator.c
│ │ ├── actuator.h
│ │ ├── dw9714_act.c
│ │ ├── Makefile
│ ├── flash ;闪光灯driver
│ │ ├── flash.c
│ │ └── flash.h
│ └── sensor ;sensor driver
│ ├── ar0144_mipi.c
│ ├── camera_cfg.h ;camera ioctl扩展命令头文件
│ ├── camera.h ;camera公用结构体头文件
│ ├── Makefile
│ ├── ov2775_mipi.c
│ ├── ov5640.c
│ ├── sensor-compat-ioctl32.c
│ ├── sensor_helper.c ;sensor公用操作接口函数文件
│ ├── sensor_helper.h
├── platform ;平台相关的配置接口
├── utility
│ ├── bsp_common.c
│ ├── bsp_common.h
│ ├── cfg_op.c
│ ├── cfg_op.h
│ ├── config.c
│ ├── config.h
│ ├── sensor_info.c
│ ├── sensor_info.h
│ ├── vin_io.h
│ ├── vin_os.c
│ ├── vin_os.h
│ ├── vin_supply.c
│ └── vin_supply.h
├── vin-cci
│ ├── sunxi_cci.c
│ └── sunxi_cci.h
├── vin-csi
│ ├── parser_reg.c
│ ├── parser_reg.h
│ ├── parser_reg_i.h
│ ├── sunxi_csi.c
│ └── sunxi_csi.h
├── vin-isp
│ ├── sunxi_isp.c
│ └── sunxi_isp.h
├── vin-mipi
│ ├── sunxi_mipi.c
│ └── sunxi_mipi.h
├── vin-stat
│ ├── vin_h3a.c
│ ├── vin_h3a.h
│ ├── vin_ispstat.c
│ └── vin_ispstat.h
├── vin_test
├── vin-video
│ ├── vin_core.c
│ ├── vin_core.h
│ ├── vin_video.c
│ └── vin_video.h
└── vin-vipp
├── sunxi_scaler.c
├── sunxi_scaler.h
├── vipp_reg.c
├── vipp_reg.h
└── vipp_reg_i.h

2.3.6 linux5.4 VIN 框架

驱动路径位于linux-5.4/drivers/media/platform/sunxi-vin 下。

sunxi-vin:
├── Kconfig
├── Makefile
├── modules
│ ├── actuator ;vcm driver
│ │ ├── actuator.c
│ │ ├── actuator.h
│ │ ├── dw9714_act.c
│ │ ├── Makefile
│ ├── flash ;flash driver
│ │ ├── flash.c
│ │ └── flash.h
│ ├── sensor ;cmos sensor driver
│ │ ├── camera_cfg.h
│ │ ├── camera.h
│ │ ├── gc0310_mipi.c
│ │ ├── Makefile
│ │ ├── ov2710_mipi.c
│ │ ├── ov5640.c
│ │ ├── sensor-compat-ioctl32.c
│ │ ├── sensor_helper.c
│ │ ├── sensor_helper.h
│ ├── sensor-list
│ │ ├── sensor_list.c
│ │ └── sensor_list.h
│ └── sensor_power ;sensor上下电接口函数
│ ├── Makefile
│ ├── sensor_power.c
│ └── sensor_power.h
├── platform
├── top_reg.c
├── top_reg.h
├── top_reg_i.h
├── utility ;驱动通用接口
│ ├── bsp_common.c
│ ├── bsp_common.h
│ ├── cfg_op.c
│ ├── cfg_op.h
│ ├── config.c
│ ├── config.h
│ ├── vin_io.h
│ ├── vin_os.c
│ ├── vin_os.h
│ ├── vin_supply.c
│ └── vin_supply.h
├── vin.c ;sunxi-vin驱动注册入口
├── vin-cci ;i2c操作相关接口
│ ├── bsp_cci.c
│ ├── bsp_cci.h
│ ├── cci_helper.c
│ ├── cci_helper.h
│ ├── Kconfig
│ ├── sunxi_cci.c
│ └── sunxi_cci.h
├── vin-csi ;csi操作相关接口
│ ├── sunxi_csi.c
│ └── sunxi_csi.h
├── vin.h
├── vin-isp ;isp驱动
│ ├── sunxi_isp.c
│ └── sunxi_isp.h
├── vin-mipi ;mipi驱动
│ ├── sunxi_mipi.c
│ └── sunxi_mipi.h
├── vin-stat
│ ├── vin_h3a.c
│ └── vin_h3a.h
├── vin-tdm
│ ├── vin_tdm.c
│ └── vin_tdm.h
├── vin-video ;video节点相关的接口定义
│ ├── vin_core.c
│ ├── vin_core.h
│ ├── vin_video.c
│ └── vin_video.h
└── vin-vipp
├── sunxi_scaler.c
├── sunxi_scaler.h

3 模块开发

3.1 模块体系结构描述

3.1.1 VFE 框架

• 使用过程中可简单的看成是vfe 模块+ device 模块+af driver + flash 控制模块的方式;

• vfe.c 是驱动的主要功能实现,包括注册/注销、参数读取、与v4l2 上层接口、与各device 的下层接口、中断处理、buffer 申请切换等;

• device 文件夹里面是各个sensor 的器件层实现,一般包括上下电、初始化,各分辨率切换,yuv sensor 包括绝大部分的v4l2 定义的ioctrl 命令的实现;而raw

sensor 的话大部分 ioctrl 命令在vfe 层调用isp 的库实现,少数如曝光/增益调节会透过vfe 层到实际器件层;

• actuator 文件夹内是各种vcm 的驱动;

• flash_light 文件夹内是闪光灯控制接口实现;

• csi 和mipi_csi 为对csi 接口和mipi 接口的控制文件;

• lib 文件夹为isp 的库文件;

• linux-3.0 前的版本相当于vivi.c+csi bsp 层

• linux-3.4 版本支持isp 驱动和双CSI

• linux-3.10 版本将mipi/csi/isp 模块化(由vfe.c 直接调用=>v4l2_subdev_ops), 支持device tree

image-20221122095738625

图3-1: VFE

3.1.2 VIN 框架

• 使用过程中可简单的看成是vin 模块+ device 模块+af driver + flash 控制模块的方式;

• vin.c 是驱动的主要功能实现,包括注册/注销、参数读取、与v4l2 上层接口、与各device 的下层接口、中断处理、buffer 申请切换等;

• modules/sensor 文件夹里面是各个sensor 的器件层实现,一般包括上下电、初始化,各分辨率切换,yuv sensor 包括绝大部分的v4l2 定义的ioctrl 命令的实

现;而raw sensor 的话大部分ioctrl 命令在vin 层调用isp 库实现,少数如曝光/增益调节会透过vin 层到实际器件层;

• modules/actuator 文件夹内是各种vcm 的驱动;

• modules/flash 文件夹内是闪光灯控制接口实现;

• vin-csi 和vin-mipi 为对csi 接口和mipi 接口的控制文件;

• vin-isp 文件夹为isp 的库操作文件;

• vin-video 文件夹内主要是video 设备操作文件;

image-20221122113602939

图3-2: VIN

3.1.3 Camera 通路框架

• VIN 支持灵活配置单/双路输入双ISP 多通路输出的规格

• 引入media 框架实现pipeline 管理

• 将libisp 移植到用户空间解决GPL 问题

• 将统计buffer 独立为v4l2 subdev

• 将的scaler(vipp)模块独立为v4l2 subdev

• 将video buffer 修改为mplane 方式,使用户层取图更方便

• 采用v4l2-event 实现事件管理

• 采用v4l2-controls 新特性

image-20221122113645959

图3-3: camera Input

3.2 驱动模块实现

3.2.1 硬件部分

检查硬件电源,gpio 是否和原理图一致并且正确连接;检查sys_config.fex 或者board.dts 是否正确配置,包括使用的电源名称和电压,详见CSI 板级配置章节说

明;如果是电源选择有多个源头的请确认板子上的连接正确,比如0ohm 电阻是否正确的焊接为0ohm,NC 的电阻是否有正确断开等等。带补光灯的也需要检查

灯和driver IC 和控制io 是否连好。

3.2.2 内核device 模块驱动

一般调试新模组的话建议以sdk 中的某个现成的驱动为基础修改:YUV 的并口模组以R40 平台(linux3.10) 的ov5640.c 为参考。

下面以ov5640.c 为例说明调试新模组需要注意的两点:

  1. 添加Makefile

[linux-3.10/drivers/media/platform/sunxi-vfe/device/Makefile]
添加
obj-m + = ov5640.o (详见1)
详注:
1.具体取决于使用的模组,如果是新模组则将驱动代码放置在该device目录下。
  1. 配置模组参数

配置参数在linux-3.10/drivers/media/platform/sunxi-vfe/device/ov5640.c 中,只需注意下面两个参数。

#define SENSOR_NAME "ov5640" (详见1)
#define I2C_ADDR 0x78 (详见2)
详注:
1.该参数为模组名,必须和sys_config.fex的csi0_dev0_mname或者board.dts的sensor0_mname保持一致。
2.I2C_ADDR可参考相应模组的datasheet,sys_config.fex的csi0_dev0_twi_addr与此值保持一致。
3.2.2.1 驱动宏定义
#define MCLK (24*1000*1000)

sensor 输入时钟频率,可查看模组厂提供的sensor datasheet,datasheet 中会有类似inputclock frequency: 6~27 MHz 信息,这个信息说明可提供给sensor 的

MCLK 可以在6 M 到27 M之间。其中MCLK 和使用的寄存器配置强相关,在模组厂提供寄存器配置时,可直接询问当前配置使用的MCLK 频率是多少。

#define VREF_POL V4L2_MBUS_VSYNC_ACTIVE_LOW
#define HREF_POL V4L2_MBUS_HSYNC_ACTIVE_HIGH
#define CLK_POL V4L2_MBUS_PCLK_SAMPLE_RISING

并口sensor 必须填写,MIPI sensor 无需填写,可在sensor 规格书找到,如下

image-20221122115215017

图3-4: timing

从上述的图像可得到以下信息:

  1. VSYNC 在低电平的时候,data pin 输出有效数据,所以VREF_POL 设置为V4L2_MBUS_VSYNC_ACTIVE_即低电平有效;

  2. HREF 在高电平的时候,data pin 输出有效数据,所以HREF_POL 设置为V4L2_MBUS_HSYNC_ACTIVE_即高电平有效;

  3. CLK_POL 则是表明SOC 是在sensor 输出的pclk 上升沿采集data pin 的数据还是下降沿采集数据,如果sensor 在pclk 上升沿改变data pin 的数据,那么SOC

应该在下降沿采集,CLK_POL 设置为V4L2_MBUS_PCLK_SAMPLE_FALLING;如果sensor在pclk 下降沿改变data pin 的数据,那么SOC 应该在上降沿采集,

CLK_POL 设置为V4L2_MBUS_PCLK_SAMPLE_RISING。

#define V4L2_IDENT_SENSOR 0x2770

一般填写sensor ID,用于sensor 检测。sensor ID 可在sensor 规格书的找到,如下

image-20221122115536252

图3-5: sensorid
#define I2C_ADDR 0x6c

sensor I2C 通讯地址,可在sensor 规格书找到,如下

image-20221122115814628

图3-6: sccbid
#define SENSOR_NAME OV5640

定义驱动名字,与系统其他文件填写的名字要一致,比如需要和sys_config.fex 中的sensorname 一致。

3.2.2.2 初始化代码
static struct regval_list sensor_default_regs[] = {}; /* 填写寄存器代码的公共部分*/
static struct regval_list sensor_XXX_regs[] = {}; /* 填写各模式的寄存器代码,不同的模式可以是分辨率、帧率等*/

上述部分的寄存器配置,公共部分可以忽略,直接在模式代码中配置sensor 即可,相应的寄存器配置,可让模组厂提供。

3.2.2.3 曝光增益接口函数
static int sensor_s_exp(struct v4l2_subdev *sd, unsigned int exp_val) /* 曝光函数*/
static int sensor_s_gain(struct v4l2_subdev *sd, unsigned int gain_val) /* 增益函数*/

AE 是同时控制曝光时间和增益的,所以需要在上面的函数中分别同时sensor 曝光和增益的寄存器。

image-20221122174724278

图3-7: expgain

根据规格书中的寄存器说明,在相应的函数配置即可。若设置exp/gain 无效,可能的原因有:

• sensor 寄存器打开了AE;

• 设置值超出了有效范围

具体可根据模组厂提供的配置设置,如若检查之后设置仍失效,可与模组厂沟通,确认配置是否正确。

3.2.2.4 上下电控制函数
static int sensor_power(struct v4l2_subdev *sd, int on)

控制sensor 上电、下电及进出待机状态,操作步骤须与规格书描述相同,注意power down 和reset pin 的电平变化。

image-20221122174813656

图3-8: powerup

驱动中,按照规格书的上电时序进行配置,而如果上电之后测量硬件并没有相应的电压,这时候 检查硬件和软件配置是否一致。关于csi 电源的配置,操作流程可如下:

  1. 先通过原理图确认sensor 模组的各路电源是连接到axp 的哪个ldo;

  2. 查看sys_config.fex 的regulator 配置,在相应的ldo 后增加相应的字段,比如“csi-vdd”等;

  3. 在sys_config.fex 的csi 部分,sensor 部分的电源后的字段再填写与上述一样的字段即可;

  4. 根据sensor 规格书的要求,填写相应的电压即可;

以上图为例,确认sensor 驱动中的上电时序。

static int sensor_power(struct v4l2_subdev *sd, int on)
{
    int ret;
    ret = 0;
    switch (on) {
    /* STBY_ON 和STBY_OFF 基本不使用,可忽略这两个选项的配置*/
    case STBY_ON:
        ...
        break;
    case STBY_OFF:
        ...
        break;
    /* 上电操作*/
    case PWR_ON:
        sensor_print("PWR_ON!\n");
        cci_lock(sd);
        /* 将PWDN、RESET 引脚设置为输出*/
        vin_gpio_set_status(sd, PWDN, 1);
        vin_gpio_set_status(sd, RESET, 1);
        /* 按照上图知道,上电前PWDN、RESET 信号为低,所以将其设置为低电平*/
        vin_gpio_write(sd, PWDN, CSI_GPIO_LOW);
        vin_gpio_write(sd, RESET, CSI_GPIO_LOW);
        /* 延时*/
        usleep_range(1000, 1200);
        /* CAMERAVDD 为SOC 中的供电电源,部分板子可以忽略该电源,
        * 因为有些板子会通过一个vcc-pe 给上拉电阻等供电,所以需要
        * 使能该路电,有些是直接和iovdd 共用了,所以有部分会忽略该
        * 路电源配置.
        */
        vin_set_pmu_channel(sd, CAMERAVDD, ON);
        /* 将PWDN 设置为高电平*/
        vin_gpio_write(sd, PWDN, CSI_GPIO_HIGH);
        /*AF上电*/
        vin_set_pmu_channel(sd, AFVDD, ON);
        /* AVDD 上电*/
        vin_set_pmu_channel(sd, AVDD, ON);
        /* 延时,延时时长为T1,T1 的大小在datasheet 的上电时序图下面有标注*/
        usleep_range(1000, 1200);
        /* DOVDD 上电*/
        vin_set_pmu_channel(sd, IOVDD, ON);
        /* 延时,按照上电时序中的标注的T2 时间延时*/
        usleep_range(1000, 1200);
        /* DVDD 上电*/
        vin_set_pmu_channel(sd, DVDD, ON);
        /* 延时,按照上电时序中的标注的T3 时间延时*/
        usleep_range(1000, 1200);
        /* 将PWDN 设置为低电平*/
        vin_gpio_write(sd, PWDN, CSI_GPIO_LOW);
        /* 设置MCLK 频率并使能*/
        vin_set_mclk_freq(sd, MCLK);
        vin_set_mclk(sd, ON);
        /* 延时,按照上电时序中的标注的T4 时间延时*/
        usleep_range(1000, 1200);
        /* 将RESET 设置为高电平*/
        vin_gpio_write(sd, RESET, CSI_GPIO_HIGH);
        /* 延时,按照上电时序中的标注的T6 时间延时*/
        usleep_range(10000, 12000);
        cci_unlock(sd);
        break;
    /* 掉电操作*/
        case PWR_OFF:
        sensor_print("PWR_OFF!\n");
        cci_lock(sd);
        /* 具体的掉电操作同样的按照datasheet 的power off 操作即可*/
        vin_gpio_write(sd, PWDN, CSI_GPIO_HIGH);
        vin_gpio_write(sd, RESET, CSI_GPIO_LOW);
        vin_set_mclk(sd, OFF);
        vin_set_pmu_channel(sd, AFVDD, OFF);
        vin_set_pmu_channel(sd, AVDD, OFF);
        vin_set_pmu_channel(sd, DVDD, OFF);
        vin_set_pmu_channel(sd, IOVDD, OFF);
        vin_set_pmu_channel(sd, CAMERAVDD, OFF);
        vin_gpio_set_status(sd, PWDN, 0);
        cci_unlock(sd);
        break;
    default:
    	return -EINVAL;
    }
    return 0;
}
3.2.2.5 检测函数
static int sensor_detect(struct v4l2_subdev *sd)

在开机加载驱动的时候,将会检测sensor ID,用于测试I2C 通讯是否正常和sensor 识别。

#define V4L2_IDENT_SENSOR 0x7750
    sensor_read(sd, 0x300A, &rdval);
    if (rdval != (V4L2_IDENT_SENSOR >> 8))
    	return -ENODEV;
    sensor_read(sd, 0x300B, &rdval);
    if (rdval != (V4L2_IDENT_SENSOR & 0xff))
    	return -ENODEV;

image-20221122175111168

图3-9: sensordetect
3.2.2.6 SENSOR 相关的IOCTL
static long sensor_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)

用于应用层获取曝光增益,及进行与sensor 相关模块的驱动控制,如对焦,闪光等

case VIDIOC_VIN_SENSOR_EXP_GAIN:/*设置sensor的曝光增益*/
    ret = sensor_s_exp_gain(sd, (struct sensor_exp_gain *)arg);
    break;
case VIDIOC_VIN_SENSOR_CFG_REQ:/*获取sensor驱动的基础配置信息*/
    sensor_cfg_req(sd, (struct sensor_config *)arg);
    break;
case VIDIOC_VIN_ACT_SET_CODE:/*设置对焦马达配置参数,在配置AF模块时,需要此ioctl*/
	actuator_set_code(sd, (struct actuator_ctrl *)arg);
3.2.2.7 与CSI 的接口
static struct sensor_format_struct sensor_formats[] = {};
RAW sensor:
.desc = "Raw RGB Bayer",
.mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
.regs = sensor_fmt_raw,
.regs_size = ARRAY_SIZE(sensor_fmt_raw),
.bpp = 1
YUV sensor:
.desc = "YUYV 4:2:2",
.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.regs = sensor_fmt_yuyv422_yuyv,
.regs_size = ARRAY_SIZE(sensor_fmt_yuyv422_yuyv),
.bpp = 2

其中,mbus_code 中BGGR 可以根据sensor raw data 输出顺序修改为GBRG/RGGB/-GRBG。若填错, 会导致色彩偏紫红和出现网格状纹理。10_1X10 表示10 bit

并口输出, 若是12 bit MIPI 输出, 则改为12_12X1。其他情况类推。对于DVP YUV sensor, 需根据yuv 输出顺序选择yuyv/vyuy/uyvy/yvyu 其中一种。

static int sensor_g_mbus_config(struct v4l2_subdev *sd,struct v4l2_mbus_config *cfg)
DVP sensor:
    cfg->type = V4L2_MBUS_PARALLEL;
    cfg->flags = V4L2_MBUS_MASTER | VREF_POL | HREF_POL | CLK_POL;
MIPI sensor:
    cfg->type = V4L2_MBUS_CSI2;
    cfg->flags = 0 | V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0;

其中,MIPI sensor 须根据实际使用的lane 数,修改V4L2_MBUS_CSI2_X_LANE 中的X值。如果使用LVDS 接口,需要将cfg->type 配置为V4L2_MBUS_SUBLVDS。

3.2.2.8 分辨率配置
static struct sensor_win_size sensor_win_sizes[] = {
{
    .width = VGA_WIDTH,
    .height = VGA_HEIGHT,
    .hoffset = 0,
    .voffset = 0,
    .hts = 928,
    .vts = 1720,
    .pclk = 48 * 1000 * 1000,
    .mipi_bps = 480 * 1000 * 1000,
    .fps_fixed = 30,
    .bin_factor = 1,
    .intg_min = 1 << 4,
    .intg_max = (1720) << 4,
    .gain_min = 1 << 4,
    .gain_max = 16 << 4,
    .regs = sensor_VGA_regs,
    .regs_size = ARRAY_SIZE(sensor_VGA_regs),
    .set_size = NULL,
},
{
    /* 定义图像输出的大小*/
    .width = VGA_WIDTH,
    .height = VGA_HEIGHT,
    /* 定义输入ISP 的偏移量,用于截取所需的Size,丢弃不需要的部分图像*/
    .hoffset = 0,
    .voffset = 0,
    /*
    定义行长(以pclk 为单位)、帧长(以hts 为单位) 和像素时钟频率。hts 又称line_length_pck,vts 又称frame_length_lines,与寄存器的值要一致。pclk(pixel clock)的值由PLL 寄存器计算得出。
    */
    .hts = 928,
    .vts = 1720,
    .pclk = 48 * 1000 * 1000,
    /* 定义MIPI 数据速率,MIPI sensor 必需,其他sensor 忽略*/
    /* mipi_bps = hts * vts * fps * raw bit / lane num */
    .mipi_bps = 480 * 1000 * 1000,
    /* 定义帧率,fps * hts * vts = pclk */
    .fps_fixed = 30,
    /*
    定义曝光行数最小值和最大值,增益最小值和最大值,以16 为1 倍。最值的设置应在sensor 规格和
    曝光函数限定的范围内,若超出会导致画面异常。此外,若AE table 中的最值超出这里的限制,会使得
    AE table 失效。
    */
    .intg_min = 1 << 4,
    .intg_max = (1720) << 4,
    .gain_min = 1 << 4,
    .gain_max = 16 << 4,
    /* (必需)说明这部分的配置对应哪个寄存器初始化代码*/
    .regs = sensor_VGA_regs,
    .regs_size = ARRAY_SIZE(sensor_VGA_regs),
    },
};

根据应用的需求,在这里配置驱动能输出的不同尺寸帧率组合,注意,一种分辨率、帧率配置为一个数组成员,不要混淆。

3.2.3 LVDS 接口须知

除了完成以上函数的实现,LVDS Sensor 驱动还需要完成combo 同步校验函数和combo 数据线映射函数。combo 校验码可以在sensor 规格书获取,combo 数

据线映射关系需要查看原理图设计进行配对,可参考imx274_slvds.c 完成开发。

image-20221122180028623

图3-10: SYNC_CODE
static void sensor_g_combo_sync_code(struct v4l2_subdev *sd,
struct combo_sync_code *sync)
{
    int i;
    for (i = 0; i < 12; i++) {
    sync->lane_sof[i].low_bit = 0x0000ab00;
    sync->lane_sof[i].high_bit = 0xFFFF0000;
    sync->lane_sol[i].low_bit = 0x00008000;
    sync->lane_sol[i].high_bit = 0xFFFF0000;
    sync->lane_eol[i].low_bit = 0x00009d00;
    sync->lane_eol[i].high_bit = 0xFFFF0000;
    sync->lane_eof[i].low_bit = 0x0000b600;
    sync->lane_eof[i].high_bit = 0xFFFF0000;
}
}
static void sensor_g_combo_lane_map(struct v4l2_subdev *sd,
	struct combo_lane_map *map)
	{
	struct sensor_info *info = to_state(sd);
    if (info->isp_wdr_mode == ISP_DOL_WDR_MODE) {
        map->lvds_lane0 = LVDS_MAPPING_A_D0_TO_LANE0;
        map->lvds_lane1 = LVDS_MAPPING_A_D1_TO_LANE1;
        map->lvds_lane2 = LVDS_MAPPING_B_D2_TO_LANE2;
        map->lvds_lane3 = LVDS_MAPPING_B_D0_TO_LANE3;
        map->lvds_lane4 = LVDS_MAPPING_B_D3_TO_LANE4;
        map->lvds_lane5 = LVDS_MAPPING_C_D2_TO_LANE5;
        map->lvds_lane6 = LVDS_LANE6_NO_USE;
        map->lvds_lane7 = LVDS_LANE7_NO_USE;
        map->lvds_lane8 = LVDS_LANE8_NO_USE;
        map->lvds_lane9 = LVDS_LANE9_NO_USE;
        map->lvds_lane10 = LVDS_LANE10_NO_USE;
        map->lvds_lane11 = LVDS_LANE11_NO_USE;
} else {
        map->lvds_lane0 = LVDS_MAPPING_A_D1_TO_LANE0;
        map->lvds_lane1 = LVDS_MAPPING_B_D2_TO_LANE1;
        map->lvds_lane2 = LVDS_MAPPING_B_D0_TO_LANE2;
        map->lvds_lane3 = LVDS_MAPPING_B_D3_TO_LANE3;
        map->lvds_lane4 = LVDS_LANE4_NO_USE;
        map->lvds_lane5 = LVDS_LANE5_NO_USE;
        map->lvds_lane6 = LVDS_LANE6_NO_USE;
        map->lvds_lane7 = LVDS_LANE7_NO_USE;
        map->lvds_lane8 = LVDS_LANE8_NO_USE;
        map->lvds_lane9 = LVDS_LANE9_NO_USE;
        map->lvds_lane10 = LVDS_LANE10_NO_USE;
        map->lvds_lane11 = LVDS_LANE11_NO_USE;
	}
}

3.2.4 内核代码注意事项

驱动中一般禁止使用mdelay 或者msleep 实现延时,例如使用msleep 实现10~20ms的延时,通常会因为系统调度而变成延时更长的时间,这种做法精度较差。

所以如果需要使用ms 级别延时,则使用usleep_range(a, b),比如原来mdelay(1)、mdelay(10) 可改为usleep_range(1000, 2000)、usleep_range(10000,

12000)。如果是长达30ms 或以上的延时可选择使用msleep();

中断过程中不能使用msleep 和usleep_range,除了特殊情况必须加延时之外,mdelay 一般也不可使用。

4 模块配置

4.1 Tina 配置

Tina 中主要是修改平台的modules.mk 配置,modules.mk 主要完成两个方面:

1.拷贝相关的ko 模块到小机rootfs 中

2.rootfs 启动时,按顺序自动加载相关的ko 模块。

由于内核框架的不一样,需要区分vfe 和vin 进行相应的配置。

4.1.1 vfe 框架

modules.mk 配置路径(以R40 平台的为例):

target/allwinner/r40-common/modules.mk

其中的r40-common 为R40 平台共有的配置文件目录,相应的修改对应平台的modules.mk即可。

define KernelPackage/sunxi-vfe
    SUBMENU:=$(VIDEO_MENU)
    TITLE:=sunxi-vfe support
    FILES:=$(LINUX_DIR)/drivers/media/v4l2-core/videobuf2-core.ko
    FILES+=$(LINUX_DIR)/drivers/media/v4l2-core/videobuf2-memops.ko
    FILES+=$(LINUX_DIR)/drivers/media/v4l2-core/videobuf2-dma-contig.ko
    FILES+=$(LINUX_DIR)/drivers/media/v4l2-core/videobuf2-v4l2.ko
    FILES+=$(LINUX_DIR)/drivers/media/platform/sunxi-vfe/vfe_io.ko
    FILES+=$(LINUX_DIR)/drivers/media/platform/sunxi-vfe/device/ov5640.ko (详见1)
    FILES+=$(LINUX_DIR)/drivers/media/platform/sunxi-vfe/vfe_v4l2.ko
    AUTOLOAD:=$(call AutoLoad,90,videobuf2-core videobuf2-memops videobuf2-dma-contig
    videobuf2-v4l2 vfe_io ov5640 vfe_v4l2) (详见2)
endef
    define KernelPackage/sunxi-vfe/description
    	Kernel modules for sunxi-vfe support
endef
详注:
    1.由具体使用的模组确定,需要确定内核路径中这个驱动是否被编译出来。
    2.AUTOLOAD为小机rootfs挂载后自动加载的机制,vfe_v4l2.ko必须在最后加载,其它ko可以按照上面的相对顺序加载。必须修改相应的sensor ko才会开启自加载。

4.1.2 vin 框架

modules.mk 配置路径(以R30 平台的为例):

target/allwinner/r30-common/modules.mk

其中的r30-common 为R30 平台共有的配置文件目录,相应的修改对应平台的modules.mk即可。

define KernelPackage/sunxi-vin
    SUBMENU:=$(VIDEO_MENU)
    TITLE:=sunxi-vin support
    FILES:=$(LINUX_DIR)/drivers/media/v4l2-core/videobuf2-core.ko
    FILES+=$(LINUX_DIR)/drivers/media/v4l2-core/videobuf2-memops.ko
    FILES+=$(LINUX_DIR)/drivers/media/v4l2-core/videobuf2-dma-contig.ko
    FILES+=$(LINUX_DIR)/drivers/media/v4l2-core/videobuf2-v4l2.ko
    FILES+=$(LINUX_DIR)/drivers/media/platform/sunxi-vin/vin_io.ko
    /*对焦马达驱动加载*/
    FILES+=$(LINUX_DIR)/drivers/media/platform/sunxi-vin/modules/actuator/actuator.ko
    FILES+=$(LINUX_DIR)/drivers/media/platform/sunxi-vin/modules/actuator/dw9714_act.ko(详见
    3)
    FILES+=$(LINUX_DIR)/drivers/media/platform/sunxi-vin/modules/sensor/ov5640.ko (详见1)
    FILES+=$(LINUX_DIR)/drivers/media/platform/sunxi-vin/vin_v4l2.ko
    AUTOLOAD:=$(call AutoLoad,90,videobuf2-core videobuf2-memops videobuf2-dma-contig
    videobuf2-v4l2 vin_io actuator dw9714_act ov5640 vin_v4l2) (详见2)
endef
    define KernelPackage/sunxi-vin/description
    	Kernel modules for sunxi-vin support
endef
详注:
    1.由具体使用的模组确定,需要确定内核路径中这个驱动是否被编译出来。
    2.AUTOLOAD为小机rootfs挂载后自动加载的机制,vin_v4l2.ko必须在最后加载,其它ko可以按照上面的相对顺序加载。
    3.对焦马达驱动加载顺序必须在sensor驱动加载之前,具体驱动型号根据模组规格书进行确认。

V 系列平台在完成modules.mk 配置后,还需要完成.ko 挂载脚本S00mpp 的配置,S00mpp

配置路径(以V853 平台为例):

target/allwinner/v853-perf1/busybox-init-base-files/etc/init.d

其中的v853-perf1 为V 系列平台共有的配置文件目录,相应的修改对应平台的S00mpp 即可。

#!/bin/sh
#
# Load mpp modules....
#
MODULES_DIR="/lib/modules/`uname -r`"
start() {
    printf "Load mpp modules\n"
    insmod $MODULES_DIR/videobuf2-core.ko
    insmod $MODULES_DIR/videobuf2-memops.ko
    insmod $MODULES_DIR/videobuf2-dma-contig.ko
    insmod $MODULES_DIR/videobuf2-v4l2.ko
    insmod $MODULES_DIR/vin_io.ko
    # insmod $MODULES_DIR/sensor_power.ko
    insmod $MODULES_DIR/gc4663_mipi.ko
    insmod $MODULES_DIR/vin_v4l2.ko
    insmod $MODULES_DIR/sunxi_aio.ko
    insmod $MODULES_DIR/sunxi_eise.ko
    # insmod $MODULES_DIR/vipcore.ko
}
stop() {
    printf "Unload mpp modules\n"
    # rmmod $MODULES_DIR/vipcore.ko
    rmmod $MODULES_DIR/sunxi_eise.ko
    rmmod $MODULES_DIR/sunxi_aio.ko
    rmmod $MODULES_DIR/vin_v4l2.ko
    rmmod $MODULES_DIR/gc4663_mipi.ko
    # rmmod $MODULES_DIR/sensor_power.ko
    rmmod $MODULES_DIR/vin_io.ko
    rmmod $MODULES_DIR/videobuf2-v4l2.ko
    rmmod $MODULES_DIR/videobuf2-dma-contig.ko
    rmmod $MODULES_DIR/videobuf2-memops.ko
    rmmod $MODULES_DIR/videobuf2-core.ko
}
case "$1" in
        start)
        start
        ;;
        stop)
        stop
        ;;
        restart|reload)
        stop
        start
        ;;
    *)
    echo "Usage: $0 {start|stop|restart}"
    exit 1
esac
exit $?

4.2 CSI 板级配置

Tina 平台根据不同的平台差异分别使用sys_config.fex 或board.dst 配置camera CSI,具体的对应关系如下表,下面将分别介绍sys_config.fex 和board.dts 中关

于camera CSI 配置。

 

表4-1: 平台配置方式对应表
平台CSI 使用的配置方式
F35 sys_config.fex
R16 sys_config.fex
R18 sys_config.fex
R30 sys_config.fex
R40 sys_config.fex
R311 sys_config.fex
MR133 sys_config.fex
R818 board.dts
MR813 board.dts
R528 board.dts
V536 sys_config.fex
V533 board.dts
V831 board.dts
V833 board.dts
V851 board.dts
V853 board.dts

4.2.1 sys_config.fex 平台配置

sys_config.fex 配置camera CSI,CSI sys_config.fex 部分对应的字段为:[csi0]。通过举例R40 平台说明在实际使用中应该如何配置:假如使用一个并口camera

模组需要配置[csi0] 的公用部分和[csi0] 的vip_dev0_(x) 部分,另外[csi0] 中vip_used 设置为1,[csi1]中vip_used 设置为0。

下面给出一个ov5640 模组的参考配置:其中[csi0] 为并口的配置。具体填写方法请参照以下说明:

/* 下面部分的CSI配置适用4.9内核之前的平台*/
;--------------------------------------------------------------------------------
;csi (COMS Sensor Interface) configuration
;csi(x)_dev(x)_used: 0:disable 1:enable
;csi(x)_dev(x)_isp_used 0:not use isp 1:use isp
;csi(x)_dev(x)_fmt: 0:yuv 1:bayer raw rgb
;csi(x)_dev(x)_stby_mode: 0:not shut down power at standby 1:shut down power at standby
;csi(x)_dev(x)_vflip: flip in vertical direction 0:disable 1:enable
;csi(x)_dev(x)_hflip: flip in horizontal direction 0:disable 1:enable
;csi(x)_dev(x)_iovdd: camera module io power handle string, pmu power supply
;csi(x)_dev(x)_iovdd_vol: camera module io power voltage, pmu power supply
;csi(x)_dev(x)_avdd: camera module analog power handle string, pmu power supply
;csi(x)_dev(x)_avdd_vol: camera module analog power voltage, pmu power supply
;csi(x)_dev(x)_dvdd: camera module core power handle string, pmu power supply
;csi(x)_dev(x)_dvdd_vol: camera module core power voltage, pmu power supply
;csi(x)_dev(x)_afvdd: camera module vcm power handle string, pmu power supply
;csi(x)_dev(x)_afvdd_vol: camera module vcm power voltage, pmu power supply
;fill voltage in uV, e.g. iovdd = 2.8V, csix_iovdd_vol = 2800000
;fill handle string as below:
;axp22_eldo3
;axp22_dldo4
;axp22_eldo2
;fill handle string "" when not using any pmu power supply
;--------------------------------------------------------------------------------
[csi0]
csi0_used = 1
csi0_sensor_list = 0
csi0_pck = port:PE00<2><default><default><default>
csi0_mck = port:PE01<2><default><default><default>
csi0_hsync = port:PE02<2><default><default><default>
csi0_vsync = port:PE03<2><default><default><default>
csi0_d0 = port:PE04<2><default><default><default>
csi0_d1 = port:PE05<2><default><default><default>
csi0_d2 = port:PE06<2><default><default><default>
csi0_d3 = port:PE07<2><default><default><default>
csi0_d4 = port:PE08<2><default><default><default>
csi0_d5 = port:PE09<2><default><default><default>
csi0_d6 = port:PE10<2><default><default><default>
csi0_d7 = port:PE11<2><default><default><default>
csi0_sck = port:PE12<2><default><default><default>
csi0_sda = port:PE13<2><default><default><default>
[csi0/csi0_dev0]
csi0_dev0_used = 1
csi0_dev0_mname = "ov5640" ;必须和sensor驱动中的SENSOR_NAME一致
csi0_dev0_twi_addr = 0x78 ;请参考实际模组的8bit ID填写
csi0_dev0_twi_id = 2
csi0_dev0_pos = "rear"
csi0_dev0_isp_used = 0 ;YUV格式填0,RAW格式填1
csi0_dev0_fmt = 0 ;YUV格式填0,RAW格式填1
csi0_dev0_stby_mode = 0
csi0_dev0_vflip = 0
csi0_dev0_hflip = 0
csi0_dev0_iovdd = "csi-iovcc" ;电源请参考实际原理图填写,同时参考
sys_config.fex 的regulator 配置,确认该字段有效
csi0_dev0_iovdd_vol = 2800000 ;电压值参考datasheet
csi0_dev0_avdd = "csi-avdd" ;电源请参考实际原理图填写,同时参考
sys_config.fex 的regulator 配置,确认该字段有效
csi0_dev0_avdd_vol = 2800000 ;电压值参考datasheet
csi0_dev0_dvdd = "csi-dvdd" ;电源请参考实际原理图填写,同时参考
sys_config.fex 的regulator 配置,确认该字段有效
csi0_dev0_dvdd_vol = 1500000 ;电压值参考datasheet
csi0_dev0_afvdd = "csi-afvcc" ;电源请参考实际原理图填写,同时参考
sys_config.fex 的regulator 配置,确认该字段有效
csi0_dev0_afvdd_vol = 2800000 ;电压值参考datasheet
csi0_dev0_power_en =
csi0_dev0_reset = port:PE14<1><0><1><0> ;io选取参照实际原理图
csi0_dev0_pwdn = port:PE15<1><0><1><0> ;io选取参照实际原理图
csi0_dev0_flash_used = 0
csi0_dev0_flash_type = 2
csi0_dev0_flash_en =
csi0_dev0_flash_mode =
csi0_dev0_flvdd = ""
csi0_dev0_flvdd_vol =
csi0_dev0_af_pwdn =
csi0_dev0_act_used = 0
csi0_dev0_act_name = "ad5820_act"
csi0_dev0_act_slave = 0x18
/* 下面部分的CSI配置适用4.9内核平台*/
;--------------------------------------------------------------------------------
;csi (COMS Sensor Interface) configuration
;csi(x)_dev(x)_used: 0:disable 1:enable
;csi(x)_dev(x)_isp_used 0:not use isp 1:use isp
;csi(x)_dev(x)_fmt: 0:yuv 1:bayer raw rgb
;csi(x)_dev(x)_stby_mode: 0:not shut down power at standby 1:shut down power at standby
;csi(x)_dev(x)_vflip: flip in vertical direction 0:disable 1:enable
;csi(x)_dev(x)_hflip: flip in horizontal direction 0:disable 1:enable
;csi(x)_dev(x)_iovdd: camera module io power handle string, pmu power supply
;csi(x)_dev(x)_iovdd_vol: camera module io power voltage, pmu power supply
;csi(x)_dev(x)_avdd: camera module analog power handle string, pmu power supply
;csi(x)_dev(x)_avdd_vol: camera module analog power voltage, pmu power supply
;csi(x)_dev(x)_dvdd: camera module core power handle string, pmu power supply
;csi(x)_dev(x)_dvdd_vol: camera module core power voltage, pmu power supply
;csi(x)_dev(x)_afvdd: camera module vcm power handle string, pmu power supply
;csi(x)_dev(x)_afvdd_vol: camera module vcm power voltage, pmu power supply
;fill voltage in uV, e.g. iovdd = 2.8V, csix_iovdd_vol = 2800000
;fill handle string as below:
;axp22_eldo3
;axp22_dldo4
;axp22_eldo2
;fill handle string "" when not using any pmu power supply
;--------------------------------------------------------------------------------
[vind0]
vind0_used = 1
[vind0/csi_cci0]
csi_cci0_used = 1 ;配置是否使用CCI,如果使用CCI,需要使能该配置并配置下面的CCI引脚
csi_cci0_sck = port:PE01<2><default><default><default>
csi_cci0_sda = port:PE02<2><default><default><default>
[vind0/flash0]
flash0_used = 0
flash0_type = 2
flash0_en =
flash0_mode =
flash0_flvdd = ""
flash0_flvdd_vol =
[vind0/actuator0]
actuator0_used = 0
actuator0_name = "ad5820_act"
actuator0_slave = 0x18
actuator0_af_pwdn =
actuator0_afvdd = "afvcc-csi"
actuator0_afvdd_vol = 2800000
[vind0/sensor0]
sensor0_used = 0
sensor0_mname = "gc8034_mipi"
sensor0_twi_cci_id = 0
sensor0_twi_addr = 0x6e
sensor0_pos = "rear"
sensor0_isp_used = 1
sensor0_fmt = 1
sensor0_stby_mode = 0
sensor0_vflip = 0
sensor0_hflip = 0
sensor0_cameravdd = ""
sensor0_cameravdd_vol = 3300000
sensor0_iovdd = "iovdd-csi"
sensor0_iovdd_vol = 1800000
sensor0_avdd = "avdd-csi-f"
sensor0_avdd_vol = 2800000
sensor0_dvdd = "dvdd-csi"
sensor0_dvdd_vol = 1200000
sensor0_power_en =
sensor0_reset = port:PE06<0><0><1><0>
sensor0_pwdn = port:PE05<0><0><1><0>
[vind0/sensor1]
sensor1_used = 1
sensor1_mname = "gc8034_mipi" ;必须要和驱动的SENSOR_NAME 一致
sensor1_twi_cci_id = 0 ;配置使用的TWI id,如果使用TWI,则不使用CCI
sensor1_twi_addr = 0x6e ;配置sensor的i2c地址
sensor1_pos = "front"
sensor1_isp_used = 1 ;配置是否使用isp
sensor1_fmt = 1
sensor1_stby_mode = 0
sensor1_vflip = 0
sensor1_hflip = 0
sensor1_cameravdd = ""
sensor1_cameravdd_vol = 3300000
sensor1_iovdd = "iovdd-csi"
sensor1_iovdd_vol = 1800000
sensor1_avdd = "avdd-csi-f"
sensor1_avdd_vol = 2800000
sensor1_dvdd = "dvdd-csi"
sensor1_dvdd_vol = 1200000
sensor1_power_en =
sensor1_reset = port:PE06<0><0><1><0>
sensor1_pwdn = port:PE05<0><0><1><0>
[vind0/vinc0] ;配置video0 的数据链路
vinc0_used = 1
vinc0_csi_sel = 0
vinc0_mipi_sel = 0
vinc0_isp_sel = 0
vinc0_rear_sensor_sel = 1 ;配置使用sensor1 输出图像数据到video0
vinc0_front_sensor_sel = 1 ;配置使用sensor1 输出图像数据到video0
vinc0_sensor_list = 0
[vind0/vinc1]
vinc1_used = 0
vinc1_csi_sel = 0
vinc1_mipi_sel = 0
vinc1_isp_sel = 0
vinc1_rear_sensor_sel = 1
vinc1_front_sensor_sel = 1
vinc1_sensor_list = 0

关于电源的配置,根据板子的原理图,了解需要sensor 驱动配置哪几路电,然后在sys_config.fex中进行配置:比如说sensor0 有个“CSI-IOVCC” 连接到AXP

的“LDO4”,那么,在sys_config.fex 中搜索LDO4 ,然后在其后面增加“csi-iovcc” ,这样,在sensor 端就可以使用该标号配置sensor0_iovdd。

regulator14 = "pmu1736_bldo2 none csi-iovdd"
sensor0_iovdd = "csi-iovdd"

同时关于mr133/R311 平台,sys_config.fex 中的vinc0_rear_sensor_sel 和vinc0_front_sensor_sel

 

配置决定着使用哪路sensor 输入数据,该配置与硬件连接相关,可参考本文档最后的其他注意事项章节。

4.2.2 board.dts 平台配置

当前MR813/R818/R528 平台的摄像头配置不再使用sys_config.fex 而使用board.dts,文件存放在tina/device/config/chips/mr813(R818、R528)/configs/

< 方案> 目录下,摄像头相关的配置如下:

    vind0:vind@0 {
        vind0_clk = <336000000>;
        vind0_isp = <327000000>;
        status = "okay";
        actuator0:actuator@0 {
        device_type = "actuator0";
        actuator0_name = "ad5820_act";/*必须要和驱动的SUNXI_ACT_NAME一致*/
        actuator0_slave = <0x18>;/*必须和驱动的SUNXI_ACT_ID一致*/
        actuator0_af_pwdn = <>;
        actuator0_afvdd = "afvcc-csi";
        actuator0_afvdd_vol = <2800000>;/*af模块的配电不在此处,在sensor配置中*/
        status = "disabled";/*使能开关,当使用AF功能时,status = "okay"*/
    };
    flash0:flash@0 {
        device_type = "flash0";
        flash0_type = <2>;
        flash0_en = <>;
        flash0_mode = <>;
        flash0_flvdd = "";
        flash0_flvdd_vol = <>;
        device_id = <0>;
        status = "disabled";
    };
    sensor0:sensor@0 {
        device_type = "sensor0";
        sensor0_mname = "imx278_mipi"; /* 必须要和驱动的 SENSOR_NAME 一致 */
        sensor0_twi_cci_id = <2>;
        sensor0_twi_addr = <0x20>;
        sensor0_mclk_id = <0>;
        sensor0_pos = "rear";
        sensor0_isp_used = <1>; /* R528 没有isp,该项需要配置为0 */
        sensor0_fmt = <1>;
        sensor0_stby_mode = <0>;
        sensor0_vflip = <0>;
        sensor0_hflip = <0>;
        /* sensor iovdd 连接的 ldo,根据硬件原理图的连接,
        * 确认是连接到 axp 哪个 ldo,假设 iovdd 连接到 aldo3,
        * 则 sensor0_iovdd-supply = <&reg_aldo3>,其他同理。
        */
        sensor0_iovdd-supply = <&reg_dldo2>;
        sensor0_iovdd_vol = <1800000>;
        sensor0_avdd-supply = <&reg_dldo3>;
        sensor0_avdd_vol = <2800000>;
        sensor0_dvdd-supply = <&reg_eldo2>;
        sensor0_afvdd-supply = <&reg_aldo3>;/*根据硬件原理图,确定配的哪路电*/
        sensor0_afvdd_vol = <2800000>;/*根据硬件原理图,确认工作电压*/
        sensor0_dvdd_vol = <1200000>;
        sensor0_power_en = <>;
        /* 根据板子实际连接,修改 reset、pwdn 的引脚即可 */
        /* GPIO 信息配置:pio 端口 组内序号 功能分配 内部电阻状态 驱动能力 输出电平状态 */
        sensor0_reset = <&pio PE 9 1 0 1 0>;
        sensor0_pwdn = <&pio PE 8 1 0 1 0>;
        status = "okay";
    };
    sensor1:sensor@1 {
        device_type = "sensor1";
        sensor1_mname = "imx386_mipi";
        sensor1_twi_cci_id = <3>;
        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_dldo2>;
        sensor1_iovdd_vol = <1800000>;
        sensor1_avdd-supply = <&reg_dldo3>;
        sensor1_avdd_vol = <2800000>;
        sensor1_dvdd-supply = <&reg_eldo2>;
        sensor1_dvdd_vol = <1200000>;
        sensor0_power_en = <>;
        sensor1_reset = <&pio PE 7 1 0 1 0>;
        sensor1_pwdn = <&pio PE 6 1 0 1 0>;
        status = "okay";
    };
    /* 一个 vinc 代表一个 /dev/video 设备 */
    vinc0:vinc@0 {
        vinc0_csi_sel = <0>; /* 代表选择的 csi,MR813/R818 有两个 csi 接口
        */
        vinc0_mipi_sel = <0>; /* 代表选择的 mipi 接口,MR813/R818 有两个 mipi
        接口 */
        vinc0_isp_sel = <0>;
        vinc0_isp_tx_ch = <0>; /* 表示 ISP 的通道数,一般配置为 0 */
        vinc0_tdm_rx_sel = <0>; /* 与 isp_sel 保持一致即可 */
        vinc0_rear_sensor_sel = <0>; /* 该 video 可以选择从哪个 sensor 输入图像数据
        */
        vinc0_front_sensor_sel = <1>;
        vinc0_sensor_list = <0>;
        status = "okay";
    };
    vinc1:vinc@1 {
        vinc1_csi_sel = <0>;
        vinc1_mipi_sel = <0>; /* R528没有mipi,该项配置为0xff */
        vinc1_isp_sel = <0>; /* R528没有isp,该项配置为0 */
        vinc1_isp_tx_ch = <0>; /* R528没有isp,该项配置为0 */
        vinc1_tdm_rx_sel = <0>; /* R528没有isp,该项配置为0xff */
        vinc1_rear_sensor_sel = <0>;
        vinc1_front_sensor_sel = <1>;
        vinc1_sensor_list = <0>;
        status = "okay";
    };
    vinc2:vinc@2 {
        vinc2_csi_sel = <1>;
        vinc2_mipi_sel = <1>;
        vinc2_isp_sel = <1>;
        vinc2_isp_tx_ch = <0>;
        vinc2_tdm_rx_sel = <1>;
        vinc2_rear_sensor_sel = <1>;
        vinc2_front_sensor_sel = <1>;
        vinc2_sensor_list = <0>;
        status = "okay";
    };
    vinc3:vinc@3 {
        vinc3_csi_sel = <1>;
        vinc3_mipi_sel = <1>;
        vinc3_isp_sel = <1>;
        vinc3_isp_tx_ch = <0>;
        vinc3_tdm_rx_sel = <1>;
        vinc3_rear_sensor_sel = <1>;
        vinc3_front_sensor_sel = <1>;
        vinc3_sensor_list = <0>;
        status = "okay";
    };
    };
    /* 以下将配置两路 sensor 输入,产生 4 个 video 节点,内核配置 CONFIG_SUPPORT_ISP_TDM=n,此时
    * 不同 sensor 输出的节点不能同时使用,比如以下配置的 video0 不可以和 video2 video3 同时使用
    */
    vinc0: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>;
        status = "okay";
    };
    vinc1:vinc@1 {
        vinc1_csi_sel = <0>;
        vinc1_mipi_sel = <0>;
        vinc1_isp_sel = <0>;
        vinc1_isp_tx_ch = <0>;
        vinc1_tdm_rx_sel = <0>;
        vinc1_rear_sensor_sel = <0>;
        vinc1_front_sensor_sel = <1>;
        vinc1_sensor_list = <0>;
        status = "okay";
    };
    vinc2:vinc@2 {
        vinc2_csi_sel = <1>;
        vinc2_mipi_sel = <1>;
        vinc2_isp_sel = <0>;
        vinc2_isp_tx_ch = <0>;
        vinc2_tdm_rx_sel = <0>;
        vinc2_rear_sensor_sel = <1>;
        vinc2_front_sensor_sel = <1>;
        vinc2_sensor_list = <0>;
        status = "okay";
    };
    vinc3:vinc@3 {
        vinc3_csi_sel = <1>;
        vinc3_mipi_sel = <1>;
        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 = "okay";
    };
    /* 以下配置将可以从两路 sensor 同时输入,内核配置 CONFIG_SUPPORT_ISP_TDM=y,但是有个限制,
    * 只能先运行 video0,然后才可以运行 video2,关闭的时候也是如此,先关 video2,再关 video0
    */
    vinc0: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>;
        status = "okay";
    };
    vinc1:vinc@1 {
        vinc1_csi_sel = <0>;
        vinc1_mipi_sel = <0>;
        vinc1_isp_sel = <0>;
        vinc1_isp_tx_ch = <0>;
        vinc1_tdm_rx_sel = <0>;
        vinc1_rear_sensor_sel = <0>;
        vinc1_front_sensor_sel = <1>;
        vinc1_sensor_list = <0>;
        status = "okay";
    };
    vinc2:vinc@2 {
        vinc2_csi_sel = <1>;
        vinc2_mipi_sel = <1>;
        vinc2_isp_sel = <1>;
        vinc2_isp_tx_ch = <0>;
        vinc2_tdm_rx_sel = <1>;
        vinc2_rear_sensor_sel = <1>;
        vinc2_front_sensor_sel = <1>;
        vinc2_sensor_list = <0>;
        status = "okay";
    };
    vinc3:vinc@3 {
        vinc3_csi_sel = <1>;
        vinc3_mipi_sel = <1>;
        vinc3_isp_sel = <1>;
        vinc3_isp_tx_ch = <0>;
        vinc3_tdm_rx_sel = <1>;
        vinc3_rear_sensor_sel = <1>;
        vinc3_front_sensor_sel = <1>;
        vinc3_sensor_list = <0>;
        status = "okay";
    };

修改该文件之后,需要重新编译固件再打包,才会更新到dts。同时,如果需要使用双摄,双摄分别使用到两个ISP,那么内核需要选上SUPPORT_ISP_TDM 配置。

4.3 menuconfig 配置说明

在命令行进入Tina 根目录,执行命令进入配置主界面:

source build/envsetup.sh (详见1)
lunch 方案编号(详见2)
make menuconfig (详见3)
详注:
1.加载环境变量及tina提供的命令;
2.输入编号,选择方案;
3.进入配置主界面(对一个shell而言,前两个命令只需要执行一次)

make menuconfig 配置路径:

Kernel modules
	└─>Video Support
        └─>kmod-sunxi-vfe(vfe框架的csi camera) (详见1)
        └─>kmod-sunxi-vin(vin框架的csi camera) (详见2)
        └─>kmod-sunxi-uvc(uvc camera) (详见3)
详注:
    1.平台使用vfe框架的csi camera选择该驱动;
    2.平台使用vin框架的csi camera选择该驱动;(该项与vfe框架,在同一个平台只会出现其中一个)
    3.usb camera选择该驱动;

在完成sensor 驱动编写,modules.mk 和板级配置后,通过make menuconfig 选上相应的驱动,camera 即可正常使用。下面以R40 平台介绍。首先,选择

Kernel modules 选项进入下一级配置,如下图所示:

image-20221123105646196

图4-1: menuconfig

然后,选择Video Support 选项,进入下一级配置,如下图所示:

image-20221123105728564

图4-2: video

最后,选择kmod-sunxi-vfe 选项,可选择<*> 表示编译包含到固件,也可以选择表示仅编译不包含在固件。如下图所示:

image-20221123105750877

图4-3: sunxi

4.4 如何增加ISP 效果配置

在完成ISP 调试之后,将会从ISP 调试工程师中得到相应的头文件配置,添加操作如下:

4.4.1 VFE 框架

  1. 将头文件添加到驱动的sunxi-vfe/isp_cfg/SENSOR_H 目录下;

  2. 在驱动sunxi-vfe/isp_cfg 目录下,有个isp_cfg.c 文件,这文件中有个isp_cfg_array 数组,在sensor 的ISP 配置文件最下面也有个相应的结构体,在

isp_cfg_array 数组中按照数组的结构,增加sensor 的name 和结构体即可,这样将会在ISP 匹配的时候,将会根据name 匹配到相应的配置;

4.4.2 VIN 框架

4.4.2.1 R 系列

  1. vin 框架的操作也是类似的,只是更换了位置。vin 的ISP 配置在tina/package/allwinner/libAWIspApi 目录下,其中R311、MR133 在src/isp520,而R818、

MR813 在src/isp522。在libisp/isp_cfg/SENSOR 目录下增加相应的头文件,然后在上一层目录的isp_ini_parse.c 文件增加头文件以及修改相应的isp_cfg_array cfg_arr 数组匹配即可。

  1. VIN 使用ISP,需要在camerademo 中make menuconfig 的时候,选择上Choosewhether to use VIN ISP (YES)。同时VIN 的需要注意,当自己开发camera

HAL 层时,需要自己运行camera ISP service,具体实现可参考camerademo 的实现。添加正确时,在运行camerademo 将会输出相应的sensor 配置信息,

比如:

[ISP]find imx278_mipi_2048_1152_60_0 [imx278_mipi_default_ini_mr813] isp config

上述表示正确查找到imx278_mipi 这个sensor 2048*1152 60fps 的ISP 配置,其他的sensorISP 配置移植正确也将会有类似的打印,输出信息分别是sensor name 、分辨率、帧率,确认这些信息一致即可。

4.4.2.2 V 系列

  1. V 系列ISP 库目录,V533、V83x 平台位于:softwinner/eyesee-mpp/middleware/sun8iw19p1/media/V536 平台位于:softwinner/eyesee-

mpp/middleware/v316/media/LIBRARY/libisp/,V85x 平台位于:external/eyesee-mpp/middleware/sun8iw21/media/LIBRARY/libisp/

  1. 修改libisp/isp_cfg/isp_ini_parse.c,将ISP 效果.h 包含进来,并修改struct isp_cfg_arraycfg_arr[] 结构体;其中参数定义:

(1)Sensor 模块名称:sensor_mipi (2)ISP 效果头文件名称 (3)分辨率宽 (4)分辨率高 (5)帧率 (6)红外IR 模式标志位 (7)WDR 模式标志位 (8)ISP 参数结构体

image-20221123113519900

图4-4: sunxi

4.5 如何输出RAW 数据

在ioctl 的VIDIOC_S_FMT 命令,将其参数pixelformat 设置为RAW 格式即可,RAW 格式如下:

    V4L2_PIX_FMT_SBGGR8
    V4L2_PIX_FMT_SGBRG8
    V4L2_PIX_FMT_SGRBG8
    V4L2_PIX_FMT_SRGGB8
    V4L2_PIX_FMT_SBGGR10
    V4L2_PIX_FMT_SGBRG10
    V4L2_PIX_FMT_SGRBG10
    V4L2_PIX_FMT_SRGGB10
    V4L2_PIX_FMT_SBGGR12
    V4L2_PIX_FMT_SGBRG12
    V4L2_PIX_FMT_SGRBG12
    V4L2_PIX_FMT_SRGGB12

将pixelformat 设置为上述的其一即可输出RAW 数据, 而如何选择上述的操作, 这个根据sensor 驱动选择, 如果驱动中sensor_formats 的mbus_code 设置为

MEDIA_BUS_FMT_SBGGR10_1X10,则在输出RAW 数据时将pixelformat 设置为V4L2_PIX_FMT_SBGGR10

 

当前camerademo 已经支持输出RAW 数据,可参照本文档《camerademo 输出RAW 数据》章节。

 

4.6 如何计算实际曝光时间

该部分为使用到ISP 的RAW sensor 配置信息。曝光时间的计算和曝光控制寄存器、hts、pclk这些配置相关,这些配置都在sensor 驱动,ISP 将会根据sensor 驱

动中的设置计算相应的曝光时间,所以驱动中的配置必须正确,否则在调试ISP 效果可能会遇到其他的一些问题。

static struct sensor_win_size sensor_win_sizes[] = {
    ...
    .hts = 928,
    .vts = 1720,
    .pclk = 48 * 1000 * 1000,
    ...
}

在sensor 的驱动中有以上的一些配置,曝光时间在驱动中是以曝光行为计算单位的,即在sensor_s_exp() 函数中设置的参数为曝光行,部分sensor 是以16 为一

倍的,所以在计算实际的曝光行时,需要将上述函数参数除以16。

曝光时间= 曝光行× hts / pclk

一般的pclk 都是M 级别的,所以时间单位为us,部分sensor 的曝光行为参数的十六分之一,需要除以十六,同时,曝光行不能大于vts 的值,否则将会出现降

帧、没有正常输出图像等问题。

4.7 如何脱离isp tuning 工具微调图像亮度

在isp 配置文件中,有类似以下的信息:

.ae_cfg = {
	256, 555, 256, 555, 31, 22, 22, 25, 3, 130, 16, 60, 1, 2
},

上述ae_cfg 参数的倒数第4 个数值(130)即是控制图像亮度的阀门(期望亮度),该值越大,图像亮度越高。ae_cfg 一共14 个,分别对应着不同的环境亮度

(Lux)。如何确定AE 当前处于哪组ae_cfg 参数呢?修改isp 配置文件中的isp_log_param = 0x1,然后重新编译运行相机应用,留意应用中关于isp 的打印信息:

[ISP_DEBUG]: isp0 ae_target 92, pic_lum 0, weight_lum 0, delta_exp_idx 138, ae_delay 0, AE_TOLERANCE

5

从上述信息可以看到当前的目标亮度是92,这时可以查看isp 配置文件ae_cfg 中哪组的阀门处于92 这个范围,如果需要增加亮度,则提高相应的阀门;降低亮度

则降低阀门。相应的根据实际调试情况修改即可。调试之后,记得将isp_log_param 参数还原为0。

4.8 VIN 如何设置裁剪和缩放

裁剪修改sensor 驱动:在驱动有类似以下的配置

static struct sensor_win_size sensor_win_sizes[] = {
    {
        .width = VGA_WIDTH,
        .height = VGA_HEIGHT,
        .hoffset = 0,
        .voffset = 0,
        .hts = 878,
        .vts = 683,
        .pclk = 72 * 1000 * 1000,
        .mipi_bps = 720 * 1000 * 1000,
        .fps_fixed = 120,
        .bin_factor = 1,
        .intg_min = 1 << 4,
        .intg_max = (683) << 4,
        .gain_min = 1 << 4,
        .gain_max = 16 << 4,
        .regs = sensor_VGA_120fps_regs,
        .regs_size = ARRAY_SIZE(sensor_VGA_120fps_regs),
        .set_size = NULL,
    },
};

上述的width height 表示经过isp 输出之后的数据,如果需要裁剪,修改width、height、hoffset 和voffset。裁剪之后的输出width = sensor_output_src -

2hoffset height = sensor_height_src - 2voffset 注意,上述的hoffset voffset 必须为双数。

所以,假设sensor 输出的是640 × 480,我们想裁剪为320 × 240 的,则上述配置修改为:

static struct sensor_win_size sensor_win_sizes[] = {
    {
        .width = 320,
        .height = 240,
        .hoffset = 160,
        .voffset = 120,
        .hts = 878,
        .vts = 683,
        .pclk = 72 * 1000 * 1000,
        .mipi_bps = 720 * 1000 * 1000,
        .fps_fixed = 120,
        .bin_factor = 1,
        .intg_min = 1 << 4,
        .intg_max = (683) << 4,
        .gain_min = 1 << 4,
        .gain_max = 16 << 4,
        .regs = sensor_VGA_120fps_regs,
        .regs_size = ARRAY_SIZE(sensor_VGA_120fps_regs),
        .set_size = NULL,
    },
};

缩放配置:使用硬件缩放,可以在应用层通过VIDIOC_S_FMT 设置分辨率的时候,直接设置分辨率的大小为缩放的分辨率即可。

	fmt.fmt.pix_mp.width = 320;
	fmt.fmt.pix_mp.height = 240;

上述的操作,将会使用硬件完成相应的缩放输出。

5 模块调试常见问题

初次调试建议打开device 中的DEV_DBG_EN 为1,方便调试。

Camera 模块调试一般可以分为三步:

  1. 使用lsmod 命令查看驱动是否加载,查看/lib/modules/内核版本号目录下是否存在相应的ko,如果没有,确认modules.mk 是否修改正确,配置了开机自动

加载。如果存在相应的ko,可手动加载测试确认ko 是否正常,手动加载成功,则确认内核的版本是否一致,导致开机时没有找到相应的ko 从而没有加载。

  1. 使用ls /dev/v* 查看是否有video0/1 节点生成

  2. 在adb shell 中使用cat /proc/kmsg 命令,或者是使用串口查看内核的打印信息,查看不能正常加载的原因。一般情况下驱动加载不成功的原因有:一是读取

的sys_config.fex 文件中的配置信息与加载的驱动不匹配,二是probe 函数遇到某些错误没能正确的完成probe 的时候返回。

5.1 移植一款sensor 需要进行哪些操作

移植camera sensor,主要进行以下操作:

  1. 根据主板的原理图,确认与sensor 模组的接口是否一致,一致才可以保证配置和数据的正常接收。

  2. 根据产品的需求,让sensor 模组厂提供产品所需的分辨率、帧率的寄存器配置,这一步需要注意,提供的配置需要是和模组匹配的。比如模组的mipi 接口只

引出2lane,而提供的寄存器配置却是配置为4lane 输出的,那么该配置在该模组无法正常使用,让模组厂提供该模组可以正常使用的正确配置。注意,该寄存

器配置SOC 原厂没有,需要sensor 厂提供。

  1. 拿到寄存器配置之后,按照本文档《驱动模块实现》章节完成sensor 驱动的编写。

  2. 在完成驱动的编写之后,按照本文档《Tina 配置》章节完成modules.mk 的修改。

  3. 根据板子的原理图与模组的硬件连接,参照本文档《sys_config.fex 配置》或者《MR813/R818平台配置》章节完成sys_config.fex 或者board.dts 的修改。

  4. 完成上述操作之后,按照本文档《menuconfig 配置说明》章节,选上camera 驱动模块,按照《camera 功能测试》章节选上camera 的测试程序,测试驱动

移植是否正常。

5.2 I2C 通信出现问题

5.2.1 R16 R11 R40 等

I2C 出现问题内核一般会伴随打印” cci_write_aX_dX error! slave = 0xXX, addr = 0xXX,value = 0xXX“。

如果与此同时,内核出现打印“chip found is not an target chip.”,则说明在初始化camera前,读取camera 的ID 已经失败。此时,一般是如下几点出现问题。

a. 最先考虑应该是更换一个camera模组试试。
b. 电源
    检查sys_config.fex
    vip_dev0_iovdd = "axp22_eldo3"
    vip_dev0_iovdd_vol = 2800000
    vip_dev0_avdd = "axp22_dldo4"
    vip_dev0_avdd_vol = 2800000
    vip_dev0_dvdd = "axp22_eldo2"
    vip_dev0_dvdd_vol = 1500000
    一定要与原理图设计保持一致。必要时,需要用万用表测量camera模组的各路电压是否正常。
c. reset和power down脚
    检查sys_config.fex配置
    vip_dev0_reset = port:PH2<1><default><default><default>
    vip_dev0_pwdn = port:PH1<1><default><default><default>
    是否与原理图设计保持一致。必要时,需要用示波器测量reset,pwdn脚,在camera加载时,是否有动作。
d. mclk
    检查sys_config.fex配置
    vip_csi_mck = port:PE01<3><default><default><default>
    pin脚是否与原理图设计保持一致。必要时,在加载camera时,测量mclk,看是否有正确输出(一般是24MHz或27MHz
    )

如果已经能够正确通过camera 的id 读取,只是在使用过程当中,偶尔出现I2C 的读写错误,此时需要从打印里面,将报错的地址和读写值,结合camera 具体的

spec 来分析,到底是操作了camera 哪些寄存器带来的问题。

 

5.2.2 其他平台

出错时一般出现以下信息:

[ 5.556579] sunxi_i2c_do_xfer()1942 - [i2c1] incomplete xfer (status: 0x20, dev addr: 0
x30)
[ 5.566234] sunxi_i2c_do_xfer()1942 - [i2c1] incomplete xfer (status: 0x20, dev addr: 0
x30)
[ 5.575963] sunxi_i2c_do_xfer()1942 - [i2c1] incomplete xfer (status: 0x20, dev addr: 0
x30)
[ 5.585375] [VIN_DEV_I2C]sc031gs_mipi sensor read retry = 2
[ 5.591666] [sensorname_mipi] error, chip found is not an target chip.

出现上述错误打印时,可按以下操作逐步debug。

  1. 确认sys_config.fex 中配置的sensor I2C 地址是否正确(sensor datasheet 中标注,读地 址为0x6d,写地址为0x6c,那么sys_config.fex 配置sensor I2C 地址为0x6c);

  2. 在完成以上操作之后,在senor 上电函数中,将掉电操作屏蔽,保持sensor 一直上电状态, 方便debug;

  3. 确认I2C 地址正确之后,测量sensor 的各路电源电压是否正确且电压幅值达到datasheet 标注的电压要求;

  4. 测量MCLK 的电压幅值与频率,是否正常;

  5. 测量senso r 的reset、pown 引脚电平配置是否正确,I2C 引脚SCK、SDA 是否已经硬件 上拉;

  6. 确认I2C 接口使用正确并使能(CCI / TWI);

  7. 如果还是I2C 出错,协调硬件同事使用逻辑分析仪等仪器进行debug;

5.2.3 经典错误

5.2.3.1 I2C 没有硬件上拉
twi_start()450 - [i2c2] START can't sendout!
twi_start()450 - [i2c2] START can't sendout!
twi_start()450 - [i2c2] START can't sendout!
[VFE_DEV_I2C_ERR]cci_write_a16_d16 error! slave = 0x1e, addr = 0xa03e, value = 0x1

出现上述的问题是因为SDA、SCK 没有拉上,导致在进行I2C 通信时,发送开始信号失败,SDA、SCK 添加上拉即可。

5.2.3.2 没有使能I2C
[VFE]Sub device register "ov2775_mipi" i2c_addr = 0x6c start!
[VFE_ERR]request i2c adapter failed!
[VFE_ERR]vfe sensor register check error at input_num = 0

出现上述的错误,是因为使用twi 进行I2C 通信但没有使能twi 导致的错误,此时需要确认sys_config.fex 中,[twiX] 中的twiX_used 是否已经设置为1。

5.3 图像异常

5.3.1 运行camerademo 可以成功采集图像,但图像全黑(RAWsensor)

当camerademo 成功采集到图像时,最起码整条数据通路已经正常,而发现图像时全黑的,注意以下几点:

  1. 在编译camerademo 之前,是根据平台(MR813/R818/MR133/R311) 正确的选上了“Enable vin isp support”,选上之后,重新编译camerademo

(建议cd package/allwinner/-camerademo 目录后执行mm -B 编译);

  1. 通过上述操作之后, 执行新编译的camerademo 可执行程序, 运行过程应可看到类似”[ISP]create isp0 server thread¡‘信息,则正确运行isp,这时再查看新

抓取的图像数据;

  1. 执行运行camerademo 只会抓取5 张图像数据,由于isp 计算合适的图像曝光需要一定的帧数,所以可能存在前面几张图像黑的情况,修改camerademo 运行

参数,抓取多几张图像数据查看(20 张);

  1. 如果是没有移植isp 的环境,则可修改sensor 驱动中寄存器组中的曝光参数配置,增加初始化时曝光时间,从而使初始输出的图像亮度较合适;

5.3.2 camerademo 采集的图像颜色异常

运行camerademo 采集图像之后,发现拍摄得到的轮廓正确但颜色不对,比如红蓝互换、画面整体偏红或偏蓝等颜色异常的情况,出现这样的问题,首先考虑是

sensor 驱动中配置的RAW 数据RGB 顺序错误导致的。在sensor 驱动中有类似以下的配置:

static struct sensor_format_struct sensor_formats[] = {
    {
        .desc = "Raw RGB Bayer",
        .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
        .regs = sensor_fmt_raw,
        .regs_size = ARRAY_SIZE(sensor_fmt_raw),
        .bpp = 1
    },
};

以上配置表明sensor 输出的图像数据是RAW10,RGB 排列顺序是BGGR,出现颜色异常时,一般就是RGB 的排列顺序配置错误导致的,RGB 排列顺序一共有4 种

(MEDIA_BUS_FMT_SBGGR10_1X10/MEDIA_BUS_FMT_SGBRG10_1X10/MEDIA_BUS_FMT_SGRBG10_修改驱动中的mbus_code 为上述的4 种之一,确认哪一种

颜色比较正常,则驱动配置正确。

如果颜色还有细微的不够艳丽、准确等问题,需要进行isp 效果调试,改善图像色彩。上述是以10bit sensor 为例进行介绍,其他的8bit、12bit、14bit 类似,参

考上述即可。

5.4 调试camera 常见现象和功能检查

  1. insmod 之后首先看内核打印,看加载有无错误打印,部分驱动在加载驱动进行上下电时候会进行i2c 操作,如果此时报错的话就不需要再进入camera 了,先

检查是否io 或电源配置不对。或者是在复用模组时候有可能是另外一个模组将i2c 拉住了。

  1. 如果i2c 读写没有问题的话,一般就可以认为sensor 控制是ok 的,只需要根据sensor 的配置填好H/VREF、PCLK 的极性就能正常接收图像了。这个时候可以

在进入camera 应用之后用示波器测量sensor 的各个信号,看h/vref、pclk 极性、幅度是否正常(2.8V 的vpp)。

  1. 如果看到画面了,但是看起来是绿色和粉红色的,但是有轮廓,一般是YUYV 的顺序设置反了,可检查yuyv 那几个寄存器是否填写正确配置,其次,看是否是

在配置的其他地方有填写同一个寄存器的地方导致将yuyv fmt 的寄存器被改写。

  1. 如果画面颜色正常,但是看到有一些行是粉红或者绿色的,往往是sensor 信号质量不好所致,通常在比较长的排线中出现这个情况。在信号质量不好并且

yuyv 顺序不对的时候也会看见整个画面的是绿色的花屏。

  1. 当驱动能力不足的时候增强sensor 的io 驱动能力有可能解决这个问题。此时用示波器观察pclk 和数据线可能会发现:pclk 波形摆幅不够IOVDD 的幅度,或者

是data 输出波形摆幅有时候能高电平达到IOVDD 的幅度,有时候可能连一半都不够。

  1. 如果是两个模组复用数据线的话,不排除是另外一个sensor 在进入standby 时候没有将其数据线设置成高阻,也会影响到当前模组的信号摆幅,允许的话可

以剪断另一个模组来证实。

  1. 当画面都正常之后检查前置摄像头垂直方向是否正确,水平方向是否是镜像,后置水平垂直是否正确,不对的话可以调节sys_config.fex 中的hflip 和vflip 参数

来解决,但如果屏幕上看到的画面与人眼看到的画面是成90 度的话,只能是通过修改模组的方向来解决。

  1. 之后可以检查不同分辨率之间的切换是否ok,是否有切换不成功的问题;以及拍照时候是否图形正常,亮度颜色是否和预览一致;双摄像头的话需要检查前后

切换是否正常。

  1. 如果上述都没有问题的话,可认为驱动无大问题,接下来可以进行其他功能(awb/exp bias/-color effect 等其他功能的测试)。

  2. 测试对焦功能,单次点触屏幕,可正确对上不同距离的物体;不点屏幕时候可以自动对焦对上画面中心物体,点下拍照后拍出来的画面能清晰。

     

  3. 打开闪光灯功能,检查在单次对焦时候能打开灯,对完之后无论成功失败或者超时能够关闭,在点下拍照之后能打开,拍完之后能关闭。

  4. 如果加载模块后,发现dev/videoX 节点没有生成,请检查下面几点。

a. 模块加载的顺序
    一定要按照以下顺序加载模块
    insmod videobuf-core.ko
    insmod videobuf-dma-contig.ko
    ;如果有对应的vcm driver,在这里加载,如果没有,请省略。
    insmod actuator.ko
    insmod ad5820_act.ko
    ;以下是camera驱动和vfe驱动的加载,先安装一些公共资源。
    insmod vfe_os.ko
    insmod vfe_subdev.ko
    insmod cci.ko
    insmod ov5640.ko
    insmod gc0308.ko
    ;如果一个csi接两个camera,所有camera对应的ko都要在vfe_v4l2.ko之前加载。
    insmod vfe_v4l2.ko
b. sys_config.fex配置
    vip_used = 1 ;确保used为1
    vip_dev_qty = 2 ;确保csi接口上接的camera数量与ko加载情况相同
    vip_dev0_mname = "ov5640" ;确保camera型号与ko加载情况相同
    vip_dev0_twi_id = 1 ;确保camera使用的i2c总线id与配置一样
    vip_dev1_mname = "gc0308" ;确保camera型号与ko加载情况相同
    vip_dev1_twi_id = 1 ;确保camera使用的i2c总线id与配置一样

5.5 画面大体轮廓正常,颜色出现大片绿色和紫红色

一般可能是csi 采样到的yuyv 顺序出现错位。

确认camera 输出的yuyv 顺序的设置与camera 的spec 一致 若camera 输出的yuyv 顺序没有问题,则可能是由于走线问题,导致pclk 采样data 时发生错位,此时可以调整pclk 的采样沿。具体做法如下:

在对应的camara 驱动源码,如ov5640.c 里面,找到宏定义#define CLK_POL。此宏定义可以有两个值V4L2_MBUS_PCLK_SAMPLE_RISING 和

V4L2_MBUS_PCLK_SAMPLE_FALLING。若原来是其中一个值,则修改成另外一个值,便可将PCLK 的采样沿做反相。

5.6 画面大体轮廓正常,但出现不规则的绿色紫色条纹

一般可能是pclk 驱动能力不足,导致某个时刻采样data 时发生错位。

解决办法:

• 若pclk 走线上有串联电阻,尝试将电阻阻值减小。

• 增强pclk 的驱动能力,需要设置camera 的内部寄存器。

 

5.7 画面看起来像油画效果,过渡渐变的地方有一圈一圈

一般是CSI 的data 线没有接好,或短路,或断路。

 

5.8 出现[VFE_WARN] Nobody is waiting on thisvideo buffer

上层还回来所有的buffer,但是没有再来取buffer。

 

5.9 出现[VFE_WARN] Only three buffer left for csi

上层占用了大部分buffer,没有还回,驱动部分只有三个buffer 此时驱动不再进行buffer 切换,直到有buffer 还回为止。

 

5.10 sensor 的硬件接口注意事项

  1. 如果是使用并口的sensor 模组,会使用到720p@30fps 或更高速度的,必须在mclk/pclk/- data/vsync/hsync 上面串33ohm 电阻,5M 的sensor 一律串电阻;

  2. 使用Mipi 模组时候PCB layout 需要尽量保证clk/data 的差分对等长,过孔数相等,特征 阻抗100ohm;

  3. 如果使用并口复用pin 的模组时候,不建议reset 脚的复用;

  4. 并口模组的排线长度加上pcb 板上走线长度不超过10cm,mipi 模组排线长度加上pcb 板上 走线长度不超过20cm,超过此距离不保证能正常使用。

  5. 主控并口数据线有D11~D0 共12bit,并口的sensor 输出一般为8/10bit,原理图连接需 要做高位对齐。

6 camera 功能测试

Tina 系统可以通过SDK 中的camerademo 包来验证camera sensor(usb camera)是否移植成功,如果可以正常捕获保存图像数据,则底层驱动、板子硬件正常。

6.1 camerademo 配置

在命令行中进入Tina 根目录,执行make menuconfig 进入配置主界面,并按以下配置路径操作:

Allwinner
	└─>camerademo

首先,选择Allwinner 选项进入下一级配置,如下图所示: image-20221123141424322

图6-1: allwinner

然后,选择camerademo 选项,可选择<*> 表示直接编译包含在固件,也可以选择表示仅编译不包含在固件。当平台的camera 框架是VIN 且需要使用ISP 时,将

需要在camerademo 的选项处点击回车进行以下界面选择使能ISP。(该选项只能在VIN 框架中,使用RAW sensor时使用,在修改该选项之后,需要先单独mm -

B 编译该package)。

image-20221123141504379

图6-2: camerademo

image-20221123141522573

图6-3: vinisp

6.2 源码结构

camerademo 的源代码位于package/allwinner/camerademo/目录下:

|---src
| camerademo.c //camea测试的主流程代码
| camerademo.h //camera demo相关数据结构
| common.c //实现共用的函数,转换时间、保存文件、测试帧率等
| common.h //共用函数头文件
| convert.c //实现图像格式转换函数
| convert.h //图像格式转换函数头文件

6.3 camerademo 使用方法

在小机端加载成功后输入camerademo help,假如驱动产生的节点video0(测试默认以/dev/video0 作为设备对象)可以打开则会出现下面提示:

通过提示我们可以得到一些提示信息,了解到该程序的运行方式、功能,可以查询sensor 支持的分辨率、sensor 支持的格式以及设置获取照片的数量、数据保存

的格式、路径、添加水印、测试数据输出的帧率、从open 节点到数据流打通需要的时间等,help 打印信息如下图:

image-20221123142705806

图6-4: help

Camerademo 共有4 种运行模式:

  1. 默认方式:直接输入camerademo 即可,在这种运行模式下,将设置摄像头为640*480 的NV21 格式输出图像数据,并以BMP 和YUV 的格式保存在/tmp 目

录下,而当输入camerademodebug 将会输出更详细的debug 信息;

  1. 探测设置camerademo setting:将会在运行过程中根据具体camera 要求输入设置参数,当输入camerademo setting debug 的时候,将会输出详细的debug 信息;

  2. 快速设置:camerademo argv[1] argv[2] argv[3] argv[4] argv[5] argv[6] argv[7],将会按照输入参数设置图像输出,同样,当输入camerademo argv[1]

argv[2] argv[3] argv[4] argv[5] argv[6] argv[7] debug 时将会输出更详细的debug 信息。

  1. 选择camera 设置:camerademo argv[1] argv[2] argv[3] argv[4] argv[5] argv[6] argv[7] argv[8],将会按照输入参数设置图像输出,同样,当输入

camerademo argv[1] argv[2] argv[3] argv[4] argv[5] argv[6] argv[7] argv[8] debug 时将会输出更详细的debug 信息。

6.3.1 默认方式

当输入camerademo 之后,使用默认的参数运行,则会打印一下信息,如下图:

image-20221123142833252

图6-5: camerademouser

首先可以清楚的看到成功open video0 节点,并且知道照片数据的保存路径、捕获照片的数量以及当前设置:是否添加水印、输出格式、分辨率和从开启流传输到

第一帧数据达到时间间隔等信息。如果需要了解更多的详细信息,可以在运行程序的时候输入参数debug 即运行camerademo debug,将会打开demo 的debug

模式,输出更详细的信息,包括camera 的驱动类型,支持的输出格式以及对应的分辨率,申请buf 的信息,实际输出帧率等。

6.3.2 选择方式

在选择模式下有两种运行方式,一种是逐步选择,在camera 的探测过程,知道其支持的输出格式以及分辨率之后再设置camera 的相关参数;另一种是直接在运

行程序的时候带上相应参数,程序按照输入参数运行(其中还可以选择camera 索引,从而测试不同的camera)。

  1. 输入camerademo setting,则按照程序的打印提示输入相应选择信息即可。 • 输入保存路径、照片数量、保存的格式等。

image-20221123142929515

图6-6: info

• 选择输出格式。

image-20221123142950450

图6-7: format

• 选择输出图像分辨率。

image-20221123143011933

图6-8: size

其它信息与默认设置一致,如需打印详细的信息,运行camerademo setting debug 即可。

  1. 第二种是设置参数: • 默认的video 0 节点:camerademo argv[1] argv[2] argv[3] argv[4] argv[5] argv[6] argv[7]。 输入参数代表意义如下:

argv[1]:camera输出格式---NV21 YUYV MJPEG等;
argv[2]:camera分辨率width;
argv[3]:camera分辨率height;
argv[4]:sensor输出帧率;
argv[5]:保存照片的格式:all---bmp和yuv格式都保存、bmp---仅以bmp格式保存、yuv---仅以yuv格式保存;
argv[6]:捕获照片的保存路径;
argv[7]:捕获照片的数量;

例如:camerademo NV21 640 480 30 yuv /tmp 2,将会输出640*480@30fps 的NV21格式照片以yuv 格式、不添加水印保存在/tmp 路径下,照片共2 张。

其它信息与默认设置一致,如需打印详细的信息,运行camerademo argv[1] argv[2] argv[3] argv[4] argv[5] argv[6] argv[7] debug 即可。

image-20221123143239114

图6-9: run1

• 选择其他的video 节点:camerademo argv[1] argv[2] argv[3] argv[4] argv[5] argv[6] argv[7] argv[8]。

输入参数代表意义如下:

argv[1]:camera输出格式---NV21 YUYV MJPEG等;
argv[2]:camera分辨率width;
argv[3]:camera分辨率height;
argv[4]:sensor输出帧率;
argv[5]:保存照片的格式:all---bmp和yuv格式都保存、bmp---仅以bmp格式保存、yuv---仅以yuv格式保存;
argv[6]:捕获照片的保存路径;
argv[7]:捕获照片的数量;
argv[8]:video节点索引;

例如:camerademo YUYV 640 480 30 yuv /tmp 1 1,将会打开/dev/video1 节点并输出640*480@30fps 的以yuv 格式、不添加水印保存在/tmp 路径下,照片共

1 张。

其它信息与默认设置一致,如需打印详细的信息,运行camerademo argv[1] argv[2] argv[3] argv[4] argv[5] argv[6] argv[7] argv[8] debug 即可。

image-20221123143328632

图6-10: run2

6.3.3 camerademo 保存RAW 数据

当需要使用camerademo 保存RAW 数据时,只需要将输出格式设置为RAW 格式即可。先确认sensor 驱动中的mbus_code 设置为多少位, 假设驱动中, 配置为

mbus_code =MEDIA_BUS_FMT_SGRBG10_1X10,那么可以确认sensor 输出是RAW10,camerademo 的输出格式设置为RAW10 即可。比如输入camerademo

RGGB10 1920 1080 30 bmp /tmp 5,以上命令输出配置sensor 输出RAW 数据并保存在/tmp 目录,命令的含义参考本章节的《选择方式》。

注意:RAW 数据文件的保存后缀是.raw 。

6.3.4 debug 信息解析

以下debug 信息将说明sensor 驱动的相关信息,拍摄到的照片保存位置、数量、保存的格式以及水印使用情况等:

image-20221123143422192

图6-11: debug1

以下debug 信息将说明驱动框架支持的格式以及sensor 支持的输出格式:

image-20221123143618199

图6-12: debug2

类似以下的信息代表这相应格式支持的分辨率信息:

image-20221123143642323

图6-13: debug3

以下信息将会提示将要设置到sensor 的格式和分辨率等信息:

image-20221123143703117

图6-14: debug4

以下信息将会提示设置格式的情况,buf 的相应信息等:

image-20221123143723798

图6-15: debug5

以下信息将提示当前拍照的照片索引以及从开启流传输到dqbuf 成功的时间间隔:

image-20221123143742621

图6-16: debug6

以下信息提示该sensor 的实际测量帧率信息:

image-20221123143807349

图6-17: debug7

以下信息提示从open 节点到可以得到第一帧数据的时间间隔,默认设置为测试拍照的相应设置:

image-20221123143825189

图6-18: debug8

6.3.5 文件保存格式

设置完毕之后,将会在所设路径(默认/tmp)下面保存图像数据,数据分别有两种格式,一种是YUV 格式,以source_ 格式.yuv 名称保存;一种是BMP 格式,以

bmp_ 格式.bmp 格式保存,如下图所示。

查看图像数据时,需要通过adb pull 命令将相应路径下的图像数据pull 到PC 端查看。

image-20221123143900168

图6-19: save

6.4 select timeout 了,如何操作?

在完成sensor 驱动的移植,驱动模块正常加载,I2C 正常通信,将会在/dev 目录下创建相应的video 节点,之后可以使用camerademo 进行捕获测试,如果出现

select timeout,end capture thread!,这个情况可按照以下操作进行debug。

  1. 先和模组厂确认,当前提供的寄存器配置是否可以正常输出图像数据。有些模组厂提供的寄存器配置还需要增加一个使能寄存器,这些可以在sensor

datasheet 上查询得到或者与模组厂沟通;

  1. 通过dmesg 命令, 查看在运行camerademo 的过程中内核是否有异常的打印。在MR813/R818 平台,内核出现tdm 相关字段的连续打印,则需要确认,

board.dts 中的isp配置是否正确,单摄的配置,isp_sel 和tdm_rx_sel 都需要配置为0;双摄的则需要先运行配置为isp0 的video 节点才能再运行isp1 的video

节点;

  1. 其他的按照是并口还是mipi 接口进行相应的debug;

6.4.1 DVP sensor

  1. 确定sensor 的出图data 配置正确,是8 位的、10 位的、12 位的?确认之后,检查驱动中的sensor_formats 和sys_config.fex 中的csi data pin 设置是否正

确;

  1. MCLK 的频率配置是否正确;

  2. sensor 驱动的sensor_g_mbus_config() 函数配置为DVP sensor,type 需要设置为V4L2_MBUS_PARALLEL;

  3. 确定输出的data 是高8 位、高10 位,确定硬件引脚配置没有问题;

  4. 示波器测量VSYNC、HSYNC 有没有波形输出,这两个标记着有一场数据、一行数据信号产 生;

  5. 测量data 脚有没有波形,电压幅值是否正常;

  6. 如果没有波形,检查一下sensor 的寄存器配置,看看有没有软件复位的操作,如果有,在该寄存器配置后面加上”{REG_DLY,0xff}“进行相应的延时,防止在

软件复位的时候,sensor还没有准备好就I2C 配置寄存器;

  1. 如果上面都还是没有接收到数据,那么在sensor 的驱动文件,有以下配置,这三个宏定义的具体值。每个都有两种配置,将这三个宏的配置两两组合,共8 种

配置,都尝试一下;

#define VREF_POL V4L2_MBUS_VSYNC_ACTIVE_HIGH
#define HREF_POL V4L2_MBUS_HSYNC_ACTIVE_HIGH
#define CLK_POL V4L2_MBUS_PCLK_SAMPLE_RISING

6.4.2 mipi sensor

如果mipi sensor 没有正常出图,做以下debug 操作:

  1. mipi 接口和主控板子连接不要飞线,mipi 信号本身就是高频差分信号,布线时都要求高,飞线更会影响其信号质量,导致无法正常接收数据;

  2. 确认sensor 驱动设置的mipi 格式,同样是查看sensor_g_mbus_config() 函数(lane 和通道数);

  3. 示波器测量mipi 接口的data 线、时钟线,看看有没有数据输出;

  4. 检查一下寄存器配置方面有没有软件复位的,增加相应的延时;

  5. 和模组厂商确认sensor 驱动中对应分辨率的sensor_win_sizes 以下参数配置是否与寄存器组配合的,因为这些参数将会影响mipi 接收数据;

.hts = 3550, .vts = 1126, .pclk = 120 * 1000 * 1000, .mipi_bps = 480 * 1000 * 1000,

上面的hts,又称line_length_pck,VTS 又称frame_length_lines,与寄存器的值要一致,Pclk(Pixel clock) 的值由PLL 寄存器计算得出,可简单计算,pclk = hts ×

vts × fps;而mipi_bps 为mipi 数据速率,mipi_bps = hts × vts × fps ×(12bit/10bit/8bit)/ lane。

有些sensor 的datasheet 没有标注hts 和vts 的,但是他们有H Blanking 和Vertical blanking,他们的转换公式是:

hts = H Blanking + output_width

vts = Vertical blanking + output_height

Output_width 就是输出的一行的大小,output_height 就是输出的一列的大小。

gc 厂的sensor,vts = VB + win_height + 16;VB 和win_height 都是可以从寄存器中获取得到的,注意,win_height 是寄存器值,而不是输出的高。

 

6.4.3 其他注意事项

6.4.3.1 R311、MR133

sensor_sel

在vin 框架中,sys_config.fex 有以下配置:

[vind0/sensor0]
...
[vind0/sensor1]
...
[vind0/vinc0]
vinc0_used = 1
vinc0_csi_sel = 0
vinc0_mipi_sel = 0
vinc0_isp_sel = 0
vinc0_rear_sensor_sel = 0
vinc0_front_sensor_sel = 0
vinc0_sensor_list = 0

在这里主要是需要注意vinc0_rear_sensor_sel 和vinc0_front_sensor_sel 的配置,当它们都配置为0,表明vind0/vinc0 配置的video0 节点,使用的是

vind0/sensor0 节点中配置的sensor 输出图像数据;当它们配置为0、1,表明vind0/vinc0 配置的video0 节点,可以使用vind0/sensor0 和vind0/sensor1 两个

sensor 输出图像数据,可以通过ioctl 的VIDIOC_S_INPUT 的index 选择使用哪个sensor 的输出;当它们都配置为1 的时候,表明vind0/vinc0 配置的video0 节

点,使用的是vind0/sensor1 的输出。

 

mipi AB 配置

mipi 配置方面,还有一个需要注意的,该部分在R311、MR133 平台才有这种情况。一般情况,我们使用的是MCSIB 组的mipi 接口,这个按照一般配置使用即

可,MCSIA、MCSIB,这两个会在原理图上表明使用的是哪一组接口,如果单独使用MCSIA 组的mipi 接口,在sys_config.fex 中配置如下:

由于只是使用MCSIA,所以应该配置的是[vind0/sensor1] 组sensor,vinc0_rear_sensor_sel 和
vinc0_front_sensor_sel 都配置为1.
[vind0/vinc0]
vinc0_used = 1
vinc0_csi_sel = 0
vinc0_mipi_sel = 0
vinc0_isp_sel = 0
vinc0_rear_sensor_sel = 1
vinc0_front_sensor_sel = 1
vinc0_sensor_list = 0


posted @ 2023-03-06 14:17  韦东山  阅读(523)  评论(0编辑  收藏  举报