MTK Camera驱动 上电与启动流程

您所在的位置:网站首页 carmera怎么读 MTK Camera驱动 上电与启动流程

MTK Camera驱动 上电与启动流程

2024-07-04 16:16:33| 来源: 网络整理| 查看: 265

Camera的框架分为Kernel 部分和hal部分,其中kernel部分主要有两块:

image sensordriver,负责具体型号的 sensor 的 id 检测,上电,以及在preview、capture、初始化、3A等等功能设定时的寄存器配置;

isp driver,通过DMA将sensor数据流上传;

HAL层部分主要有三部分组成:

imageio,主要负责数据buffer上传的pipe;

drv,包含imgsensor和isp的hal层控制;

feature io,包含各种3A等性能配置;

这篇内容主要介绍开机过程中search sensor已经上电流程等内容。

Camera启动流程

CameraService是在开机时启动的,启动后进行searchSensor的操作,会search系统多少camera,开机时的search操作,只进行camera支持数量的遍历,以及sensorID的读取操作,如下是hal部分的ASTAH绘制调用流程图,对应的接口的文件路径:

HalSensorList: vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/common/v1/HalSensorList.enumList.cpp

  vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/common/v1/HalSensorList.cpp

SeninfDrv: vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/mt6765/seninf_drv.cpp

SensorDrv: vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/common/v1/imgsensor_drv.cpp

Camera启动流程

(1)这里先看enumerateSensor_Locked完成的工作,直接看代码:

MUINT HalSensorList::searchSensors() { Mutex::Autolock _l(mEnumSensorMutex); MY_LOGD("searchSensors"); return enumerateSensor_Locked(); } MUINT HalSensorList::enumerateSensor_Locked() { SensorDrv *const pSensorDrv = SensorDrv::get(); SeninfDrv *const pSeninfDrv = SeninfDrv::createInstance(); //初始化seninf,配置ISP相关内容 pSeninfDrv->init(); //将所有的clk全部打开 pSeninfDrv->setAllMclkOnOff(ISP_DRIVING_8MA, TRUE); pSensorDrv->init(); for (MUINT i = IMGSENSOR_SENSOR_IDX_MIN_NUM; i searchSensor((IMGSENSOR_SENSOR_IDX)i)) == SENSOR_NO_ERROR){ //query sensorinfo querySensorDrvInfo((IMGSENSOR_SENSOR_IDX)i); //fill in metadata buildSensorMetadata((IMGSENSOR_SENSOR_IDX)i); pSensorInfo = pSensorDrv->getSensorInfo((IMGSENSOR_SENSOR_IDX)i); addAndInitSensorEnumInfo_Locked( (IMGSENSOR_SENSOR_IDX)i, mapToSensorType(pSensorInfo->GetType()), pSensorInfo->getDrvMacroName()); } } }

(2)下面主要看下searchSensor的流程,这里有去获取sensorList的内容:

MINT32 ImgSensorDrv::searchSensor(IMGSENSOR_SENSOR_IDX sensorIdx) { GetSensorInitFuncList(&pSensorInitFunc); featureControl(sensorIdx, SENSOR_FEATURE_SET_DRIVER, (MUINT8 *)&idx, &featureParaLen); NSFeature::SensorInfoBase* pSensorInfo = pSensorInitFunc[idx].pSensorInfo; }

GetSensorInitFuncList是获取到配置的sensorList的内容,此sensorList需要与kernel层配置的一致,不一致的话在打开camera时会出现异常:

//vendor/mediatek/proprietary/custom/mt6765/hal/imgsensor_src/sensorlist.cpp MSDK_SENSOR_INIT_FUNCTION_STRUCT SensorList[] = { #if defined(IMX486_MIPI_RAW) RAW_INFO(IMX486_SENSOR_ID, SENSOR_DRVNAME_IMX486_MIPI_RAW, CAM_CALGetCalData), #endif //..... } UINT32 GetSensorInitFuncList(MSDK_SENSOR_INIT_FUNCTION_STRUCT **ppSensorList) { if (NULL == ppSensorList) { ALOGE("ERROR: NULL pSensorList\n"); return MHAL_UNKNOWN_ERROR; } *ppSensorList = &SensorList[0]; return MHAL_NO_ERROR; }

对应的MSDK_SENSOR_INIT_FUNCTION_STRUCT的结构体如下:

typedef struct { MUINT32 sensorType; MUINT32 SensorId; MUINT8 drvname[32]; NSFeature::SensorInfoBase* pSensorInfo; MUINT32 (*getCameraIndexMgr)(CAMERA_DATA_TYPE_ENUM CameraDataType, MVOID *pDataBuf, MUINT32 size); MUINT32 (*getCameraCalData)(UINT32* pGetSensorCalData); } MSDK_SENSOR_INIT_FUNCTION_STRUCT, *PMSDK_SENSOR_INIT_FUNCTION_STRUCT;

(3)featureControl的setDriver流程:

vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/common/v1/imgsensor_drv.cpp MINT32 ImgSensorDrv::featureControl( IMGSENSOR_SENSOR_IDX sensorIdx, ACDK_SENSOR_FEATURE_ENUM FeatureId, MUINT8 *pFeaturePara, MUINT32 *pFeatureParaLen ) { //结构ACDK_SENSOR_FEATURECONTROL_STRUCT和kernel中一致 featureCtrl.InvokeCamera = sensorIdx; featureCtrl.FeatureId = FeatureId;//SENSOR_FEATURE_SET_DRIVER featureCtrl.pFeaturePara = pFeaturePara; featureCtrl.pFeatureParaLen = pFeatureParaLen; if (ioctl(m_fdSensor, KDIMGSENSORIOC_X_FEATURECONCTROL , &featureCtrl) < 0) { LOG_ERR("[featureControl] Err-ctrlCode (%s)", strerror(errno)); return -errno; } return SENSOR_NO_ERROR; } kernel启动流程

先来看整体的框架图如下:

kernel启动流程

set clock设置时钟 static long imgsensor_ioctl( struct file *a_pstFile, unsigned int a_u4Command, unsigned long a_u4Param) { case KDIMGSENSORIOC_X_SET_MCLK_PLL: i4RetValue = imgsensor_clk_set( &pgimgsensor->clk, (struct ACDK_SENSOR_MCLK_STRUCT *)pBuff); break; //...... } int imgsensor_clk_set( struct IMGSENSOR_CLK *pclk, struct ACDK_SENSOR_MCLK_STRUCT *pmclk) { if (pmclk->on) { clk_prepare_enable(pclk->imgsensor_ccf[mclk_index]) ret = clk_set_parent( pclk->imgsensor_ccf[pmclk->TG], pclk->imgsensor_ccf[mclk_index]); } else { clk_disable_unprepare(pclk->imgsensor_ccf[mclk_index]); } } set driver static long imgsensor_ioctl( struct file *a_pstFile, unsigned int a_u4Command, unsigned long a_u4Param) { case KDIMGSENSORIOC_X_FEATURECONCTROL: i4RetValue = adopt_CAMERA_HW_FeatureControl(pBuff); break; //...... } static inline int adopt_CAMERA_HW_FeatureControl(void *pBuf) { /* copy from user */ switch (pFeatureCtrl->FeatureId) { case SENSOR_FEATURE_SET_DRIVER: { MINT32 drv_idx; psensor->inst.sensor_idx = pFeatureCtrl->InvokeCamera; drv_idx = imgsensor_set_driver(psensor); memcpy(pFeaturePara, &drv_idx, FeatureParaLen); break; } } }

遍历CONFIG_CUSTOM_KERNEL_IMGSENSOR的内容,然后看sensorList是否对应,并获取对应的下标,调用imgsensor_check_is_alive进行上下电并读取ID 的操作:

struct IMGSENSOR_INIT_FUNC_LIST kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR] = { #if defined(XXXXXX_MIPI_RAW) {XXXXXX_SENSOR_ID, SENSOR_DRVNAME_XXXXXX_MIPI_RAW, XXXXXX_MIPI_RAW_SensorInit}, #endif //...... } int imgsensor_set_driver(struct IMGSENSOR_SENSOR *psensor) { struct IMGSENSOR_SENSOR_INST *psensor_inst = &psensor->inst; struct IMGSENSOR_INIT_FUNC_LIST *pSensorList = kdSensorList; //获取config的size char *sensor_configs = STRINGIZE(CONFIG_CUSTOM_KERNEL_IMGSENSOR); imgsensor_i2c_init(&psensor_inst->i2c_cfg, imgsensor_custom_config[psensor->inst.sensor_idx].i2c_dev); memcpy(psensor_list_config, sensor_configs+1, strlen(sensor_configs)-2); //对应config字符串进行按空格进行拆解 driver_name = strsep(&psensor_list_config, " \0"); while (driver_name != NULL) { for (j = 0; j < MAX_NUM_OF_SUPPORT_SENSOR; j++) { //判断对应的init函数是否存在 if (pSensorList[j].init == NULL) break; else if (!strcmp(driver_name, pSensorList[j].name)) { //如果在config中和sensorlist中同时有定义进行赋值 orderedSearchList[i++] = j; break; } } driver_name = strsep(&psensor_list_config, " \0"); } for (i = 0; i < MAX_NUM_OF_SUPPORT_SENSOR; i++) { //上面获取到的sensorlist的下标 drv_idx = orderedSearchList[i]; if (pSensorList[drv_idx].init) { //调用对应驱动的init函数 pSensorList[drv_idx].init(&psensor->pfunc); if (psensor->pfunc) { psensor_inst->psensor_name = (char *)pSensorList[drv_idx].name; //到这里是重点,进行上电读取ID的操作 if (!imgsensor_check_is_alive(psensor)) { ret = drv_idx; } } } } }

下面看对应的上下电以及读取ID 的操作:

static inline int imgsensor_check_is_alive(struct IMGSENSOR_SENSOR *psensor) { struct IMGSENSOR_SENSOR_INST *psensor_inst = &psensor->inst; //上电 err = imgsensor_hw_power(&pgimgsensor->hw, psensor, psensor_inst->psensor_name, IMGSENSOR_HW_POWER_STATUS_ON); //读取ID imgsensor_sensor_feature_control( psensor, SENSOR_FEATURE_CHECK_SENSOR_ID, (MUINT8 *)&sensorID, &retLen); if (sensorID == 0 || sensorID == 0xFFFFFFFF) { pr_info("Fail to get sensor ID %x\n", sensorID); err = ERROR_SENSOR_CONNECT_FAIL; } else { pr_info(" Sensor found ID = 0x%x\n", sensorID); err = ERROR_NONE; } //下电 imgsensor_hw_power(&pgimgsensor->hw, psensor, psensor_inst->psensor_name, IMGSENSOR_HW_POWER_STATUS_OFF); return err ? -EIO:err; } 上电相关

(1)上电时序配置

struct IMGSENSOR_HW_POWER_INFO { enum IMGSENSOR_HW_PIN pin; enum IMGSENSOR_HW_PIN_STATE pin_state_on; u32 pin_on_delay; enum IMGSENSOR_HW_PIN_STATE pin_state_off; u32 pin_off_delay; }; struct IMGSENSOR_HW_POWER_SEQ sensor_power_sequence[] = { //…… #if defined(XXXXXX_MIPI_RAW) { SENSOR_DRVNAME_XXXXXX_MIPI_RAW, { {RST, Vol_Low, 0}, {DVDD, Vol_1100, 1}, {AVDD, Vol_2800, 1}, {DOVDD, Vol_1800, 1}, {RST, Vol_High, 1}, {SensorMCLK, Vol_High, 0}, }, }, #endif }

对应的控制的流程如下:

static enum IMGSENSOR_RETURN imgsensor_hw_power_sequence( struct IMGSENSOR_HW *phw, enum IMGSENSOR_SENSOR_IDX sensor_idx, enum IMGSENSOR_HW_POWER_STATUS pwr_status, struct IMGSENSOR_HW_POWER_SEQ *ppower_sequence, char *pcurr_idx) { ppwr_info = ppwr_seq->pwr_info; // 上电 while (ppwr_info->pin != IMGSENSOR_HW_PIN_NONE && ppwr_info < ppwr_seq->pwr_info + IMGSENSOR_HW_POWER_INFO_MAX) { if (pwr_status == IMGSENSOR_HW_POWER_STATUS_ON && ppwr_info->pin != IMGSENSOR_HW_PIN_UNDEF) { pdev = phw->pdev[psensor_pwr->id[ppwr_info->pin]]; if (pdev->set != NULL) //调用GPIO或者regulator的set 电压操作,这里的pdev在imgsensor_probe中已经设置 pdev->set( pdev->pinstance, sensor_idx, ppwr_info->pin, ppwr_info->pin_state_on); mdelay(ppwr_info->pin_on_delay); } // 从上到下依次上电 ppwr_info++; pin_cnt++; } // 下电操作 if (pwr_status == IMGSENSOR_HW_POWER_STATUS_OFF) { while (pin_cnt) { //从下到上依次下电 ppwr_info--; pin_cnt--; if (ppwr_info->pin != IMGSENSOR_HW_PIN_UNDEF) { pdev = phw->pdev[psensor_pwr->id[ppwr_info->pin]]; mdelay(ppwr_info->pin_on_delay); if (pdev->set != NULL) pdev->set( pdev->pinstance, sensor_idx, ppwr_info->pin, ppwr_info->pin_state_off); } } } /* wait for power stable */ if (pwr_status == IMGSENSOR_HW_POWER_STATUS_ON) mdelay(5); return IMGSENSOR_RETURN_SUCCESS; } 总结

通过上面的代码流程,可以知道上开机时,camera模块先会将所有的MCLK打开,然后对依次对对应的sensor进行上电,读取ID(判断I2C是否正常通讯)。这部分调试过程中遇到的问题总结如下:

ID读取不到,I2C不通 检查上电时序,3项电压(AVDD/DVDD/IOVDD)是否正确; I2C地址及通道设置是否正确; 检查cfg_setting_imgsensor.cpp中MCLK和HW链接配置是否正确; Camera启动时间过长 检查Sensor上电时序要求的延时,是否有偏长的情况; 去掉多余的I2C地址,因为大部分驱动会多添加一些地址; OTP的加载调整到每次开机时第一次打开加载,之后不加载; sensorInit如果时间过长,可以调节I2C speed(400->1000); preview阶段耗时

检查streamOn/Off的耗时;

preview_init是否有较长时间的耗时

以及延时操作使用mdelay代替msleep;

pre_delay_frame/cap_delay_frame丢帧操作是否合适;

低电流、功耗相关问题: 检查电压是否都有下电成功,防止漏电; 对于共pin的sensor,在操作时是否有做好workaround; 将I2C寄存器单个读写,调整为连续读写的方式也有一定优化; sensor的PIN是否有被其他模块占用,异常操作的行为;


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭