概述
展锐平台的camera sensor驱动代码设计解析(1)
展锐平台的camera sensor驱动代码设计解析(2)
展锐平台的camera sensor驱动代码设计解析(3)
Camera驱动的基本配置及文件路径说明
- 驱动的配置在路径:devicesprdplatformboardcamerasensor_config.xml
- 驱动代码的路径在: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文件的配置解析总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复