我是靠谱客的博主 忧心季节,最近开发中收集的这篇文章主要介绍展锐平台的camera sensor驱动代码设计解析(3)Camera驱动的基本配置及文件路径说明驱动.c文件的配置解析总结,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

展锐平台的camera sensor驱动代码设计解析(1)
展锐平台的camera sensor驱动代码设计解析(2)
展锐平台的camera sensor驱动代码设计解析(3)

Camera驱动的基本配置及文件路径说明

  1. 驱动的配置在路径:devicesprdplatformboardcamerasensor_config.xml
  2. 驱动代码的路径在:vendorsprdmoduleslibcamerasensorsensor_drvclassic下,里面有各个sensor厂商的驱动,比如Galaxycore,Superpix,Samsung等。

驱动.c文件的配置解析

在打开camera调用库的时候会调用到如下函数

void *sensor_ic_open_lib(void)
{
	return &g_ov8856_mipi_raw_info;
}

对于.c中的函数接口,里面的所有函数都是如下结构体函数指针对应的函数接口

/*==============================================================================
 * Description:
 * all ioctl functoins
 * you can add functions reference SENSOR_IOCTL_FUNC_TAB_T from sensor_drv_u.h
 *
 * add ioctl functions like this:
 * .power = ov8856_power_on,
 *============================================================================*/
static struct sensor_ic_ops s_ov8856_ops_tab = {
    .create_handle = ov8856_drv_handle_create,
    .delete_handle = ov8856_drv_handle_delete,
    /*get privage data*/
    .get_data = ov8856_drv_get_private_data,
    /*common interface*/
	.power = ov8856_drv_power_on,
	.identify = ov8856_drv_identify,
	.ex_write_exp = ov8856_drv_write_exposure,
	.write_gain_value = ov8856_drv_write_gain_value,
	
#if defined(CONFIG_DUAL_MODULE)
	.read_aec_info = ov8856_drv_read_aec_info,
#endif

    .ext_ops = {
        [SENSOR_IOCTL_BEFORE_SNAPSHOT].ops = ov8856_drv_before_snapshot,
        [SENSOR_IOCTL_STREAM_ON].ops = ov8856_drv_stream_on,
        [SENSOR_IOCTL_STREAM_OFF].ops = ov8856_drv_stream_off,
        /* expand interface,if you want to add your sub cmd ,
         *  you can add it in enum {@SENSOR_IOCTL_VAL_TYPE}
         */
        [SENSOR_IOCTL_ACCESS_VAL].ops = ov8856_drv_access_val,
		[SENSOR_IOCTL_CONTRAST].ops = ov8856_drv_set_saturation,
    }
};

ov8856_drv_handle_create

static cmr_int ov8856_drv_handle_create(struct sensor_ic_drv_init_para *init_param, cmr_handle* sns_ic_drv_handle) 
{
    cmr_int ret = SENSOR_SUCCESS;
    struct sensor_ic_drv_cxt * sns_drv_cxt = NULL;
    void *pri_data = NULL;

    ret = sensor_ic_drv_create(init_param,sns_ic_drv_handle);
    sns_drv_cxt = *sns_ic_drv_handle;

    sns_drv_cxt->sensor_ev_info.preview_shutter = PREVIEW_FRAME_LENGTH - FRAME_OFFSET;
    sns_drv_cxt->sensor_ev_info.preview_gain = SENSOR_BASE_GAIN;
    sns_drv_cxt->sensor_ev_info.preview_framelength = PREVIEW_FRAME_LENGTH;

    sns_drv_cxt->frame_length_def = PREVIEW_FRAME_LENGTH;
	
	ov8856_drv_write_frame_length(sns_drv_cxt, &ov8856_aec_info, sns_drv_cxt->sensor_ev_info.preview_framelength);
	ov8856_drv_write_gain(sns_drv_cxt, &ov8856_aec_info, sns_drv_cxt->sensor_ev_info.preview_gain);
	ov8856_drv_write_shutter(sns_drv_cxt, &ov8856_aec_info, sns_drv_cxt->sensor_ev_info.preview_shutter);

    sensor_ic_set_match_module_info(sns_drv_cxt, ARRAY_SIZE(s_ov8856_module_info_tab), s_ov8856_module_info_tab);
    sensor_ic_set_match_resolution_info(sns_drv_cxt, ARRAY_SIZE(s_ov8856_resolution_tab_raw), s_ov8856_resolution_tab_raw);
    sensor_ic_set_match_trim_info(sns_drv_cxt, ARRAY_SIZE(s_ov8856_resolution_trim_tab), s_ov8856_resolution_trim_tab);
    sensor_ic_set_match_static_info(sns_drv_cxt, ARRAY_SIZE(s_ov8856_static_info), s_ov8856_static_info);
    sensor_ic_set_match_fps_info(sns_drv_cxt, ARRAY_SIZE(s_ov8856_mode_fps_info), s_ov8856_mode_fps_info);

    /*init exif info,this will be deleted in the future*/
    ov8856_drv_init_fps_info(sns_drv_cxt);
	ov8856_drv_init_exif_info(sns_drv_cxt, &sns_drv_cxt->exif_ptr);
	
    /*add private here*/
    return ret;
}

drv_handle_create这个函数会在最开始的时候调用到,比如开机进行identify的时候就会调用到,对整个驱动进行初始化配置,分配一个驱动所需要的包括各种结构体的内存空间等。

ov8856_drv_handle_delete

static cmr_int ov8856_drv_handle_delete(cmr_handle handle, void *param) 
{
    cmr_int ret = SENSOR_SUCCESS;

    SENSOR_IC_CHECK_HANDLE(handle);
    struct sensor_ic_drv_cxt * sns_drv_cxt = (struct sensor_ic_drv_cxt *)handle;

    ret = sensor_ic_drv_delete(handle,param);
    return ret;
}

drv_handle_delete函数主要是在退出camera的时候,将前面drv_handle_create分配的内存等进行销毁释放。

上电和下电时序

/*==============================================================================
 * Description:
 * sensor power on
 * please modify this function acording your spec
 *============================================================================*/
static cmr_int ov8856_drv_power_on(cmr_handle handle, cmr_uint power_on)
{
    SENSOR_IC_CHECK_HANDLE(handle);
    struct sensor_ic_drv_cxt * sns_drv_cxt = (struct sensor_ic_drv_cxt *)handle;
    struct module_cfg_info *module_info = sns_drv_cxt->module_info;

    SENSOR_AVDD_VAL_E dvdd_val = module_info->dvdd_val;
    SENSOR_AVDD_VAL_E avdd_val = module_info->avdd_val;
    SENSOR_AVDD_VAL_E iovdd_val = module_info->iovdd_val;
    BOOLEAN power_down = g_ov8856_mipi_raw_info.power_down_level;
    BOOLEAN reset_level = g_ov8856_mipi_raw_info.reset_pulse_level;	
	
    if (SENSOR_TRUE == power_on) 
	{
        hw_sensor_power_down(sns_drv_cxt->hw_handle, power_down);
        hw_sensor_set_reset_level(sns_drv_cxt->hw_handle, reset_level);
        hw_sensor_set_mclk(sns_drv_cxt->hw_handle, SENSOR_DISABLE_MCLK);
        hw_sensor_set_avdd_val(sns_drv_cxt->hw_handle, SENSOR_AVDD_CLOSED);
        hw_sensor_set_dvdd_val(sns_drv_cxt->hw_handle, SENSOR_AVDD_CLOSED);
        hw_sensor_set_iovdd_val(sns_drv_cxt->hw_handle, SENSOR_AVDD_CLOSED);
		
        usleep(10 * 1000);
		hw_sensor_set_iovdd_val(sns_drv_cxt->hw_handle, iovdd_val);
        hw_sensor_set_avdd_val(sns_drv_cxt->hw_handle, avdd_val);
        hw_sensor_set_dvdd_val(sns_drv_cxt->hw_handle, dvdd_val);

        usleep(10 * 1000);
		hw_sensor_set_mclk(sns_drv_cxt->hw_handle, EX_MCLK);
        hw_sensor_power_down(sns_drv_cxt->hw_handle, !power_down);
        hw_sensor_set_reset_level(sns_drv_cxt->hw_handle, !reset_level);
        usleep(5 * 1000);
        
    } else 
	{
        //usleep(500);
        //hw_sensor_set_reset_level(sns_drv_cxt->hw_handle, reset_level);
        //hw_sensor_power_down(sns_drv_cxt->hw_handle, power_down);
        //hw_sensor_set_mclk(sns_drv_cxt->hw_handle, SENSOR_DISABLE_MCLK);
		//usleep(200);
        //hw_sensor_set_avdd_val(sns_drv_cxt->hw_handle, SENSOR_AVDD_CLOSED);
        //hw_sensor_set_dvdd_val(sns_drv_cxt->hw_handle, SENSOR_AVDD_CLOSED);
        //hw_sensor_set_iovdd_val(sns_drv_cxt->hw_handle, SENSOR_AVDD_CLOSED);
    }
	
    SENSOR_LOGI("mydebug(1:on, 0:off): %lu", power_on);
    return SENSOR_SUCCESS;
}

drv_power_on是上电和下电时序,这个应该要使用示波器测量让其跟datasheet的上下电时序对应。Power on函数里面首先是对三路电源的控制和对power down及reset的初始值获取,另外两个if语句当为true的时候是上电,当为false的时候是下电,其中里面对上电下电的操作一定要严格按照sensor spec里面的时序图进行操作。

identify

/*==============================================================================
 * Description:
 * identify sensor id
 * please modify this function acording your spec
 *============================================================================*/
static cmr_int ov8856_drv_identify(cmr_handle handle, cmr_uint param)
{
	cmr_u16 pid_value = 0x00;
	cmr_u16 ver_value = 0x00;
	cmr_int ret_value = SENSOR_FAIL;
	
    SENSOR_IC_CHECK_HANDLE(handle);
    struct sensor_ic_drv_cxt * sns_drv_cxt = (struct sensor_ic_drv_cxt *)handle;
  
	SENSOR_LOGI("mipi raw identify");

	pid_value = hw_sensor_read_reg(sns_drv_cxt->hw_handle, ov8856_PID_ADDR);

	if (ov8856_PID_VALUE == pid_value) {
		ver_value = hw_sensor_read_reg(sns_drv_cxt->hw_handle, ov8856_VER_ADDR);
		SENSOR_LOGI("Identify: pid_value = %x, ver_value = %x", pid_value, ver_value);
		if (ov8856_VER_VALUE == ver_value) {
			SENSOR_LOGI("this is ov8856 sensor");
			ret_value = SENSOR_SUCCESS;
		} else {
			SENSOR_LOGE("sensor identify fail, pid_value = %x, ver_value = %x", pid_value, ver_value);
		}
	} else {
		SENSOR_LOGE("sensor identify fail, pid_value = %x, ver_value = %x", pid_value, ver_value);
	}

	return ret_value;
}

drv_identify函数主要检查sensor的pid,vid,间接也可以检查一下sensor的上电和mclk给时钟等,这个函数在开机和每一次打开camera的时候都会调用到,很多时候log通过这个函数了解sensor的情况。

/*==============================================================================
 * Description:
 * cfg otp setting
 * please modify this function acording your spec
 *============================================================================*/
static cmr_int ov8856_drv_access_val(cmr_handle handle, cmr_uint param)
{
	cmr_int ret = SENSOR_FAIL;
    SENSOR_VAL_T *param_ptr = (SENSOR_VAL_T *)param;
    
	SENSOR_IC_CHECK_HANDLE(handle);
	SENSOR_IC_CHECK_PTR(param_ptr);
    struct sensor_ic_drv_cxt * sns_drv_cxt = (struct sensor_ic_drv_cxt *)handle;

	SENSOR_LOGI("sensor ov8856: param_ptr->type=%x", param_ptr->type);
	
	switch(param_ptr->type)
	{
		case SENSOR_VAL_TYPE_GET_STATIC_INFO:
			ret = ov8856_drv_get_static_info(handle, param_ptr->pval);
			break;
		case SENSOR_VAL_TYPE_GET_FPS_INFO:
			ret = ov8856_drv_get_fps_info(handle, param_ptr->pval);
			break;
		case SENSOR_VAL_TYPE_SET_SENSOR_CLOSE_FLAG:
			ret = sns_drv_cxt->is_sensor_close = 1;
			break;
		case SENSOR_VAL_TYPE_GET_PDAF_INFO:
			//ret = ov8856_drv_get_pdaf_info(handle, param_ptr->pval);
			break;
	#ifdef FEATURE_OTP
		case SENSOR_VAL_TYPE_READ_OTP;
			ret = ov8856_identify_otp(handle,param_ptr);
			break;
	#endif
	    case SENSOR_VAL_TYPE_READ_OTP:
	        //property_get("persist.vendor.bypass.sensor.otp", value, "0");
	        //if (atoi(value) == 0) {
	            //if (ov8856_otp_module_vendor_id == 0 && sns_drv_cxt->sensor_id == 1)
	                ov8856_read_otp(handle, param_ptr);
	        //}
	        break;
		default:
			break;
    }

    return ret;
}

每一个驱动中都有一个drv_access_val函数,这个函数主要是oem层对驱动中一些特性相关函数的调用,包括一些需要私自添加的接口,可以在这个函数里面实现,由oem调用到上层去,如sensor的otp驱动,可以在如下函数中添加case语句SENSOR_VAL_TYPE_READ_OTP,来实现sensor自带otp的校准,其他的接口添加也可以参考。

总结

camera驱动的讲解基本完成,在开发或者bring up camera驱动的时候,需要细致的驱动进行检查,并完成每一个配置和函数。所有这些都是需要sensor原厂和驱动工程师一起协同完成。任何一个配置不正确都可能导致很多问题,比如bps不正确可能导致接收数据错误,linetime不对可能导致水波纹等。对于上电时序,最好通过严格的示波器检查,VB也最好在一帧的占比为不超过3%,mipi的时序也是需要通过波形测试确认等。

最后

以上就是忧心季节为你收集整理的展锐平台的camera sensor驱动代码设计解析(3)Camera驱动的基本配置及文件路径说明驱动.c文件的配置解析总结的全部内容,希望文章能够帮你解决展锐平台的camera sensor驱动代码设计解析(3)Camera驱动的基本配置及文件路径说明驱动.c文件的配置解析总结所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(56)

评论列表共有 0 条评论

立即
投稿
返回
顶部