1. MTK camera啟動(dòng)流程

        共 11702字,需瀏覽 24分鐘

         ·

        2021-03-26 07:59

        和你一起終身學(xué)習(xí),這里是程序員Android

        經(jīng)典好文推薦,通過閱讀本文,您將收獲以下知識(shí)點(diǎn):

        一、Camera 框架介紹:

        Camera的框架分為Kernel部分和hal部分,其中kernel部分主要有兩塊:

        • image sensor driver,負(fù)責(zé)具體型號(hào)的sensorid檢測(cè),上電,以及在previewcapture初始化、3A等等功能設(shè)定時(shí)的寄存器配置;

        • isp driver,通過DMAsensor數(shù)據(jù)流上傳;

        HAL層部分主要有三部分組成:

        • imageio,主要負(fù)責(zé)數(shù)據(jù)buffer上傳的pipe;

        • drv,包含imgsensorisphal層控制;

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

        這篇內(nèi)容主要介紹開機(jī)過程中search sensor以及上電流程等內(nèi)容。

        二、Camera 啟動(dòng)流程

        1、CameraService是在開機(jī)時(shí)啟動(dòng)的,啟動(dòng)后進(jìn)行searchSensor的操作,會(huì)search系統(tǒng)有多少camera,開機(jī)時(shí)的search操作,只進(jìn)行camera支持?jǐn)?shù)量的遍歷,以及sensor ID的讀取操作,如下是hal部分的ASTAH繪制調(diào)用流程圖,對(duì)應(yīng)的接口的文件路徑:

        • 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

        (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相關(guān)內(nèi)容
        pSeninfDrv->init();

        //將所有的clk全部打開
        pSeninfDrv->setAllMclkOnOff(ISP_DRIVING_8MA, TRUE);

        pSensorDrv->init();
        for (MUINT i = IMGSENSOR_SENSOR_IDX_MIN_NUM; i <= max_index_of_camera; i++) {
        if((ret = pSensorDrv->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的內(nèi)容:

        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的內(nèi)容,此sensorList需要與kernel層配置的一致,不一致的話在打開camera時(shí)會(huì)出現(xiàn)異常:
        文件位置:
        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;
        }

        對(duì)應(yīng)的MSDK_SENSOR_INIT_FUNCTION_STRUCT的結(jié)構(gòu)體如下:

        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) featureControlsetDriver流程:
        文件位置:
        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
        )
        {
        //結(jié)構(gòu)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 啟動(dòng)流程

        先來(lái)看整體的框架圖如下:



          

        1、set clock 設(shè)置時(shí)鐘

        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]);
        }
        }

        2、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的內(nèi)容,然后看sensorList是否對(duì)應(yīng),并獲取對(duì)應(yīng)的下標(biāo),調(diào)用imgsensor_check_is_alive進(jìn)行上下電并讀取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);
        //對(duì)應(yīng)config字符串進(jìn)行按空格進(jìn)行拆解
        driver_name = strsep(&psensor_list_config, " \0");

        while (driver_name != NULL) {
        for (j = 0; j < MAX_NUM_OF_SUPPORT_SENSOR; j++) {
        //判斷對(duì)應(yīng)的init函數(shù)是否存在
        if (pSensorList[j].init == NULL)
        break;
        else if (!strcmp(driver_name, pSensorList[j].name)) {
        //如果在config中和sensorlist中同時(shí)有定義進(jìn)行賦值
        orderedSearchList[i++] = j;
        break;
        }
        }
        driver_name = strsep(&psensor_list_config, " \0");
        }

        for (i = 0; i < MAX_NUM_OF_SUPPORT_SENSOR; i++) {
        //上面獲取到的sensorlist的下標(biāo)
        drv_idx = orderedSearchList[i];
        if (pSensorList[drv_idx].init) {
        //調(diào)用對(duì)應(yīng)驅(qū)動(dòng)的init函數(shù)
        pSensorList[drv_idx].init(&psensor->pfunc);
        if (psensor->pfunc) {
        psensor_inst->psensor_name =
        (char *)pSensorList[drv_idx].name;
        //到這里是重點(diǎn),進(jìn)行上電讀取ID的操作
        if (!imgsensor_check_is_alive(psensor)) {
        ret = drv_idx;
        }
        }
        }
        }
        }

        下面看對(duì)應(yīng)的上下電以及讀取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;
        }

        3、上電相關(guān)

        上電時(shí)序配置:

        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
        }

        對(duì)應(yīng)的控制的流程如下:

        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)
        //調(diào)用GPIO或者regulator的set 電壓操作,這里的pdev在imgsensor_probe中已經(jīng)設(shè)置
        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;
        }

        四、總結(jié)

        通過上面的代碼流程,可以知道上開機(jī)時(shí),camera模塊先會(huì)將所有的MCLK打開,然后對(duì)依次對(duì)對(duì)應(yīng)的sensor進(jìn)行上電,讀取ID(判斷I2C是否正常通訊)。這部分調(diào)試過程中遇到的問題總結(jié)如下:

        1、ID讀取不到,I2C不通

        • 檢查上電時(shí)序,3項(xiàng)電壓(AVDD/DVDD/IOVDD)是否正確;

        • I2C地址及通道設(shè)置是否正確;

        • 檢查cfg_setting_imgsensor.cppMCLKHW鏈接配置是否正確;

        2、Camera 啟動(dòng)時(shí)間過長(zhǎng)

        • 檢查Sensor上電時(shí)序要求的延時(shí),是否有偏長(zhǎng)的情況;

        • 去掉多余的I2C地址,因?yàn)榇蟛糠烛?qū)動(dòng)會(huì)多添加一些地址;

        • OTP的加載調(diào)整到每次開機(jī)時(shí)第一次打開加載,之后不加載;

        • sensorInit如果時(shí)間過長(zhǎng),可以調(diào)節(jié)I2C speed(400->1000)

        3、preview 階段耗時(shí)

        • 檢查streamOn/Off的耗時(shí);

        • preview_init是否有較長(zhǎng)時(shí)間的耗時(shí)

        • 以及延時(shí)操作使用mdelay代替msleep;

        • pre_delay_frame/cap_delay_frame丟幀操作是否合適;

        4、低電流、功耗相關(guān)問題

        • 檢查電壓是否都有下電成功,防止漏電;

        • 對(duì)于共pinsensor,在操作時(shí)是否有做好workaround;

        • I2C寄存器單個(gè)讀寫,調(diào)整為連續(xù)讀寫的方式也有一定優(yōu)化;

        • sensorPIN是否有被其他模塊占用,異常操作的行為;

        友情推薦:

        Android 開發(fā)干貨集錦

        至此,本篇已結(jié)束。轉(zhuǎn)載網(wǎng)絡(luò)的文章,小編覺得很優(yōu)秀,歡迎點(diǎn)擊閱讀原文,支持原創(chuàng)作者,如有侵權(quán),懇請(qǐng)聯(lián)系小編刪除,歡迎您的建議與指正。同時(shí)期待您的關(guān)注,感謝您的閱讀,謝謝!

        點(diǎn)個(gè)在看,方便您使用時(shí)快速查找!

        瀏覽 102
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 欧美综合视频 | 我挺进她的下面疯狂运动 | 亚洲精品国产乱码在线看天美 | 成人视频网站在线免费观看 | 高潮毛片无遮挡免费高清小说 |