学习AF代码

1. vcm介绍

  • 这个网上的资料很多,这里就不介绍了,对于开发调试需要关注的是vcm的起始电流范围
    起始电流如果太小则对焦比较慢,如果太大 则远焦不清晰
    一般建议:起始电流取vcm规格书的偏下限。

3. driver ic介绍
学习AF代码_第1张图片

  • 以上是ic的引脚图,通常模组会引出vdd即软件端的afvdd,xsd是低功耗模式(低有效)。许多硬件会将xsd和sensor的电共用起来,如果camera在退出之后,xsd处于高电平状态,则会出现漏电情况。
  • powerdown:软件低功耗模式,只有当硬件无法进入休眠时使用,列如afvdd掉电,xsd的电长供,就需要用到此寄存器
  • 寄存器:driver ic厂根据模组测试出来数据,init和消除震荡,震荡时间要小于33ms
  • 输出电流:输出的电流范围,比如0-100mA
  • 位数:AD转换的位数,目前都是10位,所以AF DAC range 范围是(0-1023),由于在对焦曲线内是线性的,可以通过电流或者DAC值转换DAC或者电流值

4. 代码及otp介绍

  • 基本代码分析
      .initial_code = 180,
      .region_size = 1,
      .region_params =
      {
        {
          .step_bound =
          {
            414, /* Macro step boundary*/
            0, /* Infinity step boundary*/
          },
          .code_per_step = 1,
          .qvalue = 128,
        },
      },
      initial_code = 180
      total step = step_bound[0] - step_bound[1]
      qvalue:如果没有otp,设置为1,有otp设置成128,通常情况code_per_step 为1.

获取actuator驱动中配置参数,进行actuator的初始化

static int32_t msm_actuator_set_param(struct msm_actuator_ctrl_t *a_ctrl,
	struct msm_actuator_set_info_t *set_info) {
	struct reg_settings_t *init_settings = NULL;
	int32_t rc = -EFAULT;
	uint16_t i = 0;
	struct msm_camera_cci_client *cci_client = NULL;
	CDBG("Enter\n");
/*根据vcm的type 获取具体的操作函数*/
	for (i = 0; i < ARRAY_SIZE(actuators); i++) {
		if (set_info->actuator_params.act_type ==
			actuators[i]->act_type) {
			a_ctrl->func_tbl = &actuators[i]->func_tbl;
			rc = 0;
		}
	}
……………………………………………………………………
	a_ctrl->region_size = set_info->af_tuning_params.region_size;
	a_ctrl->pwd_step = set_info->af_tuning_params.pwd_step;
	a_ctrl->total_steps = set_info->af_tuning_params.total_steps;
……………………………………………………………………
	if (set_info->actuator_params.init_setting_size &&
		set_info->actuator_params.init_setting_size
		<= MAX_ACTUATOR_INIT_SET) {
		if (a_ctrl->func_tbl->actuator_init_focus) {
		
			rc = a_ctrl->func_tbl->actuator_init_focus(a_ctrl,
				set_info->actuator_params.init_setting_size,
				init_settings);
……………………………………………………………………
		}
	}
	a_ctrl->initial_code = set_info->af_tuning_params.initial_code;
	if (a_ctrl->func_tbl->actuator_init_step_table)
		rc = a_ctrl->func_tbl->
			actuator_init_step_table(a_ctrl, set_info);
	CDBG("Exit\n");

	return rc;
}

init中主要的就是actuator_init_focus和actuator_init_step_table两个函数,其中actuator_init_focus里面就是基本的i2c写操作,将驱动中的文件init setting下发给sensor,在这里不做分解

static int32_t msm_actuator_init_step_table(struct msm_actuator_ctrl_t *a_ctrl,
	struct msm_actuator_set_info_t *set_info)
{
	………………………………………………
	for (; data_size > 0; data_size--)
		max_code_size *= 2; //获取最大的DAC值,根据driver ic的位数来确定,一般都是2^10 = 1024

	a_ctrl->max_code_size = max_code_size;
………………………………………………
	/* Fill step position table */  // 这个step pos table 很重要,在整个对焦过程中都会用到
	a_ctrl->step_position_table =
		kmalloc(sizeof(uint16_t) *
		(set_info->af_tuning_params.total_steps + 1), GFP_KERNEL);

	if (a_ctrl->step_position_table == NULL)
		return -ENOMEM;

	cur_code = set_info->af_tuning_params.initial_code;
	a_ctrl->step_position_table[step_index++] = cur_code;
	for (region_index = 0;
		region_index < a_ctrl->region_size;
		region_index++) {
		code_per_step =
			a_ctrl->region_params[region_index].code_per_step;
		qvalue =
			a_ctrl->region_params[region_index].qvalue;
		step_boundary =
			a_ctrl->region_params[region_index].
			step_bound[MOVE_NEAR];
		if (step_boundary >
			set_info->af_tuning_params.total_steps) {
			pr_err("invalid step_boundary = %d, max_val = %d",
				step_boundary,
				set_info->af_tuning_params.total_steps);
			kfree(a_ctrl->step_position_table);
			a_ctrl->step_position_table = NULL;
			return -EINVAL;
		}
		for (; step_index <= step_boundary;
			step_index++) {
			if (qvalue > 1 && qvalue <= MAX_QVALUE)
				cur_code = step_index * code_per_step / qvalue;  //有otp的时候需要进行转换
			else
				cur_code = step_index * code_per_step;   //没有otp时候走这个
			cur_code += set_info->af_tuning_params.initial_code;
			if (cur_code < max_code_size)
				a_ctrl->step_position_table[step_index] =
					cur_code;   //幅值table
			else {
				for (; step_index <
					set_info->af_tuning_params.total_steps;
					step_index++)
					a_ctrl->
						step_position_table[
						step_index] =
						max_code_size;
			}
			CDBG("step_position_table[%d] = %d\n", step_index,
				a_ctrl->step_position_table[step_index]);
		}
	}
	CDBG("Exit\n");
	return 0;
}

最终初始化之后的table的排列如下,该table 覆盖远焦(init_code)到近焦(init_code+total_step)整个对焦过程,所以如果远焦模糊,需要降低init_code的值,如果近焦对不清,需要增大init_code+total_step的值,即需要扩充整个table的size
在这里插入图片描述

  • otp代码分析如下
    常用的otp会烧录远焦DAC(inf_dac)和近焦DAC(mac_dac),目前就基于烧录这两个值接着学习
    在计算的时候总共有两个函数,
    eeprom_af_add_margin,扩充range
  dac_range = afcalib_data->macro_dac - afcalib_data->infinity_dac;  //otp 中读出来的range
  afcalib_data->infinity_dac +=
              afcalib_data->infinity_margin * (float)dac_range;  //一般infinity_margin是负数,算出最终的infinity_dac比读出来的小
  afcalib_data->macro_dac +=
              afcalib_data->macro_margin * (float)dac_range;//macro_margin 是正数,计算出来的macro_dac 比读出来的大

eeprom_autofocus_calibration 校准af

//效果参数中的total_steps
  total_steps = af_driver_tune->region_params[af_driver_tune->region_size - 1].
      step_bound[0] - af_driver_tune->region_params[0].step_bound[1];
//otp中的远焦和近焦值
  macro_dac = ectrl->eeprom_data.afc.macro_dac;
  infinity_dac = ectrl->eeprom_data.afc.infinity_dac;
  //用于转换,有otp的时候是128,没有otp的时候是1
  qvalue = af_driver_tune->region_params[0].qvalue;

//计算step,没有otp的时候从效果参数中获取,有otp的时候计算如下
  if(qvalue >= 1 && qvalue <= 4096) {
    code_per_step =
     (macro_dac - infinity_dac) / (float)total_steps * qvalue;
    af_driver_tune->region_params[0].code_per_step = code_per_step;
  }

  /* adjust af_driver_ptr */
  //otp中的远焦值替换效果参数中的远焦值,此时的远焦值是经过margin之后的。
  af_driver_tune->initial_code = ectrl->eeprom_data.afc.infinity_dac;

以上initial_code,code_per_step,qvalue和total step值都有了,然后会更新kernel中的pos table
需要注意的是:total step是从效果参数里面获取的,otp不会改变此值,pos table数组的长度不变
只不过把计算方案替换了,新的计算方式是:

//step_index的范围是从0-tatal_steps
pos_table[step_index] = step_index * code_per_step / qvalue + initial_code;

此时根据otp里面的值重新映射了pos table,在后续对焦中获取此表的index值对应的DAC值,然后下发给driver ic
输出对应的电流,驱动vcm移动。

你可能感兴趣的:(Camera)