Android Camera驱动分析

您所在的位置:网站首页 驱动分析是什么 Android Camera驱动分析

Android Camera驱动分析

2024-04-07 13:46| 来源: 网络整理| 查看: 265

文章目录 一、Camera的硬件接口二、代码路径三、Camera代码分析1、硬件接口设置2、Camera设备驱动3、模组驱动代码

一、Camera的硬件接口 引脚名称及作用VCAMA就是AVDD,模拟供电,主要给感光区和ADC部分供电,2.8VVCAMD就是DVDD,数字供电,主要给 ISP 供电,1.2VVCAM_IO就是VDDIO,数字IO供电,主要给 I2C 部分供电,1.8VVCAM_AF自动对焦马达供电RESET复位引脚PDN工作状态控制引脚CMMCLK时钟引脚SCL、SDAI2C接口RCN、RCPMIPI时钟接口RDN0、RDP0MIPI数据接口通道0

注:MIPI数据接口可能有多通道。

二、代码路径 描述路径文件系统设置device\top\top6737t_36_a_m0kernel-3.18\arch\arm\configsProjectConfig.mkuser版本和userdebug版本对应:top6737t_36_a_m0_defconfigdebug版本对应:top6737t_36_a_m0_debug_defconfig接口设置kernel-3.18\arch\arm\boot\dtstop6737t_36_a_m0.dtscust_i2c.dtsiKernel代码kernel-3.18\drivers\misc\mediatek\imgsensorHAL代码vendor\mediatek\proprietary\custom\mt6735\hal\D2\imgsensor镜头、闪光灯等相关代码kernel-3.18\drivers\misc\mediatek\lenskernel-3.18\drivers\misc\mediatek\flashlightvendor\mediatek\proprietary\custom\mt6735\hal\D2\lensvendor\mediatek\proprietary\custom\mt6735\hal\D2\flashlight 三、Camera代码分析 1、硬件接口设置

​ 在dts文件中,对照硬件接口,修改对应GPIO设置:

// top6737t_36_a_m0.dts /* CAMERA GPIO standardization */ &pio { camera_pins_cam0_rst0: cam0@0 { pins_cmd_dat { pins = ;/*GPIO_CAMERA_CMRST_PIN*/ slew-rate = ; /*direction 0:in, 1:out*/ output-low;/*direction out used only. output_low or high*/ }; }; camera_pins_cam0_rst1: cam0@1 { pins_cmd_dat { pins = ;/*GPIO_CAMERA_CMRST_PIN*/ slew-rate = ; output-high; }; }; camera_pins_cam0_pnd0: cam0@2 { pins_cmd_dat { pins = ;/*GPIO_CAMERA_CMPDN_PIN*/ slew-rate = ; output-low; }; }; camera_pins_cam0_pnd1: cam0@3 { pins_cmd_dat { pins = ;/*GPIO_CAMERA_CMPDN_PIN*/ slew-rate = ; output-high; }; }; camera_pins_cam1_rst0: cam1@0 { pins_cmd_dat { pins = ;/*GPIO_CAMERA_CMRST1_PIN*/ slew-rate = ; /*direction 0:in, 1:out*/ output-low;/*direction out used only. output_low or high*/ }; }; camera_pins_cam1_rst1: cam1@1 { pins_cmd_dat { pins = ;/*GPIO_CAMERA_CMRST1_PIN*/ slew-rate = ; output-high; }; }; camera_pins_cam1_pnd0: cam1@2 { pins_cmd_dat { pins = ;/*GPIO_CAMERA_CMPDN1_PIN*/ slew-rate = ; output-low; }; }; camera_pins_cam1_pnd1: cam1@3 { pins_cmd_dat { pins = ;/*GPIO_CAMERA_CMPDN1_PIN*/ slew-rate = ; output-high; }; }; camera_pins_cam_ldo0_0: cam@0 { pins_cmd_dat { pins = ; slew-rate = ; output-low; }; }; camera_pins_cam_ldo0_1: cam@1 { pins_cmd_dat { pins = ; slew-rate = ; output-high; }; }; camera_pins_default: camdefault { }; }; &kd_camera_hw1 { pinctrl-names = "default", "cam0_rst0", "cam0_rst1", "cam0_pnd0", "cam0_pnd1", "cam1_rst0", "cam1_rst1", "cam1_pnd0", "cam1_pnd1", "cam_ldo0_0", "cam_ldo0_1"; pinctrl-0 = ; pinctrl-1 = ; pinctrl-2 = ; pinctrl-3 = ; pinctrl-4 = ; pinctrl-5 = ; pinctrl-6 = ; pinctrl-7 = ; pinctrl-8 = ; pinctrl-9 = ; pinctrl-10 = ; status = "okay"; }; /* CAMERA GPIO end */

还有对应的I2C设置:

/* cust_i2c.dtsi */ &i2c0 { camera_main@10 { compatible = "mediatek,camera_main"; reg = ; }; camera_main_af@0c { compatible = "mediatek,camera_main_af"; reg = ; }; camera_sub@3c { compatible = "mediatek,camera_sub"; reg = ; }; }; 2、Camera设备驱动

​ 文件kd_sensorlist.c是摄像头作为字符型设备驱动的入口,可以通过分析本文件简单捋一下摄像头驱动的代码结构。

​ 首先,是一个I2C设备的驱动:

//kd_sensorlist.c #ifdef CONFIG_OF static const struct of_device_id CAMERA_HW_i2c_of_ids[] = { { .compatible = "mediatek,camera_main", }, //在文件cust_i2c.dtsi中找对应的描述,设置用哪组I2C,以及地址 {} }; #endif //实现I2C设备驱动的几个标准接口 struct i2c_driver CAMERA_HW_i2c_driver = { .probe = CAMERA_HW_i2c_probe, .remove = CAMERA_HW_i2c_remove, .driver = { .name = CAMERA_HW_DRVNAME1, .owner = THIS_MODULE, #ifdef CONFIG_OF .of_match_table = CAMERA_HW_i2c_of_ids, #endif }, .id_table = CAMERA_HW_i2c_id, };

在I2C的设备驱动probe函数中,注册摄像头模组的字符型设备:

//kd_sensorlist.c static int CAMERA_HW_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { ...... //注册摄像头模组的字符型设备 i4RetValue = RegisterCAMERA_HWCharDrv(); ...... PK_DBG("[CAMERA_HW] Attached!!\n"); return 0; }

在注册摄像头字符型设备函数RegisterCAMERA_HWCharDrv();中,可以看到这个字符型设备的操作函数:

//kd_sensorlist.c static inline int RegisterCAMERA_HWCharDrv(void) { ...... //操作函数 cdev_init(g_pCAMERA_HW_CharDrv, &g_stCAMERA_HW_fops); ...... sensor_device = device_create(sensor_class, NULL, g_CAMERA_HWdevno, NULL, CAMERA_HW_DRVNAME1); return 0; } //操作函数结构体 static const struct file_operations g_stCAMERA_HW_fops = { .owner = THIS_MODULE, .open = CAMERA_HW_Open, .release = CAMERA_HW_Release, .unlocked_ioctl = CAMERA_HW_Ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = CAMERA_HW_Ioctl_Compat, #endif };

​ 然后,我们看下摄像头字符型设备操作函数CAMERA_HW_Ioctl中,具体的一些操作:

//kd_sensorlist.c static long CAMERA_HW_Ioctl(struct file *a_pstFile,unsigned int a_u4Command,unsigned long a_u4Param) { ...... switch (a_u4Command) { //找到控制摄像头的驱动函数,以便获取摄像头的SensorOpen、SensorGetInfo等接口; case KDIMGSENSORIOC_X_SET_DRIVER: i4RetValue = kdSetDriver((unsigned int *)pBuff); break; //调用接口SensorOpen,给摄像头上电,通过I2C读取摄像头ID,以及设置寄存器相关参数; case KDIMGSENSORIOC_T_OPEN: i4RetValue = adopt_CAMERA_HW_Open(); break; //调用接口SensorGetInfo,获取摄像头MIPI、CLOCK等参数; case KDIMGSENSORIOC_X_GETINFO: i4RetValue = adopt_CAMERA_HW_GetInfo(pBuff); break; //调用接口SensorGetResolution,获取摄像头分辨率等参数; case KDIMGSENSORIOC_X_GETRESOLUTION2: i4RetValue = adopt_CAMERA_HW_GetResolution(pBuff); break; case KDIMGSENSORIOC_X_GETINFO2: i4RetValue = adopt_CAMERA_HW_GetInfo2(pBuff); break; //调用接口SensorFeatureControl,获取或设置摄像头增益、进入不同模式等操作; case KDIMGSENSORIOC_X_FEATURECONCTROL: i4RetValue = adopt_CAMERA_HW_FeatureControl(pBuff); break; //调用接口SensorControl,控制摄像头预览、拍照等操作; case KDIMGSENSORIOC_X_CONTROL: i4RetValue = adopt_CAMERA_HW_Control(pBuff); break; //调用接口SensorClose,关闭摄像头; case KDIMGSENSORIOC_T_CLOSE: i4RetValue = adopt_CAMERA_HW_Close(); break; //通过读ID方式检查摄像头是否存在; case KDIMGSENSORIOC_T_CHECK_IS_ALIVE: i4RetValue = adopt_CAMERA_HW_CheckIsAlive(); break; ...... default: PK_DBG("No such command\n"); i4RetValue = -EPERM; break; } ...... }

查找并加载摄像头驱动功能函数的过程如下:

//kd_sensorlist.c int kdSetDriver(unsigned int *pDrvIndex) { ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT *pSensorList = NULL; u32 drvIdx[KDIMGSENSOR_MAX_INVOKE_DRIVERS] = {0, 0}; u32 i; //KDIMGSENSOR_INVOKE_DRIVER_0和KDIMGSENSOR_INVOKE_DRIVER_1表示摄像头位置,目前支持两个位置:前摄和后摄 //传进来的int型参数,高16位表示main还是sub,低16位表示摄像头Index PK_INF("pDrvIndex:0x%08x/0x%08x\n", pDrvIndex[KDIMGSENSOR_INVOKE_DRIVER_0], pDrvIndex[KDIMGSENSOR_INVOKE_DRIVER_1]); gDrvIndex = pDrvIndex[KDIMGSENSOR_INVOKE_DRIVER_0]; //获取摄像头列表 if (0 != kdGetSensorInitFuncList(&pSensorList)) { PK_ERR("ERROR:kdGetSensorInitFuncList()\n"); return -EIO; } //分别查找前摄和后摄驱动 for (i = KDIMGSENSOR_INVOKE_DRIVER_0; i continue; } //根据摄像头位置,确定使用那一组I2C if (DUAL_CAMERA_SUB_SENSOR == g_invokeSocketIdx[i]) { spin_lock(&kdsensor_drv_lock); gI2CBusNum = SUPPORT_I2C_BUS_NUM2; spin_unlock(&kdsensor_drv_lock); /* PK_XLOG_INFO("kdSetDriver: switch I2C BUS2\n"); */ } else { spin_lock(&kdsensor_drv_lock); gI2CBusNum = SUPPORT_I2C_BUS_NUM1; spin_unlock(&kdsensor_drv_lock); /* PK_XLOG_INFO("kdSetDriver: switch I2C BUS1\n"); */ } PK_INF("g_invokeSocketIdx[%d]=%d,drvIdx[%d]=%d\n", i, g_invokeSocketIdx[i], i, drvIdx[i]); //Index不能超过定义的最大指:MAX_NUM_OF_SUPPORT_SENSOR if (MAX_NUM_OF_SUPPORT_SENSOR > drvIdx[i]) { //利用SensorInit函数将摄像头的具体函数放到g_pInvokeSensorFunc中 if (NULL == pSensorList[drvIdx[i]].SensorInit) { PK_ERR("ERROR:kdSetDriver()\n"); return -EIO; } pSensorList[drvIdx[i]].SensorInit(&g_pInvokeSensorFunc[i]); if (NULL == g_pInvokeSensorFunc[i]) { PK_ERR("ERROR:NULL g_pSensorFunc[%d]\n", i); return -EIO; } spin_lock(&kdsensor_drv_lock); //设置标识,支持这颗摄像头 g_bEnableDriver[i] = TRUE; spin_unlock(&kdsensor_drv_lock); //把摄像头的名字copy到g_invokeSensorNameStr memcpy((char *)g_invokeSensorNameStr[i], (char *)pSensorList[drvIdx[i]].drvname, sizeof(pSensorList[drvIdx[i]].drvname)); PK_INF("[%d][%d][%d][%s]\n", i, g_bEnableDriver[i], g_invokeSocketIdx[i], g_invokeSensorNameStr[i]); } } return 0; }

打开摄像头的操作,包括上电、读ID等操作,是在kd_MultiSensorOpen函数中实现的,具体如下:

//kd_sensorlist.c MUINT32 kd_MultiSensorOpen(void) { ...... for (i = (KDIMGSENSOR_MAX_INVOKE_DRIVERS - 1); i >= KDIMGSENSOR_INVOKE_DRIVER_0; i--) { if (g_bEnableDriver[i] && g_pInvokeSensorFunc[i]) { if (0 != (g_CurrentSensorIdx & g_invokeSocketIdx[i])) { #ifndef CONFIG_FPGA_EARLY_PORTING //给摄像头上电,kdCISModulePowerOn函数在tb_kd_camera_hw.c文件中实现; ret = kdCISModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM)g_invokeSocketIdx[i], (char *)g_invokeSensorNameStr[i], true,CAMERA_HW_DRVNAME1); #endif if (ERROR_NONE != ret) { PK_ERR("[%s]", __func__); return ret; } //调用这颗摄像头的open函数,里边有读ID等操作 ret = g_pInvokeSensorFunc[i]->SensorOpen(); if (ERROR_NONE != ret) { #ifndef CONFIG_FPGA_EARLY_PORTING //如果open失败,还要下电; kdCISModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM)g_invokeSocketIdx[i], (char *)g_invokeSensorNameStr[i], false, CAMERA_HW_DRVNAME1); #endif PK_ERR("SensorOpen"); return ret; } } } } ...... KD_MULTI_FUNCTION_EXIT(); return ERROR_NONE; }

​ 函数kd_MultiSensorOpen中调用的给摄像头上下电的函数,是在文件tb_kd_camera_hw.c中实现。不同模组,打开和关闭时,硬件接口的操作上会有差异,比如:先给哪路上电或下电?复位操作对应高电平还是低电平?上电后需要多长时间模组才Ready?具体的操作时序,可以参考模组的规格书。下面的代码就是上电和下电的具体操作:

// kd_camera_hw.c int kdCISModulePowerOn(CAMERA_DUAL_CAMERA_SENSOR_ENUM SensorIdx, char *currSensorName, bool On, char *mode_name) { ...... //上电操作 if (On) { ...... //判断要操作的模组,SensorIdx用来判断前摄还是后摄,currSensorName用来判断模组名字 if (SensorIdx == DUAL_CAMERA_MAIN_SENSOR && currSensorName && (0 == strcmp(SENSOR_DRVNAME_GC030A_MIPI_RAW, currSensorName))) { //第1步:使能CMMCLK ISP_MCLK1_EN(1); // 第2步:操作PDN脚和RESET脚,为芯片正常工作做准备; if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMPDN]) { mtkcam_gpio_set(pinSetIdx, CAMPDN,pinSet[pinSetIdx][IDX_PS_CMPDN + IDX_PS_OFF]); } if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMRST]) { mtkcam_gpio_set(pinSetIdx, CAMRST,pinSet[pinSetIdx][IDX_PS_CMRST + IDX_PS_OFF]); } mdelay(5); //第3步:分别给VDDIO、AVDD、DVDD上电,如果自动对焦马达需要供电,也需要给VCAM_AF上电 if (TRUE != _hwPowerOnCnt(VCAMIO, VOL_1800, mode_name)) { PK_DBG("[CAMERA SENSOR] Fail to enable IO power (VCAM_IO),power id = %d\n",VCAMIO); goto _kdCISModulePowerOn_exit_; } mdelay(1); if (TRUE != _hwPowerOnCnt(VCAMA, VOL_2800, mode_name)) { PK_DBG("[CAMERA SENSOR] Fail to enable analog power (VCAM_A),power id = %d\n",VCAMA); goto _kdCISModulePowerOn_exit_; } mdelay(5); if (TRUE != _hwPowerOnCnt(VCAMD, VOL_1200, mode_name)) { PK_DBG ("[CAMERA SENSOR] Fail to enable digital power (VCAM_D),power id = %d\n", VCAMD); goto _kdCISModulePowerOn_exit_; } if (TRUE != _hwPowerOnCnt(VCAMAF, VOL_2800, mode_name)) { PK_DBG ("[CAMERA SENSOR] Fail to enable analog power (VCAM_AF),power id = %d\n", VCAMAF); goto _kdCISModulePowerOn_exit_; } //第4步:使模组进入Nomal模式 if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMPDN]) { mtkcam_gpio_set(pinSetIdx, CAMPDN,pinSet[pinSetIdx][IDX_PS_CMPDN + IDX_PS_ON]); } if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMRST]) { mtkcam_gpio_set(pinSetIdx, CAMRST,pinSet[pinSetIdx][IDX_PS_CMRST + IDX_PS_ON]); } mdelay(5); } ...... } else //下电操作 { ...... //判断要操作的模组,SensorIdx用来判断前摄还是后摄,currSensorName用来判断模组名字 if (SensorIdx == DUAL_CAMERA_MAIN_SENSOR && currSensorName && (0 == strcmp(SENSOR_DRVNAME_GC030A_MIPI_RAW, currSensorName))) { //第1步:操作PDN脚和RESET脚,停止模组工作 if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMPDN]) { mtkcam_gpio_set(pinSetIdx, CAMPDN,pinSet[pinSetIdx][IDX_PS_CMPDN + IDX_PS_OFF]); } if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMRST]) { mtkcam_gpio_set(pinSetIdx, CAMRST,pinSet[pinSetIdx][IDX_PS_CMRST + IDX_PS_OFF]); } //第2步:分别关闭VDDIO、AVDD、DVDD、VCAM_AF的电 if (TRUE != _hwPowerDownCnt(VCAMA, mode_name)) { PK_DBG("[CAMERA SENSOR] Fail to OFF analog power (VCAM_A), power id= (%d)\n",VCAMA); goto _kdCISModulePowerOn_exit_; } if (TRUE != _hwPowerDownCnt(VCAMIO, mode_name)) { PK_DBG("[CAMERA SENSOR] Fail to OFF digital power (VCAM_IO), power id = %d\n",VCAMIO); goto _kdCISModulePowerOn_exit_; } if (TRUE != _hwPowerDownCnt(VCAMD, mode_name)) { PK_DBG("[CAMERA SENSOR] Fail to OFF analog power (VCAMD), power id= (%d)\n",VCAMD); goto _kdCISModulePowerOn_exit_; } if (TRUE != _hwPowerDownCnt(VCAMAF, mode_name)) { PK_DBG("[CAMERA SENSOR] Fail to OFF digital power (VCAMAF), power id = %d\n",VCAMAF); goto _kdCISModulePowerOn_exit_; } mdelay(5); // 第3步:关闭CMMCLK ISP_MCLK1_EN(0); } ...... } ...... return 0; _kdCISModulePowerOn_exit_: return -EIO; }

​ 至此,Kernel中给摄像头上电、打开摄像头、控制摄像头、关闭摄像头等实现,就比较清晰了。

3、模组驱动代码

​ 分析设备驱动代码时,已经知晓在kdSetDriver操作中会根据不同模组找到对应的驱动代码,根据不同的模组有不同的上下电操作。不同模组的不同驱动代码都在下面这个文件中:

//kd_sensorlist.h ...... UINT32 GC030AMIPI_RAW_SensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc); ...... ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR+1] = { ...... #if defined(GC030A_MIPI_RAW) {GC030AMIPI_SENSOR_ID, SENSOR_DRVNAME_GC030A_MIPI_RAW,GC030AMIPI_RAW_SensorInit}, #endif ...... }

不同模组列表kdSensorList,其实是不同的模组以结构体ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT格式进行填充,结构体定义如下:

//kd_imgsensor_define.h typedef struct { MUINT32 SensorId; //模组ID MUINT8 drvname[32];//模组名字 MUINT32(*SensorInit)(PSENSOR_FUNCTION_STRUCT *pfFunc);//模组初始化函数 } ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT, *PACDK_KD_SENSOR_INIT_FUNCTION_STRUCT;

模组的初始化函数是用来获取模组驱动函数接口的,模组驱动函数接口定义在:

//kd_imgsensor_define.h typedef struct { MUINT32(*SensorOpen)(void); MUINT32(*SensorGetInfo)(MSDK_SCENARIO_ID_ENUM ScenarioId, MSDK_SENSOR_INFO_STRUCT *pSensorInfo,MSDK_SENSOR_CONFIG_STRUCT *pSensorConfigData); MUINT32(*SensorGetResolution)(MSDK_SENSOR_RESOLUTION_INFO_STRUCT *pSensorResolution); MUINT32(*SensorFeatureControl)(MSDK_SENSOR_FEATURE_ENUM FeatureId, MUINT8 *pFeaturePara, MUINT32 *pFeatureParaLen); MUINT32(*SensorControl)(MSDK_SCENARIO_ID_ENUM ScenarioId, MSDK_SENSOR_EXPOSURE_WINDOW_STRUCT *pImageWindow, MSDK_SENSOR_CONFIG_STRUCT *pSensorConfigData); MUINT32(*SensorClose)(void); #if 1 /* isp suspend resume patch */ MSDK_SCENARIO_ID_ENUM ScenarioId; MSDK_SENSOR_EXPOSURE_WINDOW_STRUCT imageWindow; MSDK_SENSOR_CONFIG_STRUCT sensorConfigData; #endif } SENSOR_FUNCTION_STRUCT, *PSENSOR_FUNCTION_STRUCT;

分析不同模组驱动代码,就是分析不同模组实现SENSOR_FUNCTION_STRUCT的具体函数,比如 gc030a_mipi_raw :

//gc030amipi_Sensor.c static SENSOR_FUNCTION_STRUCT sensor_func = { open, get_info, get_resolution, feature_control, control, close };

首先,看open函数:

//gc030amipi_Sensor.c static kal_uint32 open(void) { ...... while (imgsensor_info.i2c_addr_table[i] != 0xff) { spin_lock(&imgsensor_drv_lock); imgsensor.i2c_write_id = imgsensor_info.i2c_addr_table[i]; spin_unlock(&imgsensor_drv_lock); do { //通过I2C读取模组ID sensor_id = return_sensor_id(); if (sensor_id == imgsensor_info.sensor_id) { LOG_INF("GC030A open i2c write id: 0x%x, sensor id: 0x%x\n", imgsensor.i2c_write_id,sensor_id); break; } LOG_INF("GC030A open Read sensor id fail, write id: 0x%x, id: 0x%x\n", imgsensor.i2c_write_id,sensor_id); retry--; } while(retry > 0); i++; if (sensor_id == imgsensor_info.sensor_id) break; retry = 2; } //ID不匹配则直接退出 if (imgsensor_info.sensor_id != sensor_id) { return ERROR_SENSOR_CONNECT_FAIL; } //通过I2C把摄像头Sensor的寄存器初始化参数写进去,包括镜像、增益、MIPI等基础参数 sensor_init(); ...... return ERROR_NONE; }

open函数中调用的sensor_init函数,是通过I2C写摄像头模组的初始化参数,调试过程中可能会遇到成像镜像等问题,可以通过调试这些参数来修正:

//gc030amipi_Sensor.c static void sensor_init(void) { /*SYS*/ write_cmos_sensor(0xfe, 0x80); write_cmos_sensor(0xfe, 0x80); write_cmos_sensor(0xfe, 0x80); write_cmos_sensor(0xf7, 0x01); write_cmos_sensor(0xf8, 0x05); write_cmos_sensor(0xf9, 0x0f); write_cmos_sensor(0xfa, 0x00); write_cmos_sensor(0xfc, 0x0f); write_cmos_sensor(0xfe, 0x00); /*ANALOG & CISCTL*/ write_cmos_sensor(0x03, 0x01); write_cmos_sensor(0x04, 0xc8); write_cmos_sensor(0x05, 0x03); write_cmos_sensor(0x06, 0x7b); write_cmos_sensor(0x07, 0x00); write_cmos_sensor(0x08, 0x06); write_cmos_sensor(0x0a, 0x00); write_cmos_sensor(0x0c, 0x08); write_cmos_sensor(0x0d, 0x01); write_cmos_sensor(0x0e, 0xe8); write_cmos_sensor(0x0f, 0x02); write_cmos_sensor(0x10, 0x88); write_cmos_sensor(0x12, 0x28);//23 add 20170110 write_cmos_sensor(0x17, MIRROR);//Don't Change Here!!! write_cmos_sensor(0x18, 0x12); write_cmos_sensor(0x19, 0x07); write_cmos_sensor(0x1a, 0x1b); write_cmos_sensor(0x1d, 0x48);//40 travis20160318 write_cmos_sensor(0x1e, 0x50); write_cmos_sensor(0x1f, 0x80); write_cmos_sensor(0x23, 0x01); write_cmos_sensor(0x24, 0xc8); write_cmos_sensor(0x27, 0xaf); write_cmos_sensor(0x28, 0x24); write_cmos_sensor(0x29, 0x1a); write_cmos_sensor(0x2f, 0x14); write_cmos_sensor(0x30, 0x00); write_cmos_sensor(0x31, 0x04); write_cmos_sensor(0x32, 0x08); write_cmos_sensor(0x33, 0x0c); write_cmos_sensor(0x34, 0x0d); write_cmos_sensor(0x35, 0x0e); write_cmos_sensor(0x36, 0x0f); write_cmos_sensor(0x72, 0x98); write_cmos_sensor(0x73, 0x9a); write_cmos_sensor(0x74, 0x47); write_cmos_sensor(0x76, 0x82); write_cmos_sensor(0x7a, 0xcb); write_cmos_sensor(0xc2, 0x0c); write_cmos_sensor(0xce, 0x03); write_cmos_sensor(0xcf, 0x48); write_cmos_sensor(0xd0, 0x10); write_cmos_sensor(0xdc, 0x75); write_cmos_sensor(0xeb, 0x78); /*ISP*/ write_cmos_sensor(0x90, 0x01); write_cmos_sensor(0x92, STARTY);//Don't Change Here!!! write_cmos_sensor(0x94, STARTX);//Don't Change Here!!! write_cmos_sensor(0x95, 0x01); write_cmos_sensor(0x96, 0xe0); write_cmos_sensor(0x97, 0x02); write_cmos_sensor(0x98, 0x80); /*Gain*/ write_cmos_sensor(0xb0, 0x46); write_cmos_sensor(0xb1, 0x01); write_cmos_sensor(0xb2, 0x00); write_cmos_sensor(0xb3, 0x40); write_cmos_sensor(0xb4, 0x40); write_cmos_sensor(0xb5, 0x40); write_cmos_sensor(0xb6, 0x00); /*BLK*/ write_cmos_sensor(0x40, 0x26); write_cmos_sensor(0x4e, 0x00); write_cmos_sensor(0x4f, 0x3c); /*Dark Sun*/ write_cmos_sensor(0xe0, 0x9f); write_cmos_sensor(0xe1, 0x90); write_cmos_sensor(0xe4, 0x0f); write_cmos_sensor(0xe5, 0xff); /*MIPI*/ write_cmos_sensor(0xfe, 0x03); write_cmos_sensor(0x10, 0x00); write_cmos_sensor(0x01, 0x03); write_cmos_sensor(0x02, 0x33); write_cmos_sensor(0x03, 0x96); write_cmos_sensor(0x04, 0x01); write_cmos_sensor(0x05, 0x00); write_cmos_sensor(0x06, 0x80); write_cmos_sensor(0x11, 0x2b); write_cmos_sensor(0x12, 0x20); write_cmos_sensor(0x13, 0x03); write_cmos_sensor(0x15, 0x00); write_cmos_sensor(0x21, 0x10); write_cmos_sensor(0x22, 0x00); write_cmos_sensor(0x23, 0x30); write_cmos_sensor(0x24, 0x02); write_cmos_sensor(0x25, 0x12); write_cmos_sensor(0x26, 0x02); write_cmos_sensor(0x29, 0x01); write_cmos_sensor(0x2a, 0x0a); write_cmos_sensor(0x2b, 0x03); write_cmos_sensor(0xfe, 0x00); write_cmos_sensor(0xf9, 0x0e); write_cmos_sensor(0xfc, 0x0e); write_cmos_sensor(0xfe, 0x00); write_cmos_sensor(0x25, 0xa2); write_cmos_sensor(0x3f, 0x1a); Sleep(100); write_cmos_sensor(0x25,0xe2); }

接下来,再看get_info、get_resolution函数,主要是获取摄像头模组的工作参数,参考如下:

//gc030amipi_Sensor.c static kal_uint32 get_info(MSDK_SCENARIO_ID_ENUM scenario_id,MSDK_SENSOR_INFO_STRUCT *sensor_info,MSDK_SENSOR_CONFIG_STRUCT *sensor_config_data) { LOG_INF("scenario_id = %d\n", scenario_id); sensor_info->SensorClockPolarity = SENSOR_CLOCK_POLARITY_LOW; sensor_info->SensorClockFallingPolarity = SENSOR_CLOCK_POLARITY_LOW; /* not use */ sensor_info->SensorHsyncPolarity = SENSOR_CLOCK_POLARITY_LOW; // inverse with datasheet sensor_info->SensorVsyncPolarity = SENSOR_CLOCK_POLARITY_LOW; sensor_info->SensorInterruptDelayLines = 4; /* not use */ sensor_info->SensorResetActiveHigh = FALSE; /* not use */ sensor_info->SensorResetDelayCount = 5; /* not use */ sensor_info->SensroInterfaceType = imgsensor_info.sensor_interface_type; sensor_info->MIPIsensorType = imgsensor_info.mipi_sensor_type; sensor_info->SettleDelayMode = imgsensor_info.mipi_settle_delay_mode; sensor_info->SensorOutputDataFormat = imgsensor_info.sensor_output_dataformat; sensor_info->CaptureDelayFrame = imgsensor_info.cap_delay_frame; sensor_info->PreviewDelayFrame = imgsensor_info.pre_delay_frame; sensor_info->VideoDelayFrame = imgsensor_info.video_delay_frame; sensor_info->HighSpeedVideoDelayFrame = imgsensor_info.hs_video_delay_frame; sensor_info->SlimVideoDelayFrame = imgsensor_info.slim_video_delay_frame; sensor_info->SensorMasterClockSwitch = 0; /* not use */ sensor_info->SensorDrivingCurrent = imgsensor_info.isp_driving_current; sensor_info->AEShutDelayFrame = imgsensor_info.ae_shut_delay_frame; /* The frame of setting shutter default 0 for TG int */ sensor_info->AESensorGainDelayFrame = imgsensor_info.ae_sensor_gain_delay_frame; /* The frame of setting sensor gain */ sensor_info->AEISPGainDelayFrame = imgsensor_info.ae_ispGain_delay_frame; sensor_info->IHDR_Support = imgsensor_info.ihdr_support; sensor_info->IHDR_LE_FirstLine = imgsensor_info.ihdr_le_firstline; sensor_info->SensorModeNum = imgsensor_info.sensor_mode_num; sensor_info->SensorMIPILaneNumber = imgsensor_info.mipi_lane_num; sensor_info->SensorClockFreq = imgsensor_info.mclk; sensor_info->SensorClockDividCount = 3; /* not use */ sensor_info->SensorClockRisingCount = 0; sensor_info->SensorClockFallingCount = 2; /* not use */ sensor_info->SensorPixelClockCount = 3; /* not use */ sensor_info->SensorDataLatchCount = 2; /* not use */ sensor_info->MIPIDataLowPwr2HighSpeedTermDelayCount = 0; sensor_info->MIPICLKLowPwr2HighSpeedTermDelayCount = 0; sensor_info->SensorWidthSampling = 0; // 0 is default 1x sensor_info->SensorHightSampling = 0; // 0 is default 1x sensor_info->SensorPacketECCOrder = 1; switch (scenario_id) { case MSDK_SCENARIO_ID_CAMERA_PREVIEW: sensor_info->SensorGrabStartX = imgsensor_info.pre.startx; sensor_info->SensorGrabStartY = imgsensor_info.pre.starty; sensor_info->MIPIDataLowPwr2HighSpeedSettleDelayCount = imgsensor_info.pre.mipi_data_lp2hs_settle_dc; break; case MSDK_SCENARIO_ID_CAMERA_CAPTURE_JPEG: sensor_info->SensorGrabStartX = imgsensor_info.cap.startx; sensor_info->SensorGrabStartY = imgsensor_info.cap.starty; sensor_info->MIPIDataLowPwr2HighSpeedSettleDelayCount = imgsensor_info.cap.mipi_data_lp2hs_settle_dc; break; case MSDK_SCENARIO_ID_VIDEO_PREVIEW: sensor_info->SensorGrabStartX = imgsensor_info.normal_video.startx; sensor_info->SensorGrabStartY = imgsensor_info.normal_video.starty; sensor_info->MIPIDataLowPwr2HighSpeedSettleDelayCount = imgsensor_info.normal_video.mipi_data_lp2hs_settle_dc; break; case MSDK_SCENARIO_ID_HIGH_SPEED_VIDEO: sensor_info->SensorGrabStartX = imgsensor_info.hs_video.startx; sensor_info->SensorGrabStartY = imgsensor_info.hs_video.starty; sensor_info->MIPIDataLowPwr2HighSpeedSettleDelayCount = imgsensor_info.hs_video.mipi_data_lp2hs_settle_dc; break; case MSDK_SCENARIO_ID_SLIM_VIDEO: sensor_info->SensorGrabStartX = imgsensor_info.slim_video.startx; sensor_info->SensorGrabStartY = imgsensor_info.slim_video.starty; sensor_info->MIPIDataLowPwr2HighSpeedSettleDelayCount = imgsensor_info.slim_video.mipi_data_lp2hs_settle_dc; break; default: sensor_info->SensorGrabStartX = imgsensor_info.pre.startx; sensor_info->SensorGrabStartY = imgsensor_info.pre.starty; sensor_info->MIPIDataLowPwr2HighSpeedSettleDelayCount = imgsensor_info.pre.mipi_data_lp2hs_settle_dc; break; } return ERROR_NONE; } static kal_uint32 get_resolution(MSDK_SENSOR_RESOLUTION_INFO_STRUCT *sensor_resolution) { LOG_INF("E\n"); sensor_resolution->SensorFullWidth = imgsensor_info.cap.grabwindow_width; sensor_resolution->SensorFullHeight = imgsensor_info.cap.grabwindow_height; sensor_resolution->SensorPreviewWidth = imgsensor_info.pre.grabwindow_width; sensor_resolution->SensorPreviewHeight = imgsensor_info.pre.grabwindow_height; sensor_resolution->SensorVideoWidth = imgsensor_info.normal_video.grabwindow_width; sensor_resolution->SensorVideoHeight = imgsensor_info.normal_video.grabwindow_height; sensor_resolution->SensorHighSpeedVideoWidth = imgsensor_info.hs_video.grabwindow_width; sensor_resolution->SensorHighSpeedVideoHeight = imgsensor_info.hs_video.grabwindow_height; sensor_resolution->SensorSlimVideoWidth = imgsensor_info.slim_video.grabwindow_width; sensor_resolution->SensorSlimVideoHeight = imgsensor_info.slim_video.grabwindow_height; return ERROR_NONE; }

然后,我们看下feature_control和control函数,feature_control主要用来获取或设置模组的一些特征参数,contral主要用来控制模组拍照、预览、录像等,参考如下:

//gc030amipi_Sensor.c static kal_uint32 feature_control(MSDK_SENSOR_FEATURE_ENUM feature_id,UINT8 *feature_para,UINT32 *feature_para_len) { UINT16 *feature_return_para_16=(UINT16 *) feature_para; UINT16 *feature_data_16=(UINT16 *) feature_para; UINT32 *feature_return_para_32=(UINT32 *) feature_para; UINT32 *feature_data_32=(UINT32 *) feature_para; unsigned long long *feature_data=(unsigned long long *) feature_para; SENSOR_WINSIZE_INFO_STRUCT *wininfo; MSDK_SENSOR_REG_INFO_STRUCT *sensor_reg_data=(MSDK_SENSOR_REG_INFO_STRUCT *) feature_para; LOG_INF("feature_id = %d\n", feature_id); switch (feature_id) { case SENSOR_FEATURE_GET_PERIOD: *feature_return_para_16++ = imgsensor.line_length; *feature_return_para_16 = imgsensor.frame_length; *feature_para_len=4; break; case SENSOR_FEATURE_GET_PIXEL_CLOCK_FREQ: *feature_return_para_32 = imgsensor.pclk; *feature_para_len=4; break; case SENSOR_FEATURE_SET_ESHUTTER: set_shutter(*feature_data); break; case SENSOR_FEATURE_SET_NIGHTMODE: night_mode((BOOL) *feature_data); break; case SENSOR_FEATURE_SET_GAIN: set_gain((UINT16) *feature_data); break; case SENSOR_FEATURE_SET_FLASHLIGHT: break; case SENSOR_FEATURE_SET_ISP_MASTER_CLOCK_FREQ: break; case SENSOR_FEATURE_SET_REGISTER: write_cmos_sensor(sensor_reg_data->RegAddr, sensor_reg_data->RegData); break; case SENSOR_FEATURE_GET_REGISTER: sensor_reg_data->RegData = read_cmos_sensor(sensor_reg_data->RegAddr); break; case SENSOR_FEATURE_GET_LENS_DRIVER_ID: // get the lens driver ID from EEPROM or just return LENS_DRIVER_ID_DO_NOT_CARE // if EEPROM does not exist in camera module. *feature_return_para_32=LENS_DRIVER_ID_DO_NOT_CARE; *feature_para_len=4; break; case SENSOR_FEATURE_SET_VIDEO_MODE: set_video_mode(*feature_data); break; case SENSOR_FEATURE_CHECK_SENSOR_ID: get_imgsensor_id(feature_return_para_32); break; case SENSOR_FEATURE_SET_AUTO_FLICKER_MODE: set_auto_flicker_mode((BOOL)*feature_data_16,*(feature_data_16+1)); break; case SENSOR_FEATURE_SET_MAX_FRAME_RATE_BY_SCENARIO: set_max_framerate_by_scenario((MSDK_SCENARIO_ID_ENUM)*feature_data, *(feature_data+1)); break; case SENSOR_FEATURE_GET_DEFAULT_FRAME_RATE_BY_SCENARIO: get_default_framerate_by_scenario((MSDK_SCENARIO_ID_ENUM)*(feature_data), (MUINT32 *)(uintptr_t)(*(feature_data+1))); break; case SENSOR_FEATURE_SET_TEST_PATTERN: set_test_pattern_mode((BOOL)*feature_data); break; case SENSOR_FEATURE_GET_TEST_PATTERN_CHECKSUM_VALUE: //for factory mode auto testing *feature_return_para_32 = imgsensor_info.checksum_value; *feature_para_len=4; break; case SENSOR_FEATURE_SET_FRAMERATE: LOG_INF("current fps :%d\n", (UINT32)*feature_data); spin_lock(&imgsensor_drv_lock); imgsensor.current_fps = *feature_data; spin_unlock(&imgsensor_drv_lock); break; case SENSOR_FEATURE_SET_HDR: LOG_INF("ihdr enable :%d\n", (BOOL)*feature_data); spin_lock(&imgsensor_drv_lock); imgsensor.ihdr_en = (BOOL)*feature_data; spin_unlock(&imgsensor_drv_lock); break; case SENSOR_FEATURE_GET_CROP_INFO: LOG_INF("SENSOR_FEATURE_GET_CROP_INFO scenarioId:%d\n", (UINT32)*feature_data); wininfo = (SENSOR_WINSIZE_INFO_STRUCT *)(uintptr_t)(*(feature_data+1)); switch (*feature_data_32) { case MSDK_SCENARIO_ID_CAMERA_CAPTURE_JPEG: memcpy((void *)wininfo,(void *)&imgsensor_winsize_info[1],sizeof(SENSOR_WINSIZE_INFO_STRUCT)); break; case MSDK_SCENARIO_ID_VIDEO_PREVIEW: memcpy((void *)wininfo,(void *)&imgsensor_winsize_info[2],sizeof(SENSOR_WINSIZE_INFO_STRUCT)); break; case MSDK_SCENARIO_ID_HIGH_SPEED_VIDEO: memcpy((void *)wininfo,(void *)&imgsensor_winsize_info[3],sizeof(SENSOR_WINSIZE_INFO_STRUCT)); break; case MSDK_SCENARIO_ID_SLIM_VIDEO: memcpy((void *)wininfo,(void *)&imgsensor_winsize_info[4],sizeof(SENSOR_WINSIZE_INFO_STRUCT)); break; case MSDK_SCENARIO_ID_CAMERA_PREVIEW: default: memcpy((void *)wininfo,(void *)&imgsensor_winsize_info[0],sizeof(SENSOR_WINSIZE_INFO_STRUCT)); break; } break; case SENSOR_FEATURE_SET_IHDR_SHUTTER_GAIN: LOG_INF("SENSOR_SET_SENSOR_IHDR LE=%d, SE=%d, Gain=%d\n",(UINT16)*feature_data,(UINT16)*(feature_data+1),(UINT16)*(feature_data+2)); ihdr_write_shutter_gain((UINT16)*feature_data,(UINT16)*(feature_data+1),(UINT16)*(feature_data+2)); break; default: break; } return ERROR_NONE; } static kal_uint32 control(MSDK_SCENARIO_ID_ENUM scenario_id, MSDK_SENSOR_EXPOSURE_WINDOW_STRUCT *image_window,MSDK_SENSOR_CONFIG_STRUCT *sensor_config_data) { LOG_INF("scenario_id = %d\n", scenario_id); spin_lock(&imgsensor_drv_lock); imgsensor.current_scenario_id = scenario_id; spin_unlock(&imgsensor_drv_lock); switch (scenario_id) { case MSDK_SCENARIO_ID_CAMERA_PREVIEW: preview(image_window, sensor_config_data); break; case MSDK_SCENARIO_ID_CAMERA_CAPTURE_JPEG: capture(image_window, sensor_config_data); break; case MSDK_SCENARIO_ID_VIDEO_PREVIEW: normal_video(image_window, sensor_config_data); break; case MSDK_SCENARIO_ID_HIGH_SPEED_VIDEO: hs_video(image_window, sensor_config_data); break; case MSDK_SCENARIO_ID_SLIM_VIDEO: slim_video(image_window, sensor_config_data); break; default: LOG_INF("Error ScenarioId setting"); preview(image_window, sensor_config_data); return ERROR_INVALID_SCENARIO_ID; } return ERROR_NONE; }

最后,是close函数,用来关闭模组,如果不需要特殊操作,在设备驱动的Close操作中,对模组进行下电等操作即可,模组的close函数只是一个空函数:

//gc030amipi_Sensor.c static kal_uint32 close(void) { LOG_INF("E\n"); /*No Need to implement this function*/ return ERROR_NONE; }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3