4.图像sensor的特性和驱动解析 - 平凡的世界&&技术博客

时间:2024-02-29 15:00:45

4.图像sensor的特性和驱动解析

修改 摄像头SDK中支持的sensor需要做的事

例如:ar0130 --> ov9712

1.修改加载load3518e脚本的参数 vi /etc/profile

./load3518e -i -sensor ar0130 -osmem 32 -total 64
修改参数为

/load3518e -i -sensor ov9712 -osmem 32 -total 64 

2.应用程序修改配置

1)使用提供的已配置好的程序进行测试

执行sample_9712

rtsp://192.168.1.10:554/test.264

测试无误

2)修改mpp/sample/makefile.param重新编译之前的程序

SENSOR_TYPE ?= OMNIVISION_OV9712_DC_720P_30FPS

#SENSOR_TYPE ?= APTINA_AR0130_DC_720P_30FPS 

make clean

cd venc_ortp

make

cp sample_venc_ortp ~/nfs_hi/ov9712_ortp 

./ov9712_ortp 0 

VLC播放器打开文件demo.sdp

 

4.1.本季课程主要内容和安排

4.1.1、本课程主要内容
(1)查看SDK中相应文档,重点是SoC对Sensor的支持

load3518e脚本中的重点内容

#!/bin/sh
# Useage: ./load3518e [ -r|-i|-a ] [ sensor ]
#         -r : rmmod all modules
#         -i : insmod all modules
#    default : rmmod all moules and then insmod them
#


# imx222 9m034 ov9752 ar0230 ar0130 ov9712 mn34222



####################Variables Definition##########################


SNS_TYPE=ar0230             # sensor type

mem_total=64;               # 64M, total mem
mem_start=0x80000000;       # phy mem start

os_mem_size=32;             # 32M, os mem
mmz_start=0x82000000;       # mmz start addr
mmz_size=32M;               # 32M, mmz size


##################################################################




insert_sns()
{
case $SNS_TYPE in
ar0130|9m034)
himm 0x200f0040 0x2; # I2C0_SCL
himm 0x200f0044 0x2; # I2C0_SDA

#cmos pinmux
himm 0x200f007c 0x1; # VI_DATA13
himm 0x200f0080 0x1; # VI_DATA10
himm 0x200f0084 0x1; # VI_DATA12
himm 0x200f0088 0x1; # VI_DATA11
himm 0x200f008c 0x2; # VI_VS
himm 0x200f0090 0x2; # VI_HS
himm 0x200f0094 0x1; # VI_DATA9

himm 0x2003002c 0xc4001; # sensor unreset, clk 27MHz, VI 99MHz
;;
ar0230)
himm 0x200f0040 0x2; # I2C0_SCL
himm 0x200f0044 0x2; # I2C0_SDA

himm 0x2003002c 0xb4005; # sensor unreset, clk 27MHz, VI 148.5MHz
himm 0x20030104 0x1; # vpss 148.5MHz
;;
imx222)
himm 0x200f0040 0x1 # SPI0_SCLK
himm 0x200f0044 0x1 # SPI0_SDO
himm 0x200f0048 0x1 # SPI0_SDI
himm 0x200f004c 0x1 # SPI0_CSN

#cmos pinmux
himm 0x200f007c 0x1; # VI_DATA13
himm 0x200f0080 0x1; # VI_DATA10
himm 0x200f0084 0x1; # VI_DATA12
himm 0x200f0088 0x1; # VI_DATA11
himm 0x200f008c 0x2; # VI_VS
himm 0x200f0090 0x2; # VI_HS
himm 0x200f0094 0x1; # VI_DATA9

himm 0x2003002c 0x94001; # sensor unreset, clk 37.125MHz, VI 99MHz

insmod extdrv/sensor_spi.ko;
;;
ov9712)
himm 0x200f0040 0x2; # I2C0_SCL
himm 0x200f0044 0x2; # I2C0_SDA

#cmos pinmux
himm 0x200f007c 0x1; # VI_DATA13
himm 0x200f0080 0x1; # VI_DATA10
himm 0x200f0084 0x1; # VI_DATA12
himm 0x200f0088 0x1; # VI_DATA11
himm 0x200f008c 0x2; # VI_VS
himm 0x200f0090 0x2; # VI_HS
himm 0x200f0094 0x1; # VI_DATA9

himm 0x2003002c 0xb4001; # sensor unreset, clk 24MHz, VI 99MHz
;;
ov9732)
himm 0x200f0040 0x2; # I2C0_SCL
himm 0x200f0044 0x2; # I2C0_SDA

#cmos pinmux
himm 0x200f007c 0x1; # VI_DATA13
himm 0x200f0080 0x1; # VI_DATA10
himm 0x200f0084 0x1; # VI_DATA12
himm 0x200f0088 0x1; # VI_DATA11
himm 0x200f008c 0x2; # VI_VS
himm 0x200f0090 0x2; # VI_HS
himm 0x200f0094 0x1; # VI_DATA9

himm 0x2003002c 0xc4001; # sensor unreset, clk 24MHz, VI 99MHz
;;

ov9752)
himm 0x200f0040 0x2; # I2C0_SCL
himm 0x200f0044 0x2; # I2C0_SDA

himm 0x2003002c 0xc4001; # sensor unreset, clk 24MHz, VI 99MHz
;;
ov9750)
himm 0x200f0040 0x2; # I2C0_SCL
himm 0x200f0044 0x2; # I2C0_SDA

himm 0x2003002c 0xc4001; # sensor unreset, clk 24MHz, VI 99MHz
;;

ov2718)
himm 0x200f0040 0x2; # I2C0_SCL
himm 0x200f0044 0x2; # I2C0_SDA

himm 0x2003002c 0xc4001; # sensor unreset, clk 24MHz, VI 99MHz
;;

mn34222)
himm 0x200f0040 0x2; # I2C0_SCL
himm 0x200f0044 0x2; # I2C0_SDA

himm 0x2003002c 0x94001; # sensor unreset, clk 37.125MHz, VI 99MHz
;;

bt1120)
himm 0x200f0008 0x4; # VI_VS
himm 0x200f000c 0x4; # VI_HS
himm 0x200f007c 0x1; # VI_DATA13
himm 0x200f0080 0x1; # VI_DATA10
himm 0x200f0084 0x1; # VI_DATA12
himm 0x200f0088 0x1; # VI_DATA11
himm 0x200f008c 0x1; # VI_DATA15
himm 0x200f0090 0x1; # VI_DATA14
himm 0x200f0094 0x1; # VI_DATA9

himm 0x2003002c 0x94003; # sensor unreset, clk 24MHz, VI 99MHz
;;

*)
echo "xxxx Invalid sensor type $SNS_TYPE xxxx"
report_error;;
esac
}

 

 

 查看/etc/profile中的内容(此次为自行添加的内容)


ifconfig lo 127.0.0.1
ifconfig eth0 192.168.1.10

cd /ko
./load3518e -i -sensor ar0130 -osmem 32 -total 64
mount -t nfs -o nolock 192.168.1.14:/home/swann/nfs_hi /mnt
cd /mnt

.

修改参数为

/load3518e -i -sensor ov9712 -osmem 32 -total 64

 


(2)更换另一个Sensor(OV9712),并实现之前的实验
(3)Sensor接口:并口/LVDS/MIPI CSI
(4)SoC的Sensor接口引脚复用设置
(5)sensor驱动源码详解
(6)sample中sensor相关的部分详解
4.1.2、查看SDK的2个相关文档

 

 

 


4.2.更换OV9712并且做配置更改和测试
4.2.1、更改配置脚本
4.2.2、运行rtsp传输的测试版本
4.2.3、运行官方SDK sample的测试版本
4.2.4、运行ORTP传输的测试版本
4.2.5、更换sensor的总结
(1)程序框架做好多种sensor支持的框架
(2)注意硬件接线上面的差异
(3)加载不同的驱动,做不同的参数设置

修改mpp/sample/makefile.param,更换sensor type,如何make clean,

进入venc文件夹,make


4.3_4.MIPI和LVDS和并口的细节讲解1_2
4.3.1、并口Sensor
(1)OV9712和AR0130都是并口的
(2)并口的接口定义:参考AR0130的原理图pdf
(3)并口传输的是CMOS电平信号(重点是非差分)
(4)并口sensor属于较低端老旧的,新型高像素的都是MIPI/LVDS/HISPI等差分信号的
4.3.2、LVDS
(1)low voltage differential signal,低电压差分信号
(2)接口由1组差分clock和若干组差分信号线组成
(3)LVDS主要用于视频传输的2个领域:camera和主控、LCD和主控
(4)LVDS利用差分抗干扰能力,提升clock频率从而提升带宽,传输距离也更远
(5)LVDS的数据线组数越多带宽越大、clock频率越高带宽越大(牺牲抗干扰和距离)
(6)并口和LVDS之间可以互转,但是需要专门的电平转换芯片(类似于232和485)
4.3.3、MIPI(MIPI-CSI2)
(1)MIPI: mobile industry processor interface,移动工业处理器接口
(2)MIPI接口由1组差分clock和1-4组差分信号线组成
(3)MIPI和LVDS虽然都是差分对信号,但是不兼容,不能直接对接
(4)MIPI的架构层次更分明,广泛应用在手机平板等领域中,可以认为MIPI是LVDS的升级版
(5)MIPI的数据线组数越多带宽越大、clock频率越高带宽越大(牺牲抗干扰和距离)
(6)MIPI和LVDS和并口之间均可以互相转换,但是需要专门的电平转换芯片
4.3.4、总结
(1)老旧的、低端的、数据量小的就用电平信号;新的、高端的、数据量大的都用差分信号
(2)要通信,物理层、协议层、应用层都得能对接才行。
(3)因为历史原因,很多行业会使用不同的接口标准,必要时需要去互相转换


4.5_6.HI3518E的Sensor接口引脚复用设置1_2
4.5.1、查看引脚定义框图
4.5.2、找到相应设置寄存器
4.5.3、himm工具


4.7.sensor驱动源码解析1
4.7.1、sensor驱动源码寻找
(1)从sample入手
(2)sensor层驱动在component/isp中(mpp\component\isp\sensor\ar0130)
(3)底层i2c驱动在kernel中
4.7.2、sensor驱动的框架
(1)mpp定义了一套sensor驱动的实现和封装
(2)xxxx_cmos.c中定义回调和上层函数
(3)xxxx_sensor_ctl.c中定义底层硬件相关的寄存器值配置函数
(4)kernel中的I2C驱动提供i2c层面的物理层操作接口

SAMPLE_COMM_VI_StartIspAndVi

SAMPLE_COMM_ISP_Init

sensor_register_callback由开始对接驱动和应用层

cmos_init_sensor_exp_function(&stIspRegister.stSnsExp);
s32Ret = HI_MPI_ISP_SensorRegCallBack(IspDev, AR0130_ID, &stIspRegister);

HI_S32 cmos_init_sensor_exp_function(ISP_SENSOR_EXP_FUNC_S *pstSensorExpFunc)
{
memset(pstSensorExpFunc, 0, sizeof(ISP_SENSOR_EXP_FUNC_S));

pstSensorExpFunc->pfn_cmos_sensor_init = sensor_init;
pstSensorExpFunc->pfn_cmos_sensor_exit = sensor_exit;
pstSensorExpFunc->pfn_cmos_sensor_global_init = sensor_global_init;
pstSensorExpFunc->pfn_cmos_set_image_mode = cmos_set_image_mode;
pstSensorExpFunc->pfn_cmos_set_wdr_mode = cmos_set_wdr_mode;

pstSensorExpFunc->pfn_cmos_get_isp_default = cmos_get_isp_default;
pstSensorExpFunc->pfn_cmos_get_isp_black_level = cmos_get_isp_black_level;
pstSensorExpFunc->pfn_cmos_set_pixel_detect = cmos_set_pixel_detect;
pstSensorExpFunc->pfn_cmos_get_sns_reg_info = cmos_get_sns_regs_info;

return 0;
}

 

void sensor_init()
{

if (1 == gu8SensorImageMode) /* SENSOR_720P_30FPS_MODE */
{
sensor_init_720p_30fps();
bSensorInit = HI_TRUE;
}
else if (2 == gu8SensorImageMode) /* SENSOR_960P_30FPS_MODE */
{
sensor_init_960p_30fps();
bSensorInit = HI_TRUE;
}
else
{
printf("Not support this mode\n");
}

}

sensor_write_register(0x200, 0x31); //sensor_write_register(0x200, 0x01)

在以下函数中对接sensor驱动和内核IIC接口

int sensor_write_register(int addr, int data)
{
#ifdef HI_GPIO_I2C
    i2c_data.dev_addr = sensor_i2c_addr;
    i2c_data.reg_addr = addr;
    i2c_data.addr_byte_num = sensor_addr_byte;
    i2c_data.data = data;
    i2c_data.data_byte_num = sensor_data_byte;

    ret = ioctl(g_fd, GPIO_I2C_WRITE, &i2c_data);

    if (ret)
    {
        printf("GPIO-I2C write faild!\n");
        return ret;
    }
#else
    int idx = 0;
    int ret;
    char buf[8];

    buf[idx++] = addr & 0xFF;
    if (sensor_addr_byte == 2)
    {
        ret = ioctl(g_fd, I2C_16BIT_REG, 1);
        buf[idx++] = addr >> 8;
    }
    else
    {
        ret = ioctl(g_fd, I2C_16BIT_REG, 0);
    }

    if (ret < 0)
    {
        printf("CMD_SET_REG_WIDTH error!\n");
        return -1;
    }

    buf[idx++] = data;
    if (sensor_data_byte == 2)
    {
        ret = ioctl(g_fd, I2C_16BIT_DATA, 1);
        buf[idx++] = data >> 8;
    }
    else
    {
        ret = ioctl(g_fd, I2C_16BIT_DATA, 0);
    }

    if (ret)
    {
        printf("hi_i2c write faild!\n");
        return -1;
    }

    ret = write(g_fd, buf, idx);
    if(ret < 0)
    {
        printf("I2C_WRITE error!\n");
        return -1;
    }
#endif
    return 0;
}

 


4.8.sensor驱动源码解析2
4.8.1、xxxx_cmos.c中实现和注册回调
4.8.2、xxxx_sensor_ctl.c中配置sensor寄存器


4.9.ISP_3A框架解读


4.10.sensor驱动编译实战
4.10.1、sensor的注册接口分析
4.10.2、黑电平

HI_U32 cmos_get_isp_black_level(ISP_CMOS_BLACK_LEVEL_S *pstBlackLevel)
{
    HI_S32  i;
    
    if (HI_NULL == pstBlackLevel)
    {
        printf("null pointer when get isp black level value!\n");
        return -1;
    }

    /* Don\'t need to update black level when iso change */
    pstBlackLevel->bUpdate = HI_FALSE;

    switch (genSensorMode)
    {
        default :
        case WDR_MODE_NONE :
            for (i=0; i<4; i++)
            {
                pstBlackLevel->au16BlackLevel[i] = 0xC8;
            }
            break;

    }

    return 0;    
}
修改 pstBlackLevel->au16BlackLevel[i] = 0xC8;更改黑电平值


4.10.3、sensor驱动编译实战
(1)修改驱动源码
(2)清除,并重新编译
(3)确认mpp中lib目录下的libsnsxxx.a/so已经被更新
(4)重新编译sample并运行查看效果

 


4.11.sensor驱动的寄存器操作
4.11.1、sensor的寄存器设置
(1)sensor内部有若干寄存器,可以通过I2C接口来读写
(2)数据手册有对寄存器的基本说明
(3)经验:大部分寄存器设置厂家会给,偶尔需要自己调一些
4.8.4、实战任务:修改sensor的flip和mirror寄存器查看效果
(1)查sensor数据手册的寄存器列表
(2)改sensor驱动代码

void sensor_init_720p_30fps()

在pll初始化前添加
(3)重新编译isp
(4)确认sensor库已经更新到mpp中
(5)重新编译sample,运行测试


4.12.sensor驱动部分贯通总结
4.12.1、体系思想
(1)成熟的商业解决方案都是一整套设计好的模式
(2)第一步是理解,第二步是用起来,第三步是小修改,第四步是大修改,第五步是创造
4.12.2、海思方案的sensor驱动相关体系关键点
(1)搞清楚sensor的本质:光电转换+AD+ISP+并口/MIPI/LVDS
(2)ISP有多种实现:sensor内置、主SoC内置、外接专用ISP芯片
(3)3A是为最终图像效果负责的,3A的实现有赖于镜头、sensor、isp等各部门协同工作
(4)海思的体系中把sensor和3A、ISP实现为:指针挂接注册的各自独立模块
4.12.3、扩展学习方向
(1)sensor的各种参数
(2)其他几种sensor的驱动和对比实现
(3)isp的firmware
(4)3A算法相关知识