天天看點

MTK camera啟動流程介紹一、Camera 架構介紹:二、Camera 啟動流程三、kernel 啟動流程四、總結

MTK camera啟動流程介紹一、Camera 架構介紹:二、Camera 啟動流程三、kernel 啟動流程四、總結

和你一起終身學習,這裡是程式員Android

經典好文推薦,通過閱讀本文,您将收獲以下知識點:

一、Camera 架構介紹:

二、Camera 啟動流程

三、kernel 啟動流程

1、set clock 設定時鐘

2、set driver

3、上電相關

四、總結

1、ID讀取不到,I2C不通

2、Camera 啟動時間過長

3、preview 階段耗時

4、低電流、功耗相關問題

一、Camera 架構介紹:

Camera

的架構分為

Kernel

部分和

hal

部分,其中

kernel

部分主要有兩塊:

  • image sensor driver

    ,負責具體型号的

    sensor

    id

    檢測,上電,以及在

    preview

    capture

    初始化

    3A

    等等功能設定時的寄存器配置;
  • isp driver

    ,通過

    DMA

    sensor

    資料流上傳;

HAL

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

  • imageio

    ,主要負責資料

    buffer

    上傳的

    pipe

  • drv

    ,包含

    imgsensor

    isp

    hal

    層控制;
  • feature io

    ,包含各種

    3A

    等性能配置;

這篇内容主要介紹開機過程中

search sensor

以及上電流程等内容。

二、Camera 啟動流程

1、

CameraService

是在開機時啟動的,啟動後進行

searchSensor

的操作,會

search

系統有多少

camera

,開機時的

search

操作,隻進行

camera

支援數量的周遊,以及

sensor ID

的讀取操作,如下是

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

    MTK camera啟動流程介紹一、Camera 架構介紹:二、Camera 啟動流程三、kernel 啟動流程四、總結

(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 <= 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

的内容:

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 啟動流程

先來看整體的架構圖如下:

MTK camera啟動流程介紹一、Camera 架構介紹:二、Camera 啟動流程三、kernel 啟動流程四、總結

image.png

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

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

的内容,然後看

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

3、上電相關

上電時序配置:

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

是否正常通訊)。這部分調試過程中遇到的問題總結如下:

1、ID讀取不到,I2C不通

  • 檢查上電時序,3項電壓(

    AVDD/DVDD/IOVDD

    )是否正确;
  • I2C

    位址及通道設定是否正确;
  • 檢查

    cfg_setting_imgsensor.cpp

    MCLK

    HW

    連結配置是否正确;

2、Camera 啟動時間過長

  • 檢查

    Sensor

    上電時序要求的延時,是否有偏長的情況;
  • 去掉多餘的

    I2C

    位址,因為大部分驅動會多添加一些位址;
  • OTP

    的加載調整到每次開機時第一次打開加載,之後不加載;
  • sensorInit

    如果時間過長,可以調節

    I2C speed(400->1000)

3、preview 階段耗時

  • 檢查

    streamOn/Off

    的耗時;
  • preview_init

    是否有較長時間的耗時
  • 以及延時操作使用

    mdelay

    代替

    msleep

  • pre_delay_frame/cap_delay_frame

    丢幀操作是否合适;

4、低電流、功耗相關問題

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

    pin

    sensor

    ,在操作時是否有做好

    workaround

  • I2C

    寄存器單個讀寫,調整為連續讀寫的方式也有一定優化;
  • sensor

    PIN

    是否有被其他子產品占用,異常操作的行為;

原文連結:https://blog.csdn.net/karaskass/article/details/106261187

友情推薦:

Android 開發幹貨集錦

至此,本篇已結束。轉載網絡的文章,小編覺得很優秀,歡迎點選閱讀原文,支援原創作者,如有侵權,懇請聯系小編删除,歡迎您的建議與指正。同時期待您的關注,感謝您的閱讀,謝謝!

MTK camera啟動流程介紹一、Camera 架構介紹:二、Camera 啟動流程三、kernel 啟動流程四、總結

點選閱讀原文,為大佬點贊!