最新消息: USBMI致力于为网友们分享Windows、安卓、IOS等主流手机系统相关的资讯以及评测、同时提供相关教程、应用、软件下载等服务。

MTK_camera驱动流程总结_pei

IT圈 admin 27浏览 0评论

2024年5月13日发(作者:森源源)

Camera驱动流程总结

范军君

@

目录

1,Camera架构及流程简析

2,初始化过程cameraid检测

3,Camera上电流程

4,Camera打开流程

Camera

架构及流程简析

MTK平台camera架构:

Kernel部分主要有两块:一块是imagesensor驱动,负责具体型号的sensor的id检测,上

电,以及在preview,capture,初始化,3A等等功能设定时的寄存器配置。另一块是ispdriver,

通过DMA将sensor数据流上传。

本篇主要介绍imagesensor驱动的流程。

HAL层这边主要分3块,一块是imageio,主要是数据buffer上传的pipe。一块是drv,包

含imgsensor和isp的hal层控制。最后是featureio,包含各种3A等性能配置。

本篇对HAL涉入不深,只在分析开机过程的id检测时会分析hal层的控制,属于第二块。

流程简析:

主要发生在两个时间点:开机过程中camera的动作以及打开应用时camera的动作。

开机时,camera完成了sensor框架的初始化,id检测,以及上下电操作。

打开应用时,camera会有上电,完成寄存器的初始配置,向上层传送基本参数及配置信息,

以及preview和capture模式循环。

初始化过程

cameraid

检测

代码分析:

=>alps/mediatek/custom/common/kernel/imgsensor/kd_sensorlist.c

module_init说明这段code在kernel初始化,也就是手机开机时运行。

在模块初始化函数中,注册一个i2cdevice,同时注册了一个platformdriver

本页已使用福昕阅读器进行编辑。

福昕软件(C)2005-2009,版权所有,

仅供试用。

注意drivername,匹配platformdevice需要名字一致。Platform总线为虚拟总线,注册

platformdriver主要目的是隔离上下层,增强代码的可移植性。

alps/mediatek/platform/mt6582/kernel/core/mt_dev.c

mtk平台用到的platformdevicej基本都在这个文件中注册,这样device和driver就能匹配上

了。

在platformprobe中注册i2cdriver和之前的i2cdevice匹配

配置i2cclock,注册一个字符设备。一般驱动中注册字符设备,多是利用字符设备的fops

与上层交互,特别是ioctl.

这些就是具体的fops

open只是用来计数目前打开camera的数量,所以主要的交互功能要靠ioctl来完成

这个函数很重要,沟通上下层,提供接口。这边的Command用幻字定义,可以保持cmd

的唯一性,并具备可读性。Command可带不定长参数。

下面是switchcase,通过ioctl传下来的参数选择调用分支

本页已使用福昕阅读器进行编辑。

福昕软件(C)2005-2009,版权所有,

仅供试用。

支持的command汇总,包括camera开机过程中上电,id检测以及imagesensor的参数获取

KDIMGSENSORIOC_X_SET_DRIVER和KDIMGSENSORIOC_T_CHECK_IS_ALIVE这

两个func在开机初始化检测id会被hal层调用。

=>mediatek/platform/mt6582/hardware/camera/core/drv/imgsensor/imgsensor_

impSearchSensor在开机过程中被调用,用于检测id,匹配main/subimagesensor

GetSensooInitFuncList这个函数主要为了获得下表

包含了id,name和一些方法的调用,因为在driver层有相似的架构,放在后面分析具体过程。

=>impSearchSensor

Hal层开始探测sensor,应为有两颗sensor,外层循环两次

内层循环根据上面的sensor列表来,最大支持兼容16颗sensor,hal层特效,如果没有整合

特定imagesensor的hal层代码,这边会直接退出。

getCameraDefault调用很重要,hal层camera的所有特效参数,包括3A,shading都在这边设

定。getCameraDefault通过之前的Sensorlist来连接特定imagesensor的具体实现。下表是2675

的特效参数获取函数。

获取各项特项参数

=>impSearchSensor

Ioctl向驱动层下command,注意下下传的id就是目前正在检测的imgsensor的id.终于又回

到了kd_sensorlist.c这个文件

下层的ioctl接口

现在的情况是,针对mainsensor,hal层遍历上层的sensor列表,然后call下层的kdSetDriver.

kdGetSensorList这个函数似曾相识。

这个函数很有意思,用了指向指针的指针作为参数。有兴趣可以思考下不直接使用普通指针

的原因,涉及堆栈和编译器对函数传参的处理。

指向结构体的指针,最后一个成员很重要,是一个函数指针,其参数是函数指针的结构体指

针。

上层传下来的id参数解析成两部分g_invokeSocketIdx区分目前正在匹配的是main还是

sub,drvIdx是sensor列表的序列号。

Hal层和driver层的sensorlist应该在顺序上保持一致。

函数指针的结构体指针,这些函数对应了具体imagesensor的操作,看如何挂接上具体sensor。

还是由sensorlist为函数指针赋值,挂接具体SensorInit

2675的SensorInit实现,主要是为pfFunc这个函数指针的结构体指针赋值,这样我们就实

现了驱动代码的分离,hal层只需调用Sensorlist.c这样一个虚拟设备的驱动,就可以和具体

的SensorDriver通信。这样的做法与platformdriver的设计思想一致,在lcm,传感器等驱动

中也多有体现。

到这一步,hal层在做Searchsensor时的第一步命令的setdriver的目的已经很清晰,就是为

了挂接正在遍历的sensor的具体接口。

回到Hal层,还是Searchsensor的这个函数

对于正在遍历的这颗sensor,已经挂街上具体的底层驱动接口了,那么下达checkid的真正

指令。

底层的ioctl接口

第一步是上电Poweron,这块稍后会有具体分析。

这块code,就是读id了,调用之前挂接的具体sensor的Featurecontrol,并带参。

2675的具体featurecontrol,诸多功能通过switch罗列在这边。

读id一般在开机和打开sensor时做,读之前软件resetsensor,保证所读取的id的正确性。

Ov一般都用300A和300B这两个register保存id。

读到id后和预先设定的ID作比较

如果一致,那么我们就找到了匹配到了要找的sensor,因为有前后摄,所以这样的动作要做

两。

这边还有个问题被忽略了,读id是通过i2c通信,各家sensor的i2caddr显然都不一样。

imagesensor因为采取了驱动代码的分层设计,i2cdevice的注册时放在sensorlist中的,在

moduleinit的时候已经注册,也指定了i2caddr为0xfe。那怎么和不同的sensor通信的呢

实际的i2c通信前,对i2caddr重新赋值,kd_Sensorlist.c中的0xfe只是为了应付注册。

读完id并没有结束,因为现在还在手机开机初始化阶段,并不是打开camera应用,我们

check完id,一定要给sensor下电

匹配上id后又回到了hal层,id不对的ioctl的returnerr<0.

HAL代码

匹配上的sensor则继续下传cmd,获取一些sensor的信息和配置,流程与之前的id检测类

似,不展开。

这边预留了一个extraid的接口,主要用于区分同型号不同模组厂的sensor,通过读取指定

寄存器中厂商烧录的value来做二次id判断,以兼容不同厂商的sensor,此处为空.当然extra

id也完全可以只在driver层添加,加在初次id检测后即可。

close仅为历史遗留代码,无实际作用。

开机过程中的ID检测流程已全部给出,总结一下:

HAL层运行Searchsensor这个线程

HAL层遍历sensorlist并挂接HAL层性能如3A等一些参数获取的接口

HAL层下达setDriver的cmd,并下传正在遍历的sensor在sensorlist列表中的id

Driver层根据这个id,挂接Driver层sensorlist中对应的Sensor和具体Sensor底层操作

接口

HAL层对正在遍历的sensor下达checkid的指令

Driver层为对应sensor上电,通过i2c读取预存在寄存器中的sensorid

比较读取结果,不匹配,returnerror,继续遍历。

匹配,HAL层下达其他指令收集sensor信息

下电

Camera上电流程

Camera的供电和相关引脚

电源部分:

VCAMD就是DVDD数字供电,主要给ISP供电,如果是RAWDATA格式的sensor其

ISP是在BB端,所以将其引脚将其NC;

VCAM_IO就是VDDIO数字IO电源主要给I2C部分供电;

VCAMA就是AVDD模拟供电,主要给感光区和ADC部分供电;

VCAM_AF是对Camera自动对焦马达的供电

引脚部分:

Reset引脚和powerdown引脚

代码部分:

Camera在初始化和打开的时候均有上电动作,这边以初始化部分的代码分析这块流程。

之前没有详细分析的上电代码。

kdCISModulePowerOn这个函数的实现在kd_camera_hw.c里面

=>kd_camera_hw.c

这个文件是MTK专门用于sensor上电时序管理的文件,各个sensor的上电均在这边实现。

首先是引脚定义,包括模式和引脚的极性

这边pinSetIdx可以反过来,这样就变成默认打开前摄了,现在是rearcamera优先

上电的具体时序应该参考各个sensor的datasheet,下面是ov2675的上电时序图

看图,首先使能pdn引脚然后开电,dovdd->avdd->dvdd

Poweroff,使能reset

这边的开电顺序是有些问题的,按spec应该先D2再A再D,A2是供给AF的,属于马

达部分,先后无所谓。虽然这样子顺序上电实际也没问题,但可能存在风险。

还有一点,就是记得按datasheet的要求加上delay

开电以后就可以拉pin脚上电了,注意一下这个sensor的pin脚极性和之前表中定义的相反

在dualcamera的方案中,因为共有一组电源,所以在打开某一个sensor的时候,通常要disable

另一个的pin脚以防止漏电。

下电流程可以参考spec自行分析

Camera打开流程:

看下打开Camera后,HAL层的代码流程

=>sensor_

CreateInstance,看下pSensorDrvd的类。

=>sensor_

这边拿到了我们之前分析过的imgsensor_中的实例,因此和ImgSensorDrv的方法挂

接上了。

继续看之前的初始化代码

这个switch是检查之前的sensorsearch有没有成功,然后调用impsensor_中的init

=>impsensor_

还是通过ioctl下传cmd调底层接口。不赘述了。

最终调用2675中的接口,注意PV和CP模式下的分辨率,通常不一样,PV的帧数因此更

高,而capture则更清晰。

=>imgsensor_

获取更多的信息,最多通过2675的接口读寄存器实现,不一一列举了。ImgSensorDrv的初

始化也结束了,还没有见到open的代码

=>sensor_

先看getSensorInfo的实现。

看一下getinfo里面主要的调用

其中getInfo比较重要,直接贴底层对应的接口。

和之前直接从寄存器收集到得信息不同,这边的值是驱动可以修改的,比如进入preview和

capture需要delay的帧数,clock的极性等等。

getCurrentSensorType就是看一下sensor输出数据的类型。

再往下setTgphasesetSensorIOcurrentinitCSI2peripheralsetCSI2config,这些就是和数据

流传送对应的硬件驱动配置的hal接口了,TG是时间触发器,CSI2config指CameramipiBB

端的总线配置。

可以参考这张数据流的图示

终于到打开了,还是调用imgsensor_的接口

=>imgsensor_

熟悉的ioctl,直接贴2675的接口

再读次id,之前先软件reset。然后就是几千个寄存器的初始化,打开camera,会延迟一段

时间就是这边的缘故。

打开sensor后,将进入preview,这边的上层调用没有具体分析,通过抓底层接口的log,看

下有哪些操作。

先看下open前的,对照下刚才分析的打开流程,查看下调用时序。

featurecontrol的id如下

基本一致,再看看preview前的

上层调用,有很多底层并未去实现,preview前主要在调用yuvsetting这块

主要是一些特效设定,便于在preview时通过apk里的设置项来调整

上层可以调ioctl切换preview和capture模式,preview的入口

Imgsensor端preview的接口主要是寄存器的配置,包括clock,size,AE调整等,capture的与

之类似。

贴下preview的流程图:

包括:

3A的实时调整

Pass1,pass2是MTK架构buffer的传递过程,buffer1主要是指硬件buffer的传递,buffer2

是软件buffer的传递。

各层次preview回调

退出切换模式时退出loop

2024年5月13日发(作者:森源源)

Camera驱动流程总结

范军君

@

目录

1,Camera架构及流程简析

2,初始化过程cameraid检测

3,Camera上电流程

4,Camera打开流程

Camera

架构及流程简析

MTK平台camera架构:

Kernel部分主要有两块:一块是imagesensor驱动,负责具体型号的sensor的id检测,上

电,以及在preview,capture,初始化,3A等等功能设定时的寄存器配置。另一块是ispdriver,

通过DMA将sensor数据流上传。

本篇主要介绍imagesensor驱动的流程。

HAL层这边主要分3块,一块是imageio,主要是数据buffer上传的pipe。一块是drv,包

含imgsensor和isp的hal层控制。最后是featureio,包含各种3A等性能配置。

本篇对HAL涉入不深,只在分析开机过程的id检测时会分析hal层的控制,属于第二块。

流程简析:

主要发生在两个时间点:开机过程中camera的动作以及打开应用时camera的动作。

开机时,camera完成了sensor框架的初始化,id检测,以及上下电操作。

打开应用时,camera会有上电,完成寄存器的初始配置,向上层传送基本参数及配置信息,

以及preview和capture模式循环。

初始化过程

cameraid

检测

代码分析:

=>alps/mediatek/custom/common/kernel/imgsensor/kd_sensorlist.c

module_init说明这段code在kernel初始化,也就是手机开机时运行。

在模块初始化函数中,注册一个i2cdevice,同时注册了一个platformdriver

本页已使用福昕阅读器进行编辑。

福昕软件(C)2005-2009,版权所有,

仅供试用。

注意drivername,匹配platformdevice需要名字一致。Platform总线为虚拟总线,注册

platformdriver主要目的是隔离上下层,增强代码的可移植性。

alps/mediatek/platform/mt6582/kernel/core/mt_dev.c

mtk平台用到的platformdevicej基本都在这个文件中注册,这样device和driver就能匹配上

了。

在platformprobe中注册i2cdriver和之前的i2cdevice匹配

配置i2cclock,注册一个字符设备。一般驱动中注册字符设备,多是利用字符设备的fops

与上层交互,特别是ioctl.

这些就是具体的fops

open只是用来计数目前打开camera的数量,所以主要的交互功能要靠ioctl来完成

这个函数很重要,沟通上下层,提供接口。这边的Command用幻字定义,可以保持cmd

的唯一性,并具备可读性。Command可带不定长参数。

下面是switchcase,通过ioctl传下来的参数选择调用分支

本页已使用福昕阅读器进行编辑。

福昕软件(C)2005-2009,版权所有,

仅供试用。

支持的command汇总,包括camera开机过程中上电,id检测以及imagesensor的参数获取

KDIMGSENSORIOC_X_SET_DRIVER和KDIMGSENSORIOC_T_CHECK_IS_ALIVE这

两个func在开机初始化检测id会被hal层调用。

=>mediatek/platform/mt6582/hardware/camera/core/drv/imgsensor/imgsensor_

impSearchSensor在开机过程中被调用,用于检测id,匹配main/subimagesensor

GetSensooInitFuncList这个函数主要为了获得下表

包含了id,name和一些方法的调用,因为在driver层有相似的架构,放在后面分析具体过程。

=>impSearchSensor

Hal层开始探测sensor,应为有两颗sensor,外层循环两次

内层循环根据上面的sensor列表来,最大支持兼容16颗sensor,hal层特效,如果没有整合

特定imagesensor的hal层代码,这边会直接退出。

getCameraDefault调用很重要,hal层camera的所有特效参数,包括3A,shading都在这边设

定。getCameraDefault通过之前的Sensorlist来连接特定imagesensor的具体实现。下表是2675

的特效参数获取函数。

获取各项特项参数

=>impSearchSensor

Ioctl向驱动层下command,注意下下传的id就是目前正在检测的imgsensor的id.终于又回

到了kd_sensorlist.c这个文件

下层的ioctl接口

现在的情况是,针对mainsensor,hal层遍历上层的sensor列表,然后call下层的kdSetDriver.

kdGetSensorList这个函数似曾相识。

这个函数很有意思,用了指向指针的指针作为参数。有兴趣可以思考下不直接使用普通指针

的原因,涉及堆栈和编译器对函数传参的处理。

指向结构体的指针,最后一个成员很重要,是一个函数指针,其参数是函数指针的结构体指

针。

上层传下来的id参数解析成两部分g_invokeSocketIdx区分目前正在匹配的是main还是

sub,drvIdx是sensor列表的序列号。

Hal层和driver层的sensorlist应该在顺序上保持一致。

函数指针的结构体指针,这些函数对应了具体imagesensor的操作,看如何挂接上具体sensor。

还是由sensorlist为函数指针赋值,挂接具体SensorInit

2675的SensorInit实现,主要是为pfFunc这个函数指针的结构体指针赋值,这样我们就实

现了驱动代码的分离,hal层只需调用Sensorlist.c这样一个虚拟设备的驱动,就可以和具体

的SensorDriver通信。这样的做法与platformdriver的设计思想一致,在lcm,传感器等驱动

中也多有体现。

到这一步,hal层在做Searchsensor时的第一步命令的setdriver的目的已经很清晰,就是为

了挂接正在遍历的sensor的具体接口。

回到Hal层,还是Searchsensor的这个函数

对于正在遍历的这颗sensor,已经挂街上具体的底层驱动接口了,那么下达checkid的真正

指令。

底层的ioctl接口

第一步是上电Poweron,这块稍后会有具体分析。

这块code,就是读id了,调用之前挂接的具体sensor的Featurecontrol,并带参。

2675的具体featurecontrol,诸多功能通过switch罗列在这边。

读id一般在开机和打开sensor时做,读之前软件resetsensor,保证所读取的id的正确性。

Ov一般都用300A和300B这两个register保存id。

读到id后和预先设定的ID作比较

如果一致,那么我们就找到了匹配到了要找的sensor,因为有前后摄,所以这样的动作要做

两。

这边还有个问题被忽略了,读id是通过i2c通信,各家sensor的i2caddr显然都不一样。

imagesensor因为采取了驱动代码的分层设计,i2cdevice的注册时放在sensorlist中的,在

moduleinit的时候已经注册,也指定了i2caddr为0xfe。那怎么和不同的sensor通信的呢

实际的i2c通信前,对i2caddr重新赋值,kd_Sensorlist.c中的0xfe只是为了应付注册。

读完id并没有结束,因为现在还在手机开机初始化阶段,并不是打开camera应用,我们

check完id,一定要给sensor下电

匹配上id后又回到了hal层,id不对的ioctl的returnerr<0.

HAL代码

匹配上的sensor则继续下传cmd,获取一些sensor的信息和配置,流程与之前的id检测类

似,不展开。

这边预留了一个extraid的接口,主要用于区分同型号不同模组厂的sensor,通过读取指定

寄存器中厂商烧录的value来做二次id判断,以兼容不同厂商的sensor,此处为空.当然extra

id也完全可以只在driver层添加,加在初次id检测后即可。

close仅为历史遗留代码,无实际作用。

开机过程中的ID检测流程已全部给出,总结一下:

HAL层运行Searchsensor这个线程

HAL层遍历sensorlist并挂接HAL层性能如3A等一些参数获取的接口

HAL层下达setDriver的cmd,并下传正在遍历的sensor在sensorlist列表中的id

Driver层根据这个id,挂接Driver层sensorlist中对应的Sensor和具体Sensor底层操作

接口

HAL层对正在遍历的sensor下达checkid的指令

Driver层为对应sensor上电,通过i2c读取预存在寄存器中的sensorid

比较读取结果,不匹配,returnerror,继续遍历。

匹配,HAL层下达其他指令收集sensor信息

下电

Camera上电流程

Camera的供电和相关引脚

电源部分:

VCAMD就是DVDD数字供电,主要给ISP供电,如果是RAWDATA格式的sensor其

ISP是在BB端,所以将其引脚将其NC;

VCAM_IO就是VDDIO数字IO电源主要给I2C部分供电;

VCAMA就是AVDD模拟供电,主要给感光区和ADC部分供电;

VCAM_AF是对Camera自动对焦马达的供电

引脚部分:

Reset引脚和powerdown引脚

代码部分:

Camera在初始化和打开的时候均有上电动作,这边以初始化部分的代码分析这块流程。

之前没有详细分析的上电代码。

kdCISModulePowerOn这个函数的实现在kd_camera_hw.c里面

=>kd_camera_hw.c

这个文件是MTK专门用于sensor上电时序管理的文件,各个sensor的上电均在这边实现。

首先是引脚定义,包括模式和引脚的极性

这边pinSetIdx可以反过来,这样就变成默认打开前摄了,现在是rearcamera优先

上电的具体时序应该参考各个sensor的datasheet,下面是ov2675的上电时序图

看图,首先使能pdn引脚然后开电,dovdd->avdd->dvdd

Poweroff,使能reset

这边的开电顺序是有些问题的,按spec应该先D2再A再D,A2是供给AF的,属于马

达部分,先后无所谓。虽然这样子顺序上电实际也没问题,但可能存在风险。

还有一点,就是记得按datasheet的要求加上delay

开电以后就可以拉pin脚上电了,注意一下这个sensor的pin脚极性和之前表中定义的相反

在dualcamera的方案中,因为共有一组电源,所以在打开某一个sensor的时候,通常要disable

另一个的pin脚以防止漏电。

下电流程可以参考spec自行分析

Camera打开流程:

看下打开Camera后,HAL层的代码流程

=>sensor_

CreateInstance,看下pSensorDrvd的类。

=>sensor_

这边拿到了我们之前分析过的imgsensor_中的实例,因此和ImgSensorDrv的方法挂

接上了。

继续看之前的初始化代码

这个switch是检查之前的sensorsearch有没有成功,然后调用impsensor_中的init

=>impsensor_

还是通过ioctl下传cmd调底层接口。不赘述了。

最终调用2675中的接口,注意PV和CP模式下的分辨率,通常不一样,PV的帧数因此更

高,而capture则更清晰。

=>imgsensor_

获取更多的信息,最多通过2675的接口读寄存器实现,不一一列举了。ImgSensorDrv的初

始化也结束了,还没有见到open的代码

=>sensor_

先看getSensorInfo的实现。

看一下getinfo里面主要的调用

其中getInfo比较重要,直接贴底层对应的接口。

和之前直接从寄存器收集到得信息不同,这边的值是驱动可以修改的,比如进入preview和

capture需要delay的帧数,clock的极性等等。

getCurrentSensorType就是看一下sensor输出数据的类型。

再往下setTgphasesetSensorIOcurrentinitCSI2peripheralsetCSI2config,这些就是和数据

流传送对应的硬件驱动配置的hal接口了,TG是时间触发器,CSI2config指CameramipiBB

端的总线配置。

可以参考这张数据流的图示

终于到打开了,还是调用imgsensor_的接口

=>imgsensor_

熟悉的ioctl,直接贴2675的接口

再读次id,之前先软件reset。然后就是几千个寄存器的初始化,打开camera,会延迟一段

时间就是这边的缘故。

打开sensor后,将进入preview,这边的上层调用没有具体分析,通过抓底层接口的log,看

下有哪些操作。

先看下open前的,对照下刚才分析的打开流程,查看下调用时序。

featurecontrol的id如下

基本一致,再看看preview前的

上层调用,有很多底层并未去实现,preview前主要在调用yuvsetting这块

主要是一些特效设定,便于在preview时通过apk里的设置项来调整

上层可以调ioctl切换preview和capture模式,preview的入口

Imgsensor端preview的接口主要是寄存器的配置,包括clock,size,AE调整等,capture的与

之类似。

贴下preview的流程图:

包括:

3A的实时调整

Pass1,pass2是MTK架构buffer的传递过程,buffer1主要是指硬件buffer的传递,buffer2

是软件buffer的传递。

各层次preview回调

退出切换模式时退出loop

发布评论

评论列表 (0)

  1. 暂无评论