s3c2440的摄像接口应用


s3c2440提供了一个摄像接口,使开发人员很容易地实现摄像、照相等功能。摄像接口包括8位来自摄像头的输入数据信号,一个输出主时钟信号,三个来自摄像头的输入同步时钟信号和一个输出复位信号。摄像接口的主时钟信号由USB PLL产生,它的频率为96MHz,再经过分频处理后输出给摄像头,摄像头再根据该时钟信号产生三个同步时钟信号(像素时钟、帧同步时钟和行同步时钟),反过来再输入回s3c2440

 

       s3c2440仅仅提供了一个摄像接口,因此要实现其功能,还需要摄像头。在这里,我们使用OV9650OV9650内部有大量的寄存器需要配置,这就需要另外的数据接口。OV9650的数据接口称为SCCB(串行摄像控制总线),它由两条数据线组成:一个是用于传输时钟信号的SIO_C,另一个是用于传输数据信号的SIO_DSCCB的传输协议与IIC的极其相似,只不过IIC在每传输完一个字节后,接收数据的一方要发送一位的确认数据,而SCCB一次要传输9位数据,前8位为有用数据,而第9位数据在写周期中是Don’t-Care位(即不必关心位),在读周期中是NA位。SCCB定义数据传输的基本单元为相(phase),即一个相传输一个字节数据。SCCB只包括三种传输周期,即3相写传输周期(三个相依次为设备从地址,内存地址,所写数据),2相写传输周期(两个相依次为设备从地址,内存地址)和2相读传输周期(两个相依次为设备从地址,所读数据)。当需要写操作时,应用3相写传输周期,当需要读操作时,依次应用2相写传输周期和2相读传输周期。因此SCCB一次只能读或写一个字节。下面我们就用s3c2440IIC总线接口分别与OV9650SIO_CSIO_D相连接来实现SCCB的功能。具体的读、写函数为:

 

//配置IIC接口

rGPEUP = 0xc000;               //上拉无效

rGPECON = 0xa0000000;            //GPE15IICSDAGPE14IICSCL 

 

//IIC中断

void __irq IicISR(void)

{

       rSRCPND |= 0x1<<27;

       rINTPND |= 0x1<<27;

       flag = 0; 

}

 

//写操作

//输入参数分别为要写入的内存地址和数据

void Wr_SCCB(unsigned char wordAddr, unsigned char data)

{

       //3相写传输周期

       //OV9650设备从地址字节

flag =1;

       rIICDS =0x60;              //OV9650设备从地址为0x60

       rIICSTAT = 0xf0;

       rIICCON &= ~0x10;

      

       while(flag == 1)

              delay(100);

      

       //OV9650内存地址字节

       flag = 1;

       rIICDS = wordAddr;

       rIICCON &= ~0x10;

       while(flag)

              delay(100);

      

       //写具体的数据字节

       flag = 1;

       rIICDS = data;

       rIICCON &= ~0x10;

       while(flag)

              delay(100);

                    

       rIICSTAT = 0xd0;         //停止位

       rIICCON = 0xe3;          //为下一次数据传输做准备

      

       delay(100);                  

}

 

//读操作

//参数分别为要读取的内存地址和数据

void Rd_SCCB (unsigned char wordAddr,unsigned char *data)

{

       unsigned char temp;

      

       //2相写传输周期

       //写入OV9650设备从地址字节

       flag =1;

       rIICDS = 0x60;

       rIICSTAT = 0xf0;

       rIICCON &= ~0x10;

       while(flag)

              delay(100);

      

       //写入内存地址字节

       flag = 1;

       rIICDS = wordAddr;

       rIICCON &= ~0x10;

       while(flag)

              delay(100);

      

       rIICSTAT = 0xd0;         //停止位

       rIICCON = 0xe3;          //为下一次数据传输做准备

      

       delay(100);    

      

       //2相读传输周期

       //写入OV9650设备从地址字节

       flag = 1;

       rIICDS = 0x60;

       rIICSTAT = 0xb0;

       rIICCON &= ~0x10;

       while (flag)

              delay(100);

             

       //读取一个无用字节

       flag = 1;

       temp = rIICDS;

       rIICCON &= ~((1<<7)|(1<<4));

       while(flag)

              delay(100);

      

       //读取数据

       flag = 1;

       *data= rIICDS;

       rIICCON &= ~((1<<7)|(1<<4));

       while(flag)

              delay(100);

             

       rIICSTAT = 0x90;         //停止位

       rIICCON = 0xe3;          //为下一次传输做准备

      

       delay(100);                  

}

 

       当然我们也可以用两个通用IO口来模拟SCCB总线,下面我们给出具体的程序,其中GPE15SIO_DGPE14SIO_C

 

#define CLOCK_LOW()              (rGPEDAT&=(~(1<<14)))           //时钟信号低

#define CLOCK_HIGH()             (rGPEDAT|=(1<<14))                  //时钟信号高

#define DATA_LOW()                 (rGPEDAT&=(~(1<<15)))           //数据信号低

#define DATA_HIGH()                (rGPEDAT|=(1<<15))                  //数据信号高

 

//配置IO

rGPEUP = 0xc000;               //上拉无效

rGPECON = 5<<28;             //GPE15SIO_DGPE14SIO_C,都为输出

 

void delay(int a)

{

       int k;

       for(k=0;k<a;k++)

              ;

}

 

//启动SCCB

void __inline SCCB_start(void)

{

       CLOCK_HIGH();

       DATA_HIGH();

       delay(10);

       DATA_LOW();

       delay(10);

       CLOCK_LOW();

       delay(10);

}

 

//结束SCCB

void __inline SCCB_end(void)

{

       DATA_LOW();

       delay(10);

       CLOCK_HIGH();

       delay(10);

       DATA_HIGH();

       delay(10);

}

 

//SCCB发送一个字节

void __inline SCCB_sendbyte(unsigned char data)

{

       int i=0;

       //并行数据转串行输出,串行数据输出的顺序为先高位再低位

       for(i=0;i<8;i++)

       {

              if(data & 0x80)

                     DATA_HIGH();

              else

                     DATA_LOW();

                    

              delay(10);

              CLOCK_HIGH();

              delay(10);

              CLOCK_LOW();

              delay(10);

              DATA_LOW();

              delay(10);

             

              data <<= 1;

       }

      

       //9位,Don’t Care

       DATA_HIGH();

       delay(10);

       CLOCK_HIGH();

       delay(10);

       CLOCK_LOW();

       delay(10);

}

 

// SCCB接收一个字节

void __inline SCCB_receivebyte(unsigned char *data)

{

       int i=0;

       int svalue=0;

       int pvalue = 0;

      

       rGPECON = 1<<28;             //GPE15输出改变为输入

      

       //串行数据转并行输入,高位在前

for(i=7;i>=0;i--)

       {

              CLOCK_HIGH();

              delay(10);

              svalue = rGPEDAT>>15;

              CLOCK_LOW();

              delay(10);

              pvalue |= svalue <<i;

       }

      

       rGPECON =5<<28;              //再把GPE15改回为输出

      

       //9位,N.A.

       DATA_HIGH();

       delay(10);

       CLOCK_HIGH();

       delay(10);

       CLOCK_LOW();

       delay(10);

      

       *data = pvalue &0xff;   

}

 

//写操作

void SCCB_senddata(unsigned char subaddr, unsigned char data)

{

       //3相写传输周期

       SCCB_start();                             //启动SCCB

       SCCB_sendbyte(0x60);                //OV9650设备从地址,写操作

       SCCB_sendbyte(subaddr);            //设备内存地址

       SCCB_sendbyte(data);                 //写数据字节

       SCCB_end();                              //结束SCCB

      

       delay(20);

}

 

//读操作

unsigned char SCCB_receivedata(unsigned char subaddr)

{

       unsigned char temp;

      

       //2相写传输周期

       SCCB_start();                             //启动SCCB

       SCCB_sendbyte(0x60);               //OV9650设备从地址,写操作

       SCCB_sendbyte(subaddr);            //设备内存地址

       SCCB_end();                              //结束SCCB

      

       //2相读传输周期

       SCCB_start();                             //启动SCCB

       SCCB_sendbyte(0x61);                //OV9650设备从地址,读操作

       SCCB_receivebyte(&temp);         //读字节

       SCCB_end();                              //结束SCCB

      

       return temp;   

}    

  • 1
  • 2
  • 下一页

相关内容