1. 移植任务:实现 MTK 平台主副camera 移植
2. 移植前的准备工作:
1) MTK 平台手机一台,这里我们称作 P1
2) 获知MTK 的主副camera新片型号, 这里 P1 的前camera 为bf3703,后camera的型号为bf3920 //呵呵,比亚迪的便宜货
3) 厂商提供的 camera 驱动代码, 对于 每一款camera 都有两个同名的文件夹,为如 bf3703 对应的两个文件夹为bf3703_yuv分别存放的为 hal 层和 kernel 层的驱动代码; bf3920 的对应的两个同名文件夹为 bf3920_yuv这两个文件下的文件列表如下:
hal 层驱动代码目录:
bf3920_yuv:
camera_info_bf3920_yuv.cpp camera_info_bf3920_yuv.h camera_sensor_para_bf3920_yuv.h camera_tuning_para_bf3920_yuv.cpp cfg_ftbl_bf3920_yuv.h config.ftbl.bf3920_yuv.hbf3703_yuv:
camera_info_bf3703_yuv.cpp
camera_info_bf3703_yuv.h
camera_sensor_para_bf3703_yuv.h
camera_tuning_para_bf3703_yuv.cpp
config.ftbl.bf3703_yuv.
kernel 层驱动代码:
feature_bf3920_yuv.cpp
bf3920yuv_CameraCustomized.h
bf3920yuv_Camera_Sensor_para.h
bf3920_yuv_Sensor.c
bf3920yuv_Sensor.h
bf3703_yuv:
bf3703_yuv_CameraCustomized.h
bf3703_yuv_Camera_Sensor_para.h
bf3703_yuv_Sensor.c
bf3703_yuv_Sensor.h
注意:
(1)不要想当然认为camera 代码目录就是 camera name+_yuv ,有些支持 mipi 或者其他接口的camera 驱动目录就不是这样,如camera ov5645 的驱动目录ov5645_mipi_yuv
(2)如果代码需要保证低耦合性,最好将驱动代码拷贝至mediatek/custom/ v2_e324_2ggsm4_wvga_t62d/hal/imgsensor和 mediatek/custom/common/kernel/imgsensor/
4) MTK 提供的系统开发平台代码,我这里提供的是mtk6572 的一套代码,这里简称V2
3. 移植步骤:
1) 裁剪模块:
/* v2_e324_2ggsm4_wvga_t62d 为项目新建的工程目录 */
① 进入文件 mediatek/config/v2_e324_2ggsm4_wvga_t62d/ProjectConfig.mk 查看:
/* 添加摄像头模块,定义hal 层,以下四个选项 bf3920_yuv sp0718_yuv
为我们手机的camera 驱动模块,其余两个为其他手机项目的需要添加的
驱动代码模块*/
CUSTOM_HAL_IMGSENSOR=bf3920_yuv sp0718_yuvsp0a19_yuv bf3703_yuv
/*在hal 层添加主摄像头(后置摄像头)*/
CUSTOM_HAL_MAIN_IMGSENSOR = bf3920_yuv sp0718_yuv
/*在hal 层添加副摄像头(前置摄像头)*/
CUSTOM_HAL_SUB_IMGSENSOR = sp0a19_yuv bf3703_yuv
/* 添加摄像头模块,定义kernel 层,以下四个选项bf3920_yuv sp0718_yuv
为我们手机的camera 驱动模块,其余两个为其他手机项目的需要添加的
驱动代码模块*/
CUSTOM_KERNEL_IMGSENSOR =bf3920_yuv sp0718_yuv sp0a19_yuv bf3703_yuv
/*在kernel层添加主摄像头(后置摄像头)*/
CUSTOM_KERNEL_MAIN_IMGSENSOR = bf3920_yuv sp0718_yuv
/*在kernel层添加副摄像头(前置摄像头)*/
CUSTOM_KERNEL_SUB_IMGSENSOR = sp0a19_yuv bf3703_yuv
注意: 上述操作中 模块的名称千万不要随意填写,一定要和厂商提供的驱动代码目录一致; 主副摄像头也不能填写错误,要区分开来,不能填错位,主副 camera 的区分可以根据像素来判断,一般高像素的作为主camera ,低像素的作为副camera ,当然也有例外,最好的区分方式就是看你的硬件。
/* hal层的副摄像头自动对焦设置*/
CUSTOM_HAL_LENS= dummy_lens dummy_lens dummy_lens
/* hal层的主摄像头自动对焦设置*/
CUSTOM_HAL_MAIN_LENS=dummy_lens
/* kernel层的副摄像头自动对焦设置*/
CUSTOM_KERNEL_LENS=dummy_lens dummy_lens dummy_lens
/* kernel层的副摄像头自动对焦设置*/
CUSTOM_KERNEL_MAIN_LENS=dummy_lens
注意:如果移植的摄像头没有自动对焦(AF)功能就必须将默认的AF功能屏蔽掉(否则在DMA操作数据的时候很多的算法受影响,将在切换的时候很卡)!
2) 将厂商提供的 camera 驱动代码,分别到…hal/imgesensor 和…kernel/imgesensor 目录下,拷贝后如下,
在路径mediatek/custom/common/hal/imgsensor/下:
在路径mediatek/custom/common/kernel/imgsensor/下:
3) 注册需要添加的摄像头信息
① 打开文件 custom/common/hal/imgsensor/src/sensorlist.cpp
//MSDK_SENSOR_INIT_FUNCTION_STRUCT SensorList[MAX_NUM_OF_SUPPORT_SENSOR] =
MSDK_SENSOR_INIT_FUNCTION_STRUCTSensorList[] =
{
…
#if defined(BF3920_YUV) // main sensor 定义在前面
YUV_INFO(BF3920_SENSOR_ID, SENSOR_DRVNAME_BF3920_YUV,NULL),
#endif
#if defined(BF3703_YUV)
YUV_INFO(BF3703_SENSOR_ID, SENSOR_DRVNAME_BF3703_YUV,NULL),
#endif
…
};
② 打开文件 custom/common/kernel/imgsensor/inc/kd_imgsensor.h
添加定义如下:
#defineBF3703_SENSOR_ID 0x3703
#define BF3A03_SENSOR_ID 0x3a03
#defineBF3920_SENSOR_ID 0x3920
#defineSENSOR_DRVNAME_BF3920_YUV "bf3920yuv"
#define SENSOR_DRVNAME_BF3A03_YUV "bf3a03yuv"
#defineSENSOR_DRVNAME_BF3703_YUV "bf3703yuv"
注意:上述定义的ID 值实在厂商提供的datasheet 中得到的
上述定义,将会在以下驱动文件中调用:
文件mediatek/custom/common/kernel/imgsensor/bf3703_yuv/bf3703_yuv_Sensor.c
在文件mediatek/custom/common/hal/imgsensor/bf3703_yuv/config.ftbl.bf3703_yuv.h中
③ 为系统提供调用的API
UINT32BF3920_YUV_SensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc);
UINT32BF3A03_YUV_SensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc);
UINT32BF3703_YUV_SensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc);
//! Add Sensor Init function here
//! Note:
//! 1. Add by the resolution from""large to small"", due to large sensor
//! will be possible to be main sensor.
//! This can avoid I2C error during searching sensor.
//!2.This file should be the same as mediatek\custom\common\hal\imgsensor\src\sensorlist.cpp
ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR+1]={
….
#if defined(BF3920_YUV)
{BF3920_SENSOR_ID,SENSOR_DRVNAME_BF3920_YUV,BF3920_YUV_SensorInit},
#endif
#if defined(BF3703_YUV)
{BF3703_SENSOR_ID,SENSOR_DRVNAME_BF3703_YUV,BF3703_YUV_SensorInit},
#endif
….
/* ADD sensor driver beforethis line */
{0,{0},NULL},//end of list
};
注意:上述kdSensorList 的元素定义顺序必须和① 中的SensorList 的元素定义保持一致,并且主camera 要放在前面,副 camera 放在后面如下图:
④camera 上电和掉电
以下是 上电代码,路径为: mediatek/custom/v2_e324_2ggsm4_wvga_t62d/kernel/camera/camera/kd_camera_hw.c,其实上电代码移植很简单,我们只需要将 其它类似的camera 上电拷贝过来即可,你可以考虑像素接近的camera 上电代码 比如:如果你需要移植前摄,
你可以移植 sp0a18,gc0312,sp0a19等 //上电移植过程不可能保证百分百成功,如果失败就得参考datasheet
else if (currSensorName && (0 == strcmp(SENSOR_DRVNAME_SP2518_YUV,currSensorName))) //这一行为内核 遍历 camera 过程,只需将sensor 驱动名字改为要移植的camera 名字即可
{
K_DBG("[CAMERA SENSOR] kdCISModulePowerOn get in---SENSOR_DRVNAME_SP2518_YUV sensorIdx:%d; pinSetIdx=%d\n",SensorIdx, pinSetIdx);
if(TRUE != hwPowerOn(CAMERA_POWER_VCAM_A, VOL_2800,mode_name))
{
PK_DBG("[CAMERA SENSOR] Fail to enable analog power\n");
//return -EIO;
goto _kdCISModulePowerOn_exit_;
}
if(TRUE != hwPowerOn(CAMERA_POWER_VCAM_D2, VOL_1800/*VOL_2800*/,mode_name))
{
PK_DBG("[CAMERA SENSOR] Fail to enable digital power\n");
//return -EIO;
goto _kdCISModulePowerOn_exit_;
}
else
PK_DBG("[poweron] enable CAMERA_POWER_VCAM_D2\n");
if(TRUE != hwPowerOn(CAMERA_POWER_VCAM_D, VOL_1800,mode_name))
{
PK_DBG("[CAMERA SENSOR] Fail to enable digital power\n");
//return -EIO;
goto _kdCISModulePowerOn_exit_;
}
//PDN/STBY pin
if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMPDN])
{
if(mt_set_gpio_mode(pinSet[pinSetIdx][IDX_PS_CMPDN],pinSet[pinSetIdx][IDX_PS_CMPDN+IDX_PS_MODE])){PK_DBG("[CAMERA LENS] set gpio mode failed!! \n");}
if(mt_set_gpio_dir(pinSet[pinSetIdx][IDX_PS_CMPDN],GPIO_DIR_OUT)){PK_DBG("[CAMERA LENS] set gpio dir failed!! \n");}
if(mt_set_gpio_out(pinSet[pinSetIdx][IDX_PS_CMPDN],pinSet[pinSetIdx][IDX_PS_CMPDN+IDX_PS_OFF])){PK_DBG("[CAMERA LENS] set gpio failed!! \n");}
msleep(10);
if(mt_set_gpio_out(pinSet[pinSetIdx][IDX_PS_CMPDN],pinSet[pinSetIdx][IDX_PS_CMPDN+IDX_PS_ON])){PK_DBG("[CAMERA LENS] set gpio failed!! \n");}
msleep(5);
if(mt_set_gpio_out(pinSet[pinSetIdx][IDX_PS_CMPDN],pinSet[pinSetIdx][IDX_PS_CMPDN+IDX_PS_OFF])){PK_DBG("[CAMERA LENS] set gpio failed!! \n");}
msleep(5);
//RST pin
if(mt_set_gpio_mode(pinSet[pinSetIdx][IDX_PS_CMRST],pinSet[pinSetIdx][IDX_PS_CMRST+IDX_PS_MODE])){PK_DBG("[CAMERA SENSOR] set gpio mode failed!! \n");}
if(mt_set_gpio_dir(pinSet[pinSetIdx][IDX_PS_CMRST],GPIO_DIR_OUT)){PK_DBG("[CAMERA SENSOR] set gpio dir failed!! \n");}
if(mt_set_gpio_out(pinSet[pinSetIdx][IDX_PS_CMRST],pinSet[pinSetIdx][IDX_PS_CMRST+IDX_PS_OFF])){PK_DBG("[CAMERA SENSOR] set gpio failed!! \n");}
mdelay(10);
if(mt_set_gpio_out(pinSet[pinSetIdx][IDX_PS_CMRST],pinSet[pinSetIdx][IDX_PS_CMRST+IDX_PS_ON])){PK_DBG("[CAMERA SENSOR] set gpio failed!! \n");}
mdelay(5);
}
//disable inactive sensor
if(pinSetIdx == 0) {//disable sub
pinSetIdxTmp = 1;
}
else{
pinSetIdxTmp = 0;
}
if (GPIO_CAMERA_INVALID != pinSet[pinSetIdxTmp][IDX_PS_CMRST]) {
if(mt_set_gpio_mode(pinSet[pinSetIdxTmp][IDX_PS_CMRST],pinSet[pinSetIdxTmp][IDX_PS_CMRST+IDX_PS_MODE])){PK_DBG("[CAMERA SENSOR] set gpio mode failed!! \n");}
if(mt_set_gpio_mode(pinSet[pinSetIdxTmp][IDX_PS_CMPDN],pinSet[pinSetIdxTmp][IDX_PS_CMPDN+IDX_PS_MODE])){PK_DBG("[CAMERA LENS] set gpio mode failed!! \n");}
if(mt_set_gpio_dir(pinSet[pinSetIdxTmp][IDX_PS_CMRST],GPIO_DIR_OUT)){PK_DBG("[CAMERA SENSOR] set gpio dir failed!! \n");}
if(mt_set_gpio_dir(pinSet[pinSetIdxTmp][IDX_PS_CMPDN],GPIO_DIR_OUT)){PK_DBG("[CAMERA LENS] set gpio dir failed!! \n");}
if(mt_set_gpio_out(pinSet[pinSetIdxTmp][IDX_PS_CMRST],pinSet[pinSetIdxTmp][IDX_PS_CMRST+IDX_PS_OFF])){PK_DBG("[CAMERA SENSOR] set gpio failed!! \n");} //low == reset sensor
if(mt_set_gpio_out(pinSet[pinSetIdxTmp][IDX_PS_CMPDN],pinSet[pinSetIdxTmp][IDX_PS_CMPDN+IDX_PS_OFF])){PK_DBG("[CAMERA LENS] set gpio failed!! \n");} //high == power down lens module
}
}
以下为 掉电带,代码:
if(currSensorName && (0 == strcmp(SENSOR_DRVNAME_SP2518_YUV,currSensorName)))
{
msleep(5);
if(mt_set_gpio_out(pinSet[pinSetIdx][IDX_PS_CMPDN],pinSet[pinSetIdx][IDX_PS_CMPDN+IDX_PS_OFF])){PK_DBG("[CAMERA LENS] set gpio failed!! \n");}
if(mt_set_gpio_out(pinSet[pinSetIdx][IDX_PS_CMRST],pinSet[pinSetIdx][IDX_PS_CMRST+IDX_PS_OFF])){PK_DBG("[CAMERA SENSOR] set gpio failed!! \n");}
if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMRST])
{
//PDN pin
if(mt_set_gpio_mode(pinSet[pinSetIdx][IDX_PS_CMPDN],pinSet[pinSetIdx][IDX_PS_CMPDN+IDX_PS_MODE])){PK_DBG("[CAMERA LENS] set gpio mode failed!! \n");}
if(mt_set_gpio_dir(pinSet[pinSetIdx][IDX_PS_CMPDN],GPIO_DIR_OUT)){PK_DBG("[CAMERA LENS] set gpio dir failed!! \n");}
if(mt_set_gpio_out(pinSet[pinSetIdx][IDX_PS_CMPDN],pinSet[pinSetIdx][IDX_PS_CMPDN+IDX_PS_ON])){PK_DBG("[CAMERA LENS] set gpio failed!! \n");} //sym modify
msleep(3);
//RST pin
if(mt_set_gpio_mode(pinSet[pinSetIdx][IDX_PS_CMRST],pinSet[pinSetIdx][IDX_PS_CMRST+IDX_PS_MODE])){PK_DBG("[CAMERA SENSOR] set gpio mode failed!! \n");}
if(mt_set_gpio_dir(pinSet[pinSetIdx][IDX_PS_CMRST],GPIO_DIR_OUT)){PK_DBG("[CAMERA SENSOR] set gpio dir failed!! \n");}
if(mt_set_gpio_out(pinSet[pinSetIdx][IDX_PS_CMRST],pinSet[pinSetIdx][IDX_PS_CMRST+IDX_PS_OFF])){PK_DBG("[CAMERA SENSOR] set gpio failed!! \n");}
msleep(3);
}
MainCameraDigtalPowerCtrl(0);
if(TRUE != hwPowerDown(CAMERA_POWER_VCAM_A,mode_name)) {
PK_DBG("[CAMERA SENSOR] Fail to OFF analog power\n");
//return -EIO;
goto _kdCISModulePowerOn_exit_;
}
if(TRUE != hwPowerDown(CAMERA_POWER_VCAM_D2,mode_name))
{
PK_DBG("[CAMERA SENSOR] Fail to enable analog power\n");
//return -EIO;
goto _kdCISModulePowerOn_exit_;
}
if(TRUE != hwPowerDown(CAMERA_POWER_VCAM_D, mode_name)) {
PK_DBG("[CAMERA SENSOR] Fail to OFF digital power\n");
//return -EIO;
goto _kdCISModulePowerOn_exit_;
}
}
else
{
mt_set_gpio_mode(GPIO_CAMERA_CMPDN1_PIN, GPIO_CAMERA_CMPDN1_PIN_M_GPIO);
mt_set_gpio_dir(GPIO_CAMERA_CMPDN1_PIN, GPIO_DIR_OUT);
mt_set_gpio_out(GPIO_CAMERA_CMPDN1_PIN, GPIO_OUT_ONE);
mt_set_gpio_mode(GPIO_CAMERA_CMPDN_PIN, GPIO_CAMERA_CMPDN_PIN_M_GPIO);
mt_set_gpio_dir(GPIO_CAMERA_CMPDN_PIN, GPIO_DIR_OUT);
mt_set_gpio_out(GPIO_CAMERA_CMPDN_PIN, GPIO_OUT_ONE);
//RST pin
mt_set_gpio_mode(GPIO_CAMERA_CMRST1_PIN, GPIO_CAMERA_CMRST1_PIN_M_GPIO);
mt_set_gpio_dir(GPIO_CAMERA_CMRST1_PIN, GPIO_DIR_OUT);
mt_set_gpio_out(GPIO_CAMERA_CMRST1_PIN, GPIO_OUT_ONE);
msleep(5);
mt_set_gpio_out(GPIO_CAMERA_CMRST1_PIN, GPIO_OUT_ZERO);
//if (currSensorName && (0 == strcmp(SENSOR_DRVNAME_S5K4ECGX_MIPI_YUV,currSensorName)))
{
MainCameraDigtalPowerCtrl(0);
}
if(TRUE != hwPowerDown(CAMERA_POWER_VCAM_D, mode_name)) {
PK_DBG("[CAMERA SENSOR] Fail to OFF digital power\n");
//return -EIO;
goto _kdCISModulePowerOn_exit_;
}
if(TRUE != hwPowerDown(CAMERA_POWER_VCAM_A,mode_name)) {
PK_DBG("[CAMERA SENSOR] Fail to OFF analog power\n");
//return -EIO;
goto _kdCISModulePowerOn_exit_;
}
if(TRUE != hwPowerDown(CAMERA_POWER_VCAM_D2,mode_name))
{
PK_DBG("[CAMERA SENSOR] Fail to enable analog power\n");
//return -EIO;
goto _kdCISModulePowerOn_exit_;
}
if(TRUE != hwPowerDown(CAMERA_POWER_VCAM_A2,mode_name))
{
PK_DBG("[CAMERA SENSOR] Fail to enable analog power\n");
//return -EIO;
goto _kdCISModulePowerOn_exit_;
}
}
}
以下为一款camera 的上电和掉电图,仅作参考:
上电时序
掉电时序
⑤ 到此为止,配置已经完毕,如果还有问题,很可能是由于驱动代码的问题,因为
厂商提供的驱动不是百分百马上移植就可以用的,出现错误,就要结合自己的硬件平台和camera 的datasheet 对驱动代码做出更改,如果还是解决不了就得找 FAE 了。
⑥编译,烧写,调试
因为整个移植过程我们主要更改了 hal、kernel 目录下的代码,因此我们可以使用快速编译: ./mk v2_e324_2ggsm4_wvga_t62d r lk k bootimage ;接着最后一步,打开falshtools à Scatter-loadingà Mt6572_Android_scatter.txt 加载生成的镜像文件à 手机断电冷启动à 等待烧入(大概1min),之后,拔掉 USB开机,打开camera APK , 可以
拍照,测试 前后camera