作者:邹南,华清远见嵌入式学院讲师。
CAMERA SENSOR
OV9650/9655是CMOS接口的图像传感器芯片,可以感知外部的视觉信号并将其转换为数字信号并输出。通过下面的框图可以清晰的看到它的工作原理:
我们需要通过XVCLK1给摄像头提供时钟,RESET是复位线,PWDN在摄像头工作时应该始终为低。HREF是行参考信号,PCLK是像素时钟,VSYNC是场同步信号。一旦给摄像头提供了时钟,并且复位摄像头,摄像头就开始工作了,通过HREF,PCLK和VSYNC同步传输数字图像信号。数据是通过D0~D7这八根数据线并行送出的。
OV9650向外传输的图像格式是YUV的格式 ,YUV是一种压缩后的图像数据格式,它里面还包含很多具体的格式类型,我们的摄像头对应的是YCbCr(8 bits, 4:2:2, Interpolated color).一定要搞清楚格式,后面的驱动里面设置的格式一定要和这个格式一致。
OV9650里面有很多寄存器需要配置,配置这些寄存器就需要通过芯片里面的SCCB总线去配置。SCCB其实是一种弱化的I2C总线。我们可以直接把摄像头接在S5PC100的I2C控制器上,利用I2C总线去读写寄存器,当然直接使用GPIO模拟I2C也可以实现读写。
从OV9650采集过来的数据没法直接交给CPU处理。S5PC100芯片里面集成了Camera控制器,叫FIMC(Fully Interactive Mobile Camera)。摄像头需要先把图像数据传给控制器,经过控制器处理(裁剪拉升后直接预览或者编码)之后交给CPU处理。
实际上摄像头工作需要的时钟也是FIMC给它提供的。
Sccb协议简介
SCCB(Serial Camera Control Bus)是和I2C类似的一个协议。 SIO_C和SIO_D分别为SCCB总线的时钟线和数据线。
从设备地址(ID Address,8bit),分为读地址和写地址,高7位用于选中芯片, 第0位是读/写控制位(R/W),决定是对该芯片进行读或写操作;
内部寄存器单元地址(Sub_ Address,8bit),用于决定对内部的哪个寄存器单元进行操作,通常还支持地址单元连续的多字节顺序读写操作。SCCB控制总线功能的实现完全是依靠SIO_C、SIO_D两条总线上电平的状态以及两者之间的相互配合实现的。SCCB总线传输的启动和停止条件如图
过程:采用简单的三相(Phase)写数据的方式,即在写寄存器的过程中先发送OV7650的ID地址(ID Address),然后发送写数据的目地寄存器地址(Sub_address),最后发送要写入的数据(Write Data)。如果给连续的寄存器写数据,写完一个寄存器后,OV7650会自动把寄存器地址加1,程序可继续向下写,而不需要再次输入ID地址,从而三相写数据变为了两相写数据,由于本系统只需对有限个不连续寄存器进行配置,如果采用对全部寄存器都加以配置这一方法的话,会浪费很多时间和资源,所以我们只对需要更改数据的寄存器进行写数据。对于每一个需更改的寄存器,都采用三相写数据的方法。
OV9650是OmniVision公司的COMS摄像头,130万像素,支持SXVGA、VGA、QVGA、CIF等图像输出格式。 最大速率在SXVGA时为15fps,在VGA时为30fps。
OV9650摄像头时序如下图:
在获得摄像头ID号后说明sccb通信方式已经正常运行,就可以对内部的控制寄存器进行配置,主要的内部控制其有:
时钟预分频寄存器:
图像缓冲区格式设置寄存器:
增益控制寄存器:
输出模式设置寄存器
配置完成后,在camera模块数据线上就应该有数据传输出来。然后配置主机中camera控制器进行数据的接收和转换。
CAMIF
该套架构专为摄像头而设计,如下罗列相应的功能以及接口。分析FIMC需要从两方面出发,第一是CAMIF端,第二是传感器端,下面逐一分析。
CAMERA DISCRIBE:
● Camera interface
Mutiple input support
● ITU-R BT 601/656 mode
◆ DMA(axi 64bits interface) mode
◆ MIPI(CSI) mode
Mutiple output support
● DMA(axi 64bits interface)
● Direct FIFIO mode
● Digital Zoom in capability
● 可编程视屏同步信号极性
● 支持最大64M像素输入
● 图像镜像以及旋转支持
● 多样式图像的处理
● 捕捉图像以及通用处理能力
CRAMERA ARCHITECTURAL
1、可同时支持两个摄像头传感器
2、且3路CRAMIF 可同时操作两个摄像头传感器
3、CRAMIFn有自己的本地管道通向FIMD
4、CRAMIFn有私属的AXI总线读写通道
下图给出了各个camif 的属性。
下面来看看如何配置时钟:
图一
图二
图三
简单分析下,FIMC由4路时钟构成,CAM_SCLK如图二所示,xci_pclk由摄像头传感器内部分频后得到,输出返回至CAMIF。
BUS_CLOCK&CORE_CLOCK可选择APLL,MPLL,HPLL,EPLL输入。注意core clock 最大值是133Mhz , CAM_MCLK最大是83Mhz,XciPCLK最大值也是83Mhz 。
在测试中,笔者选择了MPLL这一路,最后经过分频后得到16.7Mhz的BUS/CORE_CLOCK。
知道时钟后,我们可以看看camif的时序部分:
从s5pc100的用户手册中看到这两幅图,清楚的表现了camif timing 。一个垂直同步信号下,会引发一个HREF信号,它是一个水平相关信号,在一个HREF周期中,会发生一次数据传输。这一点基本和lcd的控制器时序是类似的。
program flow
(1,Reg .register)
配置camera source format Reg 需要填写采集的数据图像的大小。这里我们采用的是800x480,其中800是srcHsize ,480是srcVsize。
● 配置 camera window offset Reg 该寄存器主要指定了需要对采集到的源图像的剪裁所需的各个偏移值。
● 配置全局控制寄存器 camera control Reg 该寄存器有很重要的两个bits,一个是控制器的复位,一个是摄像头传感器chip的复位。并且还需要填写扫描方式1,隔行扫描或者逐行扫描。
● 配置Output DMA 的 start address Reg 注意,一共有4个frame,全配上的话会使得图像输刷新更快,图像显示更流畅。
● 配置Target Format Reg , 该寄存器主要是对图像的旋转以及目标尺寸的设置。
● 对Pre-Scaler control Reg 1的配置主要是设置scaler。具体需要看公式:
if(SrcXSize>=64*DstXSize)
error;
else if(SrcXSize>=32*DstXSize) {
X_ratio=32;
X_shift=5;
}
else if(SrcXSize>=16*DstXSize) {
X_ratio=16;
X_shift=4;
}
else if(SrcXSize>=8*DstXSize) {
X_ratio=8;
X_shift=3;
}
else if(SrcXSize>=4*DstXSize) {
X_ratio=4;
X_shift=2;
}
else if(SrcXSize>=2*DstXSize) {
X_ratio=2;
X_shift=1;
}
else {
X_ratio=1;
X_shift=0;
}
PreDstXsize = SRC_Xsize / PreXRatio ;
MainXratio = (SRC_Xsize<<8)/(DST_Xsize<<X_Shift)
SHfactor = 10-(H_Shift + X_Shift);
X={v,h}; v=vertical h=height;
● 对main-scaler control Reg的配置。需要选择LCD的输入路径。并且还有scaler的起始位。
● 配置output DMA offset Reg的设置,它决定了你输出图像的整体偏移量
● 使能 capture enable Reg ,使能捕捉。
按照以上步骤,就可以简单的输出图像了。注意测试的方案为:camif的数据读取地址与lcd的framebuffer一致,这样摄像头采集到的图像可以第一时间被lcd捕获并显示。注意摄像头采集不能通过local fifo给显示设备。
问题与总结:
1、在整个移植过程中会遇到各种各样的未知问题。通过不断地测试与推敲后,最终成功。下面是一些遇到的问题和解决方案:
2、如果无法读取到传感器的product id 以及manufacture id ,则可能是sccb的限时不够或者达不到要求。也有可能是没有进行软复位,这一点要非常注意,在模拟i2c协议时,这一点尤为重要。
3、如果传感器不输出数据,则代表camif的配置还有问题,主要要看时序是否正确,还有是否使能了capture 信号角,main-scaler start bit;
4、如果有数据了,但是显示出来的却不清楚,或者花瓶的话,那恭喜你,你离成功快近了,但是要做好连续奋战几天的准备。因为这个问题就是一个字,实验。最后的问题就是输入的图像像素以及scaler公式配置不正确,导致输出的像素不正确。这样就不会输出正确的图像。
(笔者的实验数据是src/800*480 target/640*320)
内核相关的一些总结
由于在整个移植过程中,我们都参考的是Android 2.6.29内核,现在讲下一些移植的经验。
在linux下,相关的目录
FIMC: ~\drivers\media\video\samsung\fimc
FIMD: ~\drivers\video\samsung
这两个是核心目录,包含了所有FIMC/D体系的代码,只是与内核关联的部分涉及到了I2C子系统,平台设备驱动,以及v4l2视频编程接口,推荐看资料《FS_S5PC100平台上Linux Camera驱动开发详解》。