当前位置: 首页 > news >正文

第4季6:图像sensor的寄存器操作

以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。

一、sensor_write_register函数的解析

在第4季4:图像sensor的驱动源码解析中写到,sensor_register_callback函数的调用关系如下:

sensor_register_callback                //位于ar0130_cmos.c文件文件
    cmos_init_sensor_exp_function       //位于ar0130_cmos.c文件文件
        sensor_init                     //位于ar0130_sensor_ctl.c文件
            sensor_init_720p_30fps      //位于ar0130_sensor_ctl.c文件
                sensor_write_register   //位于ar0130_sensor_ctl.c文件
                    sensor_i2c_init     //位于ar0130_sensor_ctl.c文件,只执行一次
                    ioctl               //I2C驱动提供给应用层的接口函数

我们重点关注其中的sensor_write_register函数,该函数主要完成对某个寄存器的赋值操作,比如在函数sensor_init_720p_30fps中,调用sensor_write_register函数的情形如下。

void sensor_init_720p_30fps()
{
//[720p30]

    sensor_write_register( 0x301A, 0x0001 );    // RESET_REGISTER
    delay_ms(200); //ms 因为操作可能需要耗费一定的时间
    sensor_write_register( 0x301A, 0x10D8 );    // RESET_REGISTER
    delay_ms(200); //ms
    //Linear Mode Setup
    //AR0130 Rev1 Linear sequencer load  8-2-2011
    sensor_write_register( 0x3088, 0x8000 );// SEQ_CTRL_PORT
    sensor_write_register( 0x3086, 0x0225 );// SEQ_DATA_PORT

//省略部分代码
}

我们来详细分析sensor_write_register函数的代码细节。

int sensor_write_register(int addr, int data)
{
#ifdef HI_GPIO_I2C    //可略过,因为这部分是使用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  //我们重点关注这部分
    if(flag_init == 0)//如果还没有执行过I2C的初始化
    {
    
	sensor_i2c_init();//执行初始化
	flag_init = 1;//之后不会再初始化
    }

    int idx = 0;
    int ret;
    char buf[8];//定义了8个字节长度的字符数组

    buf[idx++] = addr & 0xFF;//   buf[0]= 地址的低8位
    if (sensor_addr_byte == 2)//如果地址类型是16位的。
                              //对于AR0130,其寄存器地址就是16bit的,这个成立。
    {
        ret = ioctl(g_fd, I2C_16BIT_REG, 1);
        buf[idx++] = addr >> 8;// buf[1]= 16位地址的高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;//buf[2]=数据的低8位?这里为何不“& 0xFF”呢?
    if (sensor_data_byte == 2)//如果数据长度是16位的。
                              //对于AR0130,寄存器的长度就是16位的,这个成立。
    {
        ret = ioctl(g_fd, I2C_16BIT_DATA, 1);
        buf[idx++] = data >> 8;//buf[3]=数据的高8位
    }
    else
    {
        ret = ioctl(g_fd, I2C_16BIT_DATA, 0);
    }

    if (ret)
    {
        printf("hi_i2c write faild!\n");
        return -1;
    }
    //至此,寄存器的地址、寄存器的数据都存储在buf数组中了。
    //接下来要调用I2C驱动提供给应用层的接口(即write函数)来进行真正的数据写入。
    ret = write(g_fd, buf, idx);
    if(ret < 0)
    {
        printf("I2C_WRITE error!\n");
        return -1;
    }
#endif
    return 0;
}

其中的sensor_i2c_init函数内容如下:

int sensor_i2c_init(void)
{
    if(g_fd >= 0)
    {
        return 0;
    }    
//省略部分代码
    int ret;

    g_fd = open("/dev/i2c-0", O_RDWR);//打开I2C驱动对应的设备文件
    if(g_fd < 0)
    {
        printf("Open /dev/i2c-0 error!\n");
        return -1;
    }
    //利用ioctl函数来将I2C强制转换为slave模式?i2c地址要查数据手册
    ret = ioctl(g_fd, I2C_SLAVE_FORCE, sensor_i2c_addr);
    if (ret < 0)
    {
        printf("CMD_SET_DEV error!\n");
        return ret;
    }

    return 0;
}

二、sensor寄存器的解析

对于sensor_write_register函数,它的参数1是sensor寄存器的地址,参数2是要写入sensor寄存器中的数值。如何查看sensor寄存器的地址以及某个寄存器的位含义?可以查看sensor的数据手册。这里以AR0130的数据手册《AR0130_RR_C》为例。

上面的sensor_init_720p_30fps函数的第一行代码如下,其中0x301A表示地址为0x301A的寄存器,0x0001表示要往该寄存器中写入的数值。根据注释,这行代码完成寄存器的复位工作(即复位AR0130)。

sensor_write_register( 0x301A, 0x0001 );    // RESET_REGISTER

我们通过查找数据手册来验证是否如此。在该数据手册的第7页前后有如下内容,从中可知寄存器的地址为16位的,寄存器的数据长度也是16位的。圈出的部分是地址为0x301A的寄存器的内容,可知它的名字是“reset_register”,猜想和寄存器复位(即复位AR0130)有关。

我们进一步找到这个寄存器的位含义表格(在第27页前后)。根据描述,bit[0]如果写1则会产生复位信号(复位的时候sensor如果正在采集数据,则会丢弃这帧数据)。上面的那行代码中的参数2为0x0001,这意味着给bit[0]写1,所以那行代码就是用来复位sensor的,就如注释写的一样。

三、sensor寄存器的操作实验

在数据手册的29页前后,有一个地址为0x3040的寄存器的描述,该寄存器用来设置图像的翻转。

(1)我们可以在mpp/component/isp/sensor/ar0130/ar0130_sensor_ctl.c文件中的sensor_init_720p_30fps函数的合适位置(大概330行处),修改代码如下。

//Enable Parallel Mode
sensor_write_register( 0x301A, 0x10D8); // RESET_REGISTER
sensor_write_register( 0x31D0, 0x0001); // HDR_COMP

//新添的内容,翻转是flip,镜像是mirror
//sensor_write_register( 0x3040, 0x0000);//第一次:未flip,未mirror
//sensor_write_register( 0x3040, 0x8000);//第二次:flip,未mirror,即仅水平翻转
//sensor_write_register( 0x3040, 0x4000);//第三次:未flip,但mirror,即仅垂直翻转
//sensor_write_register( 0x3040, 0xC000);//第四次:flip、mirror,即同时水平、垂直翻转

然后我们在mpp/component/isp下执行make(为了生成更改后的库形式的“应用层驱动”。这里不用执行make clean,因为Makefile感知到源码修改了,因此会更新(作为目标的)库文件)。

接着我们在mpp/sample_ortp_ar0130/venc目录下执行make clean再执行make(这里就需要先执行make clean,因为之前的操作,没有修改源码sample_venc.c,而只是修改了库文件,该目录下的Makefile不会感知到库文件的更新,从而不会更新sampl_venc。如果不make clean,执行make的时候将不进行任何操作),生成samp_venc这个可执行程序。

接着将sample_venc文件拷贝到虚拟机/home/xjh/iot/hisi_development/hisi_rootfs/目录中,然后将该目录挂载到板载系统的/mnt目录,在/mnt目录下执行“./sample_venc 0”,输入c。

接着在VLC播放器中,选择媒体,打开文件,选择sdp文件(提取码ms4a)(注意这文件里的设置要与实际对应)。此时可以看到实时画面,我们截图进行对比。

第一次:原来图像。 

第二次:水平翻转图像(flip)。 

 第三次:垂直翻转(mirror)

第四次:水平翻转与垂直翻转。

相关文章:

  • 汽车电子之功能安全介绍
  • 【viper】go 配置管理神器viper使用详解
  • 170-本地WIFI测试环境配置IP
  • 【面试宝典】Mysql面试题大全
  • Unity 符号表
  • Sentinel--服务容错
  • rust编译器教我做人,为啥还要学习rust语言,因为想使用rust做一些底层服务,更深入的研究技术。
  • Visual Assist v10.9.2471.0 Crack
  • 面试题:SpringBoot调用http服务几种方式
  • yolov7配置与训练记录(二)
  • Spring Cloud(十五):微服务自动化部署 DevOps CI/CD、Maven打包、ELK日志采集
  • [设计] Doris血缘解析流程
  • 【校招VIP】[推电影项目]商业项目的竞品分析和需求分析
  • 语法练习:array123
  • 设计模式之原型模式
  • JVM之垃圾收集器三
  • 【web前端期末大作业】基于html关爱空巢老人网页设计与实现
  • flutter课程(The Complete 2021 Flutter Development Bootcamp with Dart)学习总结
  • 架构师知识体系梳理
  • LaTex使用技巧9:argmin / argmax下标写法
  • 电加热油锅炉工作原理_电加热导油
  • 大型电蒸汽锅炉_工业电阻炉
  • 燃气蒸汽锅炉的分类_大连生物质蒸汽锅炉
  • 天津市维修锅炉_锅炉汽化处理方法
  • 蒸汽汽锅炉厂家_延安锅炉厂家
  • 山西热水锅炉厂家_酒店热水 锅炉
  • 蒸汽锅炉生产厂家_燃油蒸汽发生器
  • 燃煤锅炉烧热水_张家口 淘汰取缔燃煤锅炉
  • 生物质锅炉_炉
  • 锅炉天然气_天燃气热风炉