美文网首页
【Camera专题】Camera驱动源码全解析_上

【Camera专题】Camera驱动源码全解析_上

作者: c枫_撸码的日子 | 来源:发表于2020-03-13 11:51 被阅读0次

    1、手把手撸一份驱动 到 点亮 Camera
    2、Camera dtsi 完全解析
    3、Camera驱动源码全解析上
    4、Camera驱动源码全解析下

    一.c文件函数全解析

    #define MAX_ANALOG_GAIN 1.0
    #define MIN_ANALOG_GAIN 15.5
    这2个值在datasheet(规格书),参考图1

    图1
    寄存器的值 gain倍数
    0x0100 (256) 1
    ··· ···
    0x0F80(3968) 15.5

    1.sensor 增益的计算

    1.1 sensor_real_to_register_gain
    计算模拟增益在sensor寄存器中对应的值

     12 /**
     13  * FUNCTION: sensor_real_to_register_gain
     14  *
     15  * DESCRIPTION: Calcuate sensor analog gain register value
     16  **/
     17 static unsigned int sensor_real_to_register_gain(float gain)
     18 {
     19   uint16_t reg_analog_gain;
     20 /*限制最大gain为15.5倍,最小gain为1倍*/
     21   if (gain < MIN_ANALOG_GAIN) {//1
     22       gain = MIN_ANALOG_GAIN;
     23   } else if (gain > MAX_ANALOG_GAIN) {//15.5
     24       gain = MAX_ANALOG_GAIN;
     25   }
     26   gain = (gain) * 256.0;//1倍gain对应256
     27   reg_analog_gain = (uint16_t) gain;//计算写到sensor 寄存器中的值
     28 
     29   return reg_analog_gain;
     30 }
    

    因为1倍gain 对应到寄存器的值为 0x100(十进制:256)
    所以 gain = (gain) * 256.0;

    特殊情况

     18 static uint32_t sensor_real_to_register_gain(float gain) {
     19     unsigned int reg_gain = 0;
             /*限制最大gain为15.5倍,最小gain为1倍*/
     20     if (gain > 15.5) {
     21         gain = 15.5;
     22     }else if(gain < 1.0){
     23         gain = 1.0;
     24     } else if (gain <= 2.0f) {
     25         gain = ((int)(gain * 16.0f)) / 16.0f;
     26     } else if (gain <= 4.0f) {
     27         gain = ((int)(gain * 8.0f)) / 8.0f;
     28     } else if (gain <= 8.0f) {
     29         gain = ((int)(gain * 4.0f)) / 4.0f;
     30     } else {
     31         gain = ((int)(gain * 2.0f)) / 2.0f;
     32     }
     33     gain = gain*256.0;//1倍gain对应256
     34     reg_gain = (unsigned short)gain;
     35     return reg_gain;
     36 }
    

    这部分为gain step 的判断,因我们的gain step不是线性的,举个例子:sensor analog gain= 4或4.2, ,在曝光时间一样的情况下,其亮度是一样的。添加了这部分的代码,可以保证同一亮度等级的gain 值归到一类,多出来的部分用平台端的digital gain来补,一定程度上可以避免gain step引起的AE闪烁问题。

    1.2 sensor_register_to_real_gain
    计算 模拟增益 真实倍数的gain

     38 /**
     39  * FUNCTION: register_to_real_gain
     40  *
     41  * DESCRIPTION: Calcuate sensor real gain value
     42  **/
     43 static float sensor_register_to_real_gain(uint32_t RegGain)
     44 {
     45     float real_gain;
             /*限制最大gain寄存器的值为0x0F80,最小为0x100*/
     46     if(RegGain>0x0F80){
     47         RegGain = 0x0F80;
     48     } else if(RegGain<0x100){
     49         RegGain = 0x100;
     50     }
     51     real_gain = (float) (((float)(RegGain))/256.0);//除以256得出几倍gain
     52     return real_gain;
     53 }
    

    real_gain = (float) (((float)(寄存器的值))/256.0);

    1.3 sensor_digital_gain_calc
    计算 sensor数字增益
    #define MIN_DIGITAL_GAIN 1.0
    #define MAX_DIGITAL_GAIN 1.0
    从规格书中或者FAE那里可以知道

    寄存器的值 digital_gain倍数
    0x0400 (1024) 1
    ··· ···
    0x1000(4096) 4
     54 /**
     55  * FUNCTION: sensor_digital_gain_calc
     56  *
     57  * DESCRIPTION: Calcuate the sensor digital gain
     58  **/
     59 static unsigned int sensor_digital_gain_calc(float real_gain, float sensor_real_gain)
     60 { 
     61   unsigned int reg_dig_gain = 0;
     62   float real_dig_gain = 0;
     63   
     64   if (real_gain > MAX_ANALOG_GAIN) {//15.5
     65     real_dig_gain = real_gain / sensor_real_gain;
     66   } else {
     67     real_dig_gain = MAX_DIGITAL_GAIN;//1
     68   }
     69   
     70   if (real_dig_gain > MAX_DIGITAL_GAIN) {//大于1就会设置成1
     71     real_dig_gain = MAX_DIGITAL_GAIN;//1
     72   }
     73   
     74   reg_dig_gain = (unsigned int)(real_dig_gain * 1024);//计算对应的reg_dig_gain 
     75   
     76   return reg_dig_gain;
     77 }
    

    因为数字增益补偿都在平台端做了,所以sensor端的数字增益补偿就不需要了。
    因此MAX_DIGITAL_GAIN 1.0设置成1倍。

    reg_dig_gain = (unsigned int)(real_dig_gain * 1024);
    real_dig_gain 结果是1,reg_dig_gain = 1x1024 =1024 也就是一倍数字增益.

    看一下相关log
    最暗环境下:



    real_gain =23.675781 > 15.5 = MAX_ANALOG_GAIN
    real_dig_gain(数字增益) = real_gain / sensor_real_gain=23.675781/15.5=1.527470;
    real_dig_gain >1
    因此 real_dig_gain = MAX_DIGITAL_GAIN=1;//1
    最亮环境下:



    同理,
    real_gain = 1.0 < MAX_ANALOG_GAIN = 15.5时
    real_dig_gain = MAX_DIGITAL_GAIN=1;//1

    因此sensor_digital_gain_calc算出了最后就是1x1024 = 1024

    2.sensor曝光时间的计算

     55 /**
     56  * FUNCTION: sensor_calculate_exposure
     57  *
     58  * DESCRIPTION: Calcuate the sensor exposure
     59  **/
     60 int32_t sensor_calculate_exposure(
     61   __attribute__((unused)) float real_gain,
     62   __attribute__((unused)) uint32_t line_count,
     63   __attribute__((unused)) sensor_exposure_info_t *exp_info,
     64   __attribute__((unused)) float s_real_gain) {
     65     if (!exp_info) {
     66       return -1;
     67     }
     68     MLOG("exposure real_gain %f line_count %d", real_gain, line_count);
     69     //计算模拟增益 对应 寄存器的值
     70     exp_info->reg_gain = sensor_real_to_register_gain(real_gain);
             //计算模拟增益 真实值
     71     exp_info->sensor_real_gain =
     72       register_to_real_gain(exp_info->reg_gain);
             //计算数字增益       
     73     exp_info->sensor_digital_gain = 0x400;//一倍数字gain 1024
     74     exp_info->sensor_real_dig_gain = 1.0f;//no sensor digital gain
            //当然你也可以直接调用函数,不过函数返回的永远是1024,结果是一样的
           // exp_info->sensor_digital_gain =
          // sensor_digital_gain_calc(real_gain, exp_info->sensor_real_gain);//结果为1024
          //    exp_info->sensor_real_dig_gain =
          //  (float)exp_info->sensor_digital_gain / 1024;//结果为 1
              //计算平台数字增益
     76     exp_info->digital_gain = real_gain / exp_info->sensor_real_gain;
     77     exp_info->line_count = line_count;//曝光行数
     78     return 0;
     79 }
    

    1.sensor_digital_gain 和 sensor_real_dig_gain
    这2个值代表的sensor端的数字增益,
    但是数字增益现在都是平台端做,所以sensor端不用。
    因此这两个值写成什么都不会产生任何影响,不写也行。
    驱动源码没有对sensor 的digital_gain寄存器写入任何值,所以sensor端不会生效。

    2. exp_info->digital_gain:平台端数字增益
    exp_info->digital_gain = real_gain / exp_info->sensor_real_gain;
    平台端数字增益=需要的真实增益/sensor端模拟增益

    log

    我们以红框为例子,计算一下:

    • exp_info->reg_gain :sensor端 模拟增益 对应 寄存器的值
      exp_info->reg_gain =sensor_real_to_register_gain(23.675781);
      23.675781 > 15.5,sensor端模拟增益最大只能做15.5
      exp_info->reg_gain = 15.5x256 = 3968
    • exp_info->sensor_real_gain:sensor端 模拟增益
      exp_info->sensor_real_gain = register_to_real_gain(exp_info->reg_gain);
      exp_info->sensor_real_gain = register_to_real_gain(3968);
      exp_info->sensor_real_gain = 3968/256=15.5
      exp_info->digital_gain:平台端数字增益
      exp_info->digital_gain
      = real_gain / exp_info->sensor_real_gain;
      =23.675781/15.5
      =1.5274

    这里分别就算出了sensor端需要补偿的模拟增益和平台端需要补偿的数字增益,
    exp_info->digital_gain =1.5274会在ISP端自己做补偿

    但是exp_info->sensor_real_gain=15.5需要写到sensor寄存器中才能生效。

    因此就有了下面的函数

    3.模拟增益 写入sensor寄存器

     81 /**
     82  * FUNCTION: sensor_fill_exposure_array
     83  *
     84  * DESCRIPTION: Fill the sensor exposure array
     85  **/
     86 int32_t sensor_fill_exposure_array(
     87   __attribute__((unused)) uint32_t gain,
     88   __attribute__((unused)) uint32_t digital_gain,
     89   __attribute__((unused)) uint32_t line,
     90   __attribute__((unused)) uint32_t fl_lines,
     91   __attribute__((unused)) int32_t luma_avg,
     92   __attribute__((unused)) uint32_t hdr_param,
     93   __attribute__((unused)) struct camera_i2c_reg_setting* reg_setting,
     94   __attribute__((unused)) unsigned int s_gain,
     95   __attribute__((unused)) int s_linecount,
     96   __attribute__((unused)) int is_hdr_enabled) {
     97     uint16_t i = 0;
     98     uint16_t reg_count = 0;
     99 
    100     if (!reg_setting) {
    101       return -1;
    102     }
    103     MLOG("gain %d line %d f_line %d", gain, line, fl_lines);
               //开启sensor 端的group 功能,将曝光(line),gain等打包,保证在同一帧下进去。
    104     for (i = 0; i < sensor_lib_ptr.groupon_settings.size; i++) {
    105       reg_setting->reg_setting[reg_count].reg_addr =
    106         sensor_lib_ptr.groupon_settings.reg_setting_a[i].reg_addr;
    107       reg_setting->reg_setting[reg_count].reg_data =
    108         sensor_lib_ptr.groupon_settings.reg_setting_a[i].reg_data;
    109       reg_setting->reg_setting[reg_count].delay =
    110         sensor_lib_ptr.groupon_settings.reg_setting_a[i].delay;
    111       reg_count++;
    112     }
    113     reg_setting->reg_setting[reg_count].reg_addr =
    114       sensor_lib_ptr.output_reg_addr.frame_length_lines;//frame_length_lines高8位地址
    115     reg_setting->reg_setting[reg_count].reg_data = (fl_lines & 0xFF00) >> 8;
    116     reg_setting->reg_setting[reg_count].delay = 0;
    117     reg_count++;
    118 
    119     reg_setting->reg_setting[reg_count].reg_addr =
    120       sensor_lib_ptr.output_reg_addr.frame_length_lines + 1;//frame_length_lines低8位地址
    121     reg_setting->reg_setting[reg_count].reg_data = (fl_lines & 0xFF);
    122     reg_setting->reg_setting[reg_count].delay = 0;
    123     reg_count++;
    124 
    125     reg_setting->reg_setting[reg_count].reg_addr =
    126     sensor_lib_ptr.exp_gain_info.coarse_int_time_addr;//曝光寄存器的地址3500
    127     reg_setting->reg_setting[reg_count].reg_data = (line & 0xFF0000) >> 16;
    128     reg_setting->reg_setting[reg_count].delay = 0;
    129     reg_count++;
    130 
    131     reg_setting->reg_setting[reg_count].reg_addr =
    132     sensor_lib_ptr.exp_gain_info.coarse_int_time_addr + 1;//曝光寄存器的地址3501
    133     reg_setting->reg_setting[reg_count].reg_data = (line & 0xFF00) >> 8;
    134     reg_setting->reg_setting[reg_count].delay = 0;
    135     reg_count++;
    136 
    137     reg_setting->reg_setting[reg_count].reg_addr =
    138       sensor_lib_ptr.exp_gain_info.coarse_int_time_addr + 2;//曝光寄存器的地址3502
    139     reg_setting->reg_setting[reg_count].reg_data = (line & 0xFF);
    140     reg_setting->reg_setting[reg_count].delay = 0;
    141     reg_count++;
    142 
    143     reg_setting->reg_setting[reg_count].reg_addr =
    144       sensor_lib_ptr.exp_gain_info.global_gain_addr;
                         //模拟增益寄存器的地址3508
    145     reg_setting->reg_setting[reg_count].reg_data = (gain & 0xFF00) >> 8;
    146     reg_setting->reg_setting[reg_count].delay = 0;
    147     reg_count++;
                         //模拟增益寄存器的地址3509
    149     reg_setting->reg_setting[reg_count].reg_addr =
    150       sensor_lib_ptr.exp_gain_info.global_gain_addr + 1;
    151     reg_setting->reg_setting[reg_count].reg_data = (gain & 0xFF);
    152     reg_setting->reg_setting[reg_count].delay = 0;
    153     reg_count++;
    154     //关闭sensor 端的group 功能
    155     for (i = 0; i < sensor_lib_ptr.groupoff_settings.size; i++) {
    156       reg_setting->reg_setting[reg_count].reg_addr =
    157         sensor_lib_ptr.groupoff_settings.reg_setting_a[i].reg_addr;
    158       reg_setting->reg_setting[reg_count].reg_data =
    159         sensor_lib_ptr.groupoff_settings.reg_setting_a[i].reg_data;
    160       reg_setting->reg_setting[reg_count].delay =
    161         sensor_lib_ptr.groupoff_settings.reg_setting_a[i].delay;
    162       reg_count++;
    163     }
    164 
    165 
    166     reg_setting->size = reg_count;
    167     reg_setting->addr_type = CAMERA_I2C_WORD_ADDR;
    168     reg_setting->data_type = CAMERA_I2C_BYTE_DATA;
    169     reg_setting->delay = 0;
    170     return 0;
    171 }
    

    这里我们只是把所有的配置信息写入了camera_i2c_reg_setting这个结构体,真正写入寄存器的是下面这个操作:


    sensor_write_i2c_setting 通过IOCTL给内核发了一个指令:VIDIOC_MSM_SENSOR_CFG
    LOG_IOCTL(ctrl->s_data->fd, VIDIOC_MSM_SENSOR_CFG, &cfg, "write_i2c")

    最终调用到内核方法msm_sensor_config

    特殊情况:


    因为OV5675 这颗sensor比较特殊, exposure is twice as before,Ex. [3501,3502]=0040 means 8 Tline exposure。

    总结

    1.sensor模拟增益
    sensor_real_to_register_gain 模拟增益真实值,如1倍gain 2.2倍gain
    sensor_register_to_real_gain 模拟增益对应的sensor寄存器的值:如1倍gain 对应256

    2.sensor 数字增益
    sensor_digital_gain_calc:返回的是1倍digital_gain的值
    由于数字增益在都在平台端做,sensor端不再补偿。

    3.sensor曝光函数计算:
    sensor端最大做15.5倍模拟增益,超过的部分平台端做数字增益补偿!

    4.写入sensor寄存器
    sensor_fill_exposure_array只把寄存器信息填充到camera_i2c_reg_setting,
    最终通过内核写入sensor

    AEC 算法使用实际增益。由于必须将传感器硬件的实际增益转换为寄存器增益才能配置传
    感器,因此,我们必须基于传感器数据表实现以下函数。参考传感器数据表中的模拟和数
    字增益设置部分。
    xxxx_real_to_register_gain()
    xxxx_register_to_real_gain()
    下列函数用于计算下一次曝光配置的曝光时间和增益。
    xxxx_calculate_exposure()
    以下函数用于准备下一次曝光配置的数组。
    xxxx_fill_exposure_array()

    继续当一名咸鱼( ̄︶ ̄)!

    Stay hungry,Stay foolish!

    相关文章

      网友评论

          本文标题:【Camera专题】Camera驱动源码全解析_上

          本文链接:https://www.haomeiwen.com/subject/hswpjhtx.html