新拿到的硬件,是好是坏,或者有没有一些大意或细节的错误,当然需要驱动程序并结合一些电气工具如(示波器)去检测.
1.SCCB:
当然这是最首检测也是必须检测的.这里我是用iic-tools工具(LINUX平台支持用户空间驱动的项目,需要内核编译相关的支持).源码可以网上搜索移植.后续会提供我这边提供整理简化的IIC-TOOLS源码.iic-tools是LINUX平台调试IIC设备的利器.一共有i2cdetect,i2cset,i2cget,i2cdump四个工具,可以遍历iic总线上的设备.其具体用法可网上搜索.OV9712标识了其SCCB设备地址为0x60,如果i2cdetect出来的结果和其设备地址有出入,就需要检查一下硬件了.
当然,前期是可以用iic-tools工具大体检测,如果是有特殊接口API要求,则就需要具体的API编程.例如下面是我获取OV9712的PID的函数:
unsigned short ov9712GetId(int iic_fd) { unsigned short pid = 0; unsigned char tmp = 0; iic_set_addr(iic_fd,OV9712ADDR); tmp = iic_read(iic_fd,PIDHADDR); pid = tmp; pid = pid << 8; tmp = iic_read(iic_fd,PIDLADDR); pid = pid | tmp; if(0x9711 == pid) printf("Found Sensor OV9712.So Lucky!\n"); else printf("Oops:Miss OV9712.\n"); return pid; }0x9711是OV9712的产品ID,可以查看其数据手册.
这里曾遇到个问题,就是SCCB通讯失败,原因是OV9712必须有MCLK才可以SCCB通讯的.
2.初始化OV9712:
确认SCCB通讯是没问题的,就直接往OV9712堆sample code吧.把原厂提供的初始化代码通过SCCB协议,往里面塞.塞完寄存器后大体量一下MCLK、VSYNC、HSYNC、PCLK及DATA引脚,都有信号输出并且是正常的.截取了一部分原始数据铺在320x240的屏上显示只有一些彩条乱七八糟的.出现这种情况当时就往两个方向想了:
一个是极性问题;第二个对出来的图像数据直接铺屏(RGB565)的问题.
2-1.极性匹配:
厂家提供的代码里面间没有对VSYNC、HSYNC和PCLK的极性进行重新配置,就是采用默认的.于是查找OV9712数据手册找到VSYNC、HSYNC、PCLK的极性控制寄存器.如下:
可见,OV9712的VSYNC、HSYNC默认的极性是Positive,即上升沿有效.
注意,这里不要这里的寄存器坑了,HSYNC默认确实是positive,但是前提是你选定的是HSYNC模式.OV9712支持三种模式:HREF、HSYNC、CCIR565.默认的就是HERF模式而不是HSYNC模式.HERF和HSYNC是同一个pin脚,不同的是,HERF模式下,HERF引脚为低的时候VSYNC引脚输出才有效.见OV9712的数据手册的时序图,如下:
因此,在HREF模式下,是下降沿有效的.在这种模式下主控端需要配置HSYNC引脚为下降沿有效.我把JZ4776主控端配置成上升沿有效的时候,是获取不了图片的.既然废弃了HSYNC行同步,那么会不会出现行同步不一致而导致主控拒绝接收数据呢?个人认为,有VSYNC足够了,它引发了中断,就意味着一帧图像传输完毕,主控端就可以去处理数据了,HSYNC是可以被忽略的.如果遇到一些平台比较严格的话,还需要处理HSYNC同步的话,就具体处理了.
PCLK的极性如下:
因此,我们可以确定HREF模式下PIN脚VSYNC、HREF(HSYNC)、PCLK的极性分别为:
VSYNC:上升沿; HERF(HSYNC):下降沿; PCLK:上升沿.因此,再根据设备去配置主控端的相应极性:
默认的VSYN和PCLK极性是一致的,主要是把HSP配置为1(即下降沿有效).
2-2.接收图像的顺序:
一般CPU的CIM控制器都有从SENSOR端过来的接收到的数据进行重组排序处理的.一般而言,SENSOR端输出的是YUV或RAW RGB,一般而言,数据手册都可以找到明确其明确格式,比如OV9712的图像输出格式就是BAYER(RAW DATA)中的一种.从其数据手册可以看到如下字样:
The color filters are arranged in a Bayer pattern. The primary color BG/GR array is arranged in line-alternating fashion.「小技巧:」无论是YUV还是RAW DATA,如果是接收顺序反了的话,一般都有轮廓.可以适当尝试一下别的字节重组顺序.
JZ4775对从SENSOR接收过来的4个字节拼成32位的字,有下面8种方式:
这里选择第五种方式,即3'b100.高低位调转的方式.
核对了上述两点之外,出来的图像依然看不出图像的完整性.配置依然可能存在问题,镜头也没调焦距,上层转换函数也有可能存在问题.这三个方面的因素都有可能导致同样的现象.于是想了下有没有更好更直接的快捷方式.通过查阅OV9712的数据手册,发现其提供了个test pattern模式.进入这种模式下,显示8段彩条.如下:
在OV9712提供的另一款"应用程序编程手册"可以知道进入test pattern模式通过下面寄存器设置:
当然,还要设置寄存器0xca进入TestPattern模式.代码如下:
void ov9712TestPattern(int iic_fd) { iic_write(iic_fd,0xca,0x24); iic_write(iic_fd,0x12,0x02); iic_write(iic_fd,0x97,0x88); }然后把SENSOR端过来的数据转RGB565保存起来,发现图片有断层情况.后来检查发现是转换函数的bmp头构造得有问题.修复后效果和test pattern一致.为了调试方便,决定把转换出来的RGB565(1280 X 800)显示在2.8寸屏(320 x 240)上.通过跳行跳列实现.代码如下:
/* Function: Skip One Row And One Column. Date: 2014-3-29 Author: SE7EN */ void skipPiexl1(const u16 *inBuf,u16 *outBuf,const u32 width,const u32 height,u32 div) { assert((inBuf && outBuf && (0 == (width % 4) && (0 == (height % 4)) && (0 == (div % 4))))); const u16 *pInW = inBuf; u16 *pOut = outBuf; u32 i = 0,j = 0,k = 0,sum = 0,aver = 0; for(i = 0; i < height; i+=2) { for(j = 0; j < width; j+=2) { *pOut = *pInW; pOut++; pInW +=2; } pInW = pInW + width; } }因为我的是竖屏,因此还需要把两次缩放的像素buf旋转90度,代码如下:
/* Function: Operation For RGB. Date: 2014-3-29 Author: SE7EN */ #include "skippiexl.h" void rgb565_rotate90(const u16 *input, u16 *output,u32 width_in,u32 height_in) { const u16 *pIn=input; u16 *pOut=output; int i,j; for(i=0; i<height_in; i++) { for(j=0; j<width_in; j++) { *pOut = *pIn++; pOut = output+height_in*j + i; } } }
3.小结:
SENSOR其实是挺复杂的一个东西,很多过中涉及的概念都只是有个笼统的概念.在此作录备忘,后续还需要调试图像质量,这个只能靠技术支持了.