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

系列文章

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

寄存器的值 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端模拟增益

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

  • 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!

猜你喜欢

转载自blog.csdn.net/justXiaoSha/article/details/121266952