本帖最后由 星空 于 2021-6-25 14:18 编辑
1 camera 硬件通识
1.1 camera模组介绍
(1)工作原理
物体通过镜头(lens)聚集的光,通过CMOS或CCD集成电路,把光信号转换成电信号,再经过内部图像处理器(ISP)转换成数字图像信号输出到数字信号处理器(DSP)加工处理,转换成标准的GRB、YUV等格式图像信号、 (2) CCM 包含四大件: 镜头(lens)、传感器(sensor)、软板((FPC)、图像处理芯片(DSP) 。决定一个摄像头好坏的重要部件是:镜头(lens)、图像处理芯片 (DSP)、传感器(sensor)。 镜头(lens)是相机的灵魂,镜头(lens)对成像的效果有很重要的作用,是利用透镜的折射原理,景物光线通过镜头,在聚焦平面上形成清晰的影像,通过感光材料CMOS或CCD感光器记录景物的影像。 传感器(sensor)是 CCM 的核心模块,目前广泛使用的有两种:一种是广泛使用的CCD(电荷藕合)元件;另一种是CMOS(互补金属氧化物导体)器件。 图像处理芯片(DSP)是 CCM 的重要组成部分,它的作用是将感光芯片获得的数据及时快速地传递到中央处理器并刷新感光芯片,因此DSP芯片的好坏,直接影响画面品质(比如色彩饱和度,清晰度等)。 (3) 图像的输出格式 A、YUV “Y” 表示明亮度(Luminance、Luma), “U” 和 “V” 则是色度、浓度(Chrominance、Chroma), 一般情况下sensor支持YUV422格式,即数据格式是按Y-U-Y-V次序输出的。 B、JPEG 作为一种存储格式它是非常普遍的,但是作为sensor的输出格式的话,一般是低分辨率的,其自带JPEG engine,可以直接输出压缩后的jpg格式的数据; C、RGB 传统的红绿蓝格式,比如RGB565。通俗点说它的颜色混合方式就好像有红、绿、蓝三盏灯,当它们的光相互叠合的时候,色彩相混,而亮度却等于两者亮度之总和,越混合亮度越高,即加法混合; D、RAW 图像感应器将捕捉到的光源信号转化为数字信号的原始数据。RAW文件是一种记录了数码相机传感器的原始信息,同时记录了由相机拍摄所产生的一些原数据( Metadata,如ISO的设置、快门速度、光圈值、白平衡等)的文件。 RAW是未经处理、也未经压缩的格式,可以把RAW概念化为“原始图像编码数据”或更形象的称为“数字底片”。 不同的输出格式,包含的数据大小不同: 首先,如果说数据量最小,那么莫过于RAW格式,但是,数据传输过来要经过一次性大量的计算才能将里面的信息提取出来,如果你想用,一般5M以上sensor就只输出RAW数据以保证比较快的输出速度,后端挂一个DSP来处理输出的数据。其次是JPEG,数据量也很小,但是同样要求较快的处理速度。而RGB和YUV一个像素都是占用了2B的大小,但是RGB却可以将数据读出来后直接刷到屏上,为什么却要选择YUV的呢? 原因在于YUV输出亮度信号没有任何损失,而色偏信号人眼并不是特别敏感,RGB565输出格式是R5G3 G3B5会丢掉很多原始信息,所以YUV图像质量和稳定性要比RGB565好的多。 这就是为什么像素高的摄像头为什么都是raw格式的
(4) 传感器尺寸和画质的关系
传感器尺寸大小对于画质的影响,其实跟之前一样,就是采集的光线数据的正确性和完整性的不同。在像素相同的情况下:
A、 传感器面积越大,感光阵列的面积就越大,相邻感光电路的距离就越大,加电时产生的电磁干扰就越小;
B、 传感器面积越大,感光阵列的面积就越大,对应单个像素的透镜就能做的越大,聚集到的光线就越多,感光二极管受光后产生的输出电平就越高。假设噪声大小不变,那么更大的有用输出电平,带来更高的信噪比,转换后的信息处理时正确率就越高;
C、 为什么在光线非常好的时候,传感器尺寸大小间的差异会缩小? 因为即使传感器尺寸小,但是光线强度足够,每个感光二极管都能受到足够的光线,产生的信噪比就大,噪点也就缩小了。
1.2 硬件接口
(1) 三路电压AVDD/DVDD/IOVDD:
AVDD模拟电源,主要给感光区和ADC供电,要求比较干净;
DVDD数字电源,主要是给ISP供电;
IOVDD数字IO电源,给I2C和DVP供电。
(2) PDN/RST:
RST:用来reset sensor;RESET一般是低电平有效,当脉冲为低电平时,reset sensor,而正常工作时,应该设置为高电平。
复位时序时序通常是: 高 –> 低 –> 高,根据硬件需要加一定的延时;
PWN:PWN一般高有效,当脉冲为高电平时,进入省电模式,而正常工作时为低电平。高电平时,一切对camera的操作都是无效的,包括复位。所以在RST之前,一定要将PWN管脚设置为正常工作模式(低电平),否则复位无效。
(3) I2C 控制接口SCL/SDA
(4) MCLK 时钟用于分频给其他的clk使用;
(5) mipi 接口RCP/RCN、RDP/RDN 时钟信号
2 camera 软件通识
(1) 控制信号是i2ci2c 不通的原因有两种
(1) 一种是device端(sensor device)本身就没有回ACK,表现为I2C_ACKERR,大多是slave(从设备)问题,从设备上电是否符合SPEC等;
(2) 一种就是问题出在在master端(我们的CPU),表现为I2C_TIMEOUT,每2S timeout一次,出现I2C_TIMEOUT典型之一,在I2C bus没有上电的情况下去操作I2C,如: camera powerOff >>> Write/Read I2C
(2) 图像信号是mipi
具体要看mipi通信协议
3 驱动框架结构
MTK camera主要的内容在hal层,现在有hal1/hal3,当下主流的使用的是hal3,驱动主要负责sensor电源的控制以及sensor相关寄存器的操作,MTK采用设备和驱动分离的思想,抽象出imgsensor.c来控制sensor的上下电以及sensor具体的操作.
1 sensor driver
sensor driver对上响应需求,对下控制sensor硬件行为,处理器通过I2C接口来控制sensor的大部分行为,sensor输出的数据传输到TG、ISP等模块处理后,ISP将数据保存到内存中之后,才可以dump出sensor的数据,才能看到sensor的第一帧画面。
(1)
imgsensor_mode_struct不同模式特征的结构体
这个结构体描叙了各个模式下的pclk/linelength/framelength 等
- typedef struct imgsensor_mode_struct {
- kal_uint32 pclk; //record different mode's pclk
- kal_uint32 linelength; //record different mode's linelength
- kal_uint32 framelength; //record different mode's framelength
- kal_uint8 startx; //record different mode's startx of grabwindow
- kal_uint8 starty; //record different mode's startx of grabwindow
- kal_uint16 grabwindow_width; //record different mode's width of grabwindow
- kal_uint16 grabwindow_height; //record different mode's height of grabwindow
- /* following for MIPIDataLowPwr2HighSpeedSettleDelayCount by different scenario */
- kal_uint8 mipi_data_lp2hs_settle_dc;
- /* following for GetDefaultFramerateByScenario() */
- kal_uint16 max_framerate;
- kal_uint32 mipi_pixel_rate;
- } imgsensor_mode_struct;
复制代码
对应的描叙信息如下:pclk ≈ linelength * frame_length * framerate
- static kal_uint32 set_max_framerate_by_scenario(MSDK_SCENARIO_ID_ENUM scenario_id, MUINT32 framerate)
- {
- kal_uint32 frame_length;
- pr_info("scenario_id = %d, framerate = %d\n", scenario_id, framerate);
- switch (scenario_id) {
- case MSDK_SCENARIO_ID_CAMERA_PREVIEW:
- frame_length = imgsensor_info.pre.pclk / framerate * 10 / imgsensor_info.pre.linelength;
- spin_lock(&imgsensor_drv_lock);
- imgsensor.dummy_line = (frame_length > imgsensor_info.pre.framelength) ? (frame_length - imgsensor_info.pre.framelength) : 0;
- imgsensor.frame_length = imgsensor_info.pre.framelength + imgsensor.dummy_line;
- imgsensor.min_frame_length = imgsensor.frame_length;
- spin_unlock(&imgsensor_drv_lock);
- //set_dummy();
- break;
复制代码
Sensor的linelength是固定的,每个模式的pclk也是不可调的,所以要调整帧率framerate,只能调整frame_length。set_dummy使得当前帧率立刻变化为设置的帧率,如果pclk或者linelength与对应sensor setting的实际值不一致,设置的帧率和响应的帧率会有一个偏差,画面可能出现水波纹。
注意:如果打开摄像头黑屏,帧率不对,这里需要重点查下
(2)imgsensor_info_struct
struct imgsensor_info_struct描叙sensor info常量的结构体
- static imgsensor_info_struct imgsensor_info = {
- .sensor_id = IMX230_SENSOR_ID, //record sensor id defined in Kd_imgsensor.h
- .checksum_value = 0xafd83a68, //checksum value for Camera Auto Test
- .pre = {
- .pclk = 381000000, //record different mode's pclk
- .linelength = 6024, //record different mode's linelength
- .framelength = 2108, //record different mode's framelength
- .startx = 0, //record different mode's startx of grabwindow
- .starty = 0, //record different mode's starty of grabwindow
- .grabwindow_width = 2672, //record different mode's width of grabwindow
- .grabwindow_height = 2008, //record different mode's height of grabwindow
- /* following for MIPIDataLowPwr2HighSpeedSettleDelayCount by different scenario */
- .mipi_data_lp2hs_settle_dc = 85,//unit , ns
- /* following for GetDefaultFramerateByScenario() */
- .max_framerate = 300,
- .mipi_pixel_rate = 188000000,
- },
- .cap = {
- .pclk = 597000000,
- .linelength = 6024,
- .framelength = 4128,
- .startx = 0,
- .starty = 0,
- .grabwindow_width = 5344,
- .grabwindow_height = 4016,
- .mipi_data_lp2hs_settle_dc = 85,//unit , ns
- .max_framerate = 240,
- .mipi_pixel_rate = 561920000,
- },
-
- .margin = 4, //sensor framelength & shutter margin
- .min_shutter = 1, //min shutter
- .max_frame_length = 0x7fff,//max framelength by sensor register's limitation
- .ae_shut_delay_frame = 0, //shutter delay frame for AE cycle, 2 frame with ispGain_delay-shut_delay=2-0=2
- .ae_sensor_gain_delay_frame = 0,//sensor gain delay frame for AE cycle,2 frame with ispGain_delay-sensor_gain_delay=2-0=2
- .ae_ispGain_delay_frame = 2,//isp gain delay frame for AE cycle
- .ihdr_support = 0, //1, support; 0,not support
- .ihdr_le_firstline = 0, //1,le first ; 0, se first
- .sensor_mode_num = 5, //support sensor mode num
- .cap_delay_frame = 1, //enter capture delay frame num
- .pre_delay_frame = 1, //enter preview delay frame num
- .video_delay_frame = 1, //enter video delay frame num
- .hs_video_delay_frame = 3, //enter high speed video delay frame num
- .slim_video_delay_frame = 3,//enter slim video delay frame num
- .isp_driving_current = ISP_DRIVING_8MA, //mclk driving current <span style="color: rgb(171, 178, 191); font-family: "Source Code Pro", "DejaVu Sans Mono", "Ubuntu Mono", "Anonymous Pro", "Droid Sans Mono", Menlo, Monaco, Consolas, Inconsolata, Courier, monospace, "PingFang SC", "Microsoft YaHei", sans-serif; font-variant-ligatures: common-ligatures; white-space: pre; background-color: rgb(40, 44, 52);"> </span><span class="token comment" style="box-sizing: border-box; outline: 0px; overflow-wrap: normal; color: rgb(92, 99, 112); word-break: break-all; white-space: pre; font-style: italic !important; font-variant-numeric: normal !important; font-variant-east-asian: normal !important; font-stretch: normal !important; line-height: normal !important; font-family: "Source Code Pro", "DejaVu Sans Mono", "Ubuntu Mono", "Anonymous Pro", "Droid Sans Mono", Menlo, Monaco, Consolas, Inconsolata, Courier, "PingFang SC", "Microsoft YaHei", sans-serif !important;">//</span><span class="token comment" style="box-sizing: border-box; outline: 0px; overflow-wrap: normal; word-break: break-all; white-space: pre; font-style: italic !important; font-variant-numeric: normal !important; font-variant-east-asian: normal !important; font-stretch: normal !important; line-height: normal !important; font-family: "Source Code Pro", "DejaVu Sans Mono", "Ubuntu Mono", "Anonymous Pro", "Droid Sans Mono", Menlo, Monaco, Consolas, Inconsolata, Courier, "PingFang SC", "Microsoft YaHei", sans-serif !important;"><font color="#ff0000">isp驱动电流,电流过大可能会射频干扰</font></span>
- .sensor_interface_type = SENSOR_INTERFACE_TYPE_MIPI,//sensor_interface_type
- .mipi_sensor_type = MIPI_OPHY_NCSI2, //0,MIPI_OPHY_NCSI2; 1,MIPI_OPHY_CSI2
- .mipi_settle_delay_mode = MIPI_SETTLEDELAY_AUTO,//0,MIPI_SETTLEDELAY_AUTO; 1,MIPI_SETTLEDELAY_MANNUAL
- .sensor_output_dataformat = SENSOR_OUTPUT_FORMAT_RAW_R,//sensor output first pixel color
- .mclk = 24,//mclk value, suggest 24 or 26 for 24Mhz or 26Mhz
- .mipi_lane_num = SENSOR_MIPI_4_LANE,//mipi lane num
- .i2c_addr_table = {0x34,0x20,0xff},//record sensor support all write id addr, only supprt 4must end with 0xff
- };
复制代码
(3)struct imgsensor_struct记录sensor info变量的结构体,用于动态的保存sensor的关键信息
- typedef struct imgsensor_struct {
- kal_uint8 mirror; //mirrorflip information
- kal_uint8 sensor_mode; //record IMGSENSOR_MODE enum value
- kal_uint32 shutter; //current shutter
- kal_uint16 gain; //current gain
- kal_uint32 pclk; //current pclk
- kal_uint32 frame_length; //current framelength
- kal_uint32 line_length; //current linelength
- kal_uint32 min_frame_length; //current min framelength to max framerate
- kal_uint16 dummy_pixel; //current dummypixel
- kal_uint16 dummy_line; //current dummline
- kal_uint16 current_fps; //current max fps
- kal_bool autoflicker_en; //record autoflicker enable or disable
- kal_bool test_pattern; //record test pattern mode or not
- MSDK_SCENARIO_ID_ENUM current_scenario_id;//current scenario id
- kal_uint8 ihdr_en; //ihdr enable or disable
- kal_uint8 i2c_write_id; //record current sensor's i2c write id
- } imgsensor_struct;
复制代码
2 驱动入口xxxx_MIPI_RAW_SensorInit
可以看到SensorInit以函数指针的形式传入到kdSensorList结构体中:
4 camera启动流程
5 camera 打开流程
6 camera 移植过程
|