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()
继续当一名咸鱼( ̄︶ ̄)!
网友评论