s3c2440 提供了一個(gè)攝像接口,使開發(fā)人員很容易地實(shí)現(xiàn)攝像、照相等功能。攝像接口包括 8 位來自攝像頭的輸入數(shù)據(jù)信號,一個(gè)輸出主時(shí)鐘信號,三個(gè)來自攝像頭的輸入同步時(shí)鐘信號和一個(gè)輸出復(fù)位信號。攝像接口的主時(shí)鐘信號由 USB PLL 產(chǎn)生,它的頻率為 96MHz ,再經(jīng)過分頻處理后輸出給攝像頭,攝像頭再根據(jù)該時(shí)鐘信號產(chǎn)生三個(gè)同步時(shí)鐘信號(像素時(shí)鐘、幀同步時(shí)鐘和行同步時(shí)鐘),反過來再輸入回 s3c2440 。s3c2440 僅僅提供了一個(gè)攝像接口,因此要實(shí)現(xiàn)其功能,還需要攝像頭。在這里,我們使用 OV9650 。 OV9650 內(nèi)部有大量的寄存器需要配置,這就需要另外的數(shù)據(jù)接口。 OV9650 的數(shù)據(jù)接口稱為 SCCB (串行攝像控制總線),它由兩條數(shù)據(jù)線組成:一個(gè)是用于傳輸時(shí)鐘信號的 SIO_C ,另一個(gè)是用于傳輸數(shù)據(jù)信號的 SIO_D 。 SCCB 的傳輸協(xié)議與 IIC 的極其相似,只不過 IIC 在每傳輸完一個(gè)字節(jié)后,接收數(shù)據(jù)的一方要發(fā)送一位的確認(rèn)數(shù)據(jù),而 SCCB 一次要傳輸 9 位數(shù)據(jù),前 8 位為有用數(shù)據(jù),而第 9 位數(shù)據(jù)在寫周期中是 Don’t-Care 位(即不必關(guān)心位),在讀周期中是 NA 位。 SCCB 定義數(shù)據(jù)傳輸?shù)幕締卧獮橄啵?phase ),即一個(gè)相傳輸一個(gè)字節(jié)數(shù)據(jù)。 SCCB 只包括三種傳輸周期,即 3 相寫傳輸周期(三個(gè)相依次為設(shè)備從地址,內(nèi)存地址,所寫數(shù)據(jù)), 2 相寫傳輸周期(兩個(gè)相依次為設(shè)備從地址,內(nèi)存地址)和 2 相讀傳輸周期(兩個(gè)相依次為設(shè)備從地址,所讀數(shù)據(jù))。當(dāng)需要寫操作時(shí),應(yīng)用 3 相寫傳輸周期,當(dāng)需要讀操作時(shí),依次應(yīng)用 2 相寫傳輸周期和 2 相讀傳輸周期。因此 SCCB 一次只能讀或?qū)懸粋€(gè)字節(jié)。下面我們就用 s3c2440 的 IIC 總線接口分別與 OV9650 的 SIO_C 和 SIO_D 相連接來實(shí)現(xiàn) SCCB 的功能。具體的讀、寫函數(shù)為:
本文引用地址:http://butianyuan.cn/article/201611/321674.htm
// 配置 IIC 接口
rGPEUP = 0xc000;// 上拉無效
rGPECON = 0xa0000000;//GPE15 : IICSDA , GPE14 : IICSCL
//IIC 中斷
void __irq IicISR(void)
{
rSRCPND |= 0x1<<27;
rINTPND |= 0x1<<27;
flag = 0;
}
// 寫操作
// 輸入?yún)?shù)分別為要寫入的內(nèi)存地址和數(shù)據(jù)
void Wr_SCCB(unsigned char wordAddr, unsigned char data)
{
//3 相寫傳輸周期
// 寫 OV9650 設(shè)備從地址字節(jié)
flag =1;
rIICDS =0x60;//OV9650 設(shè)備從地址為 0x60
rIICSTAT = 0xf0;
rIICCON &= ~0x10;
while(flag == 1)
delay(100);
// 寫 OV9650 內(nèi)存地址字節(jié)
flag = 1;
rIICDS = wordAddr;
rIICCON &= ~0x10;
while(flag)
delay(100);
// 寫具體的數(shù)據(jù)字節(jié)
flag = 1;
rIICDS = data;
rIICCON &= ~0x10;
while(flag)
delay(100);
rIICSTAT = 0xd0;// 停止位
rIICCON = 0xe3;// 為下一次數(shù)據(jù)傳輸做準(zhǔn)備
delay(100);
}
// 讀操作
// 參數(shù)分別為要讀取的內(nèi)存地址和數(shù)據(jù)
void Rd_SCCB (unsigned char wordAddr,unsigned char *data)
{
unsigned char temp;
//2 相寫傳輸周期
// 寫入 OV9650 設(shè)備從地址字節(jié)
flag =1;
rIICDS = 0x60;
rIICSTAT = 0xf0;
rIICCON &= ~0x10;
while(flag)
delay(100);
// 寫入內(nèi)存地址字節(jié)
flag = 1;
rIICDS = wordAddr;
rIICCON &= ~0x10;
while(flag)
delay(100);
rIICSTAT = 0xd0;// 停止位
rIICCON = 0xe3;// 為下一次數(shù)據(jù)傳輸做準(zhǔn)備
delay(100);
//2 相讀傳輸周期
// 寫入 OV9650 設(shè)備從地址字節(jié)
flag = 1;
rIICDS = 0x60;
rIICSTAT = 0xb0;
rIICCON &= ~0x10;
while (flag)
delay(100);
// 讀取一個(gè)無用字節(jié)
flag = 1;
temp = rIICDS;
rIICCON &= ~((1<<7)|(1<<4));
while(flag)
delay(100);
// 讀取數(shù)據(jù)
flag = 1;
*data= rIICDS;
rIICCON &= ~((1<<7)|(1<<4));
while(flag)
delay(100);
rIICSTAT = 0x90;// 停止位
rIICCON = 0xe3;// 為下一次傳輸做準(zhǔn)備
delay(100);
}
當(dāng)然我們也可以用兩個(gè)通用 IO 口來模擬 SCCB 總線,下面我們給出具體的程序,其中 GPE15 為 SIO_D , GPE14 為 SIO_C 。
#define CLOCK_LOW()(rGPEDAT&=(~(1<<14)))// 時(shí)鐘信號低
#define CLOCK_HIGH()(rGPEDAT|=(1<<14))// 時(shí)鐘信號高
#define DATA_LOW()(rGPEDAT&=(~(1<<15)))// 數(shù)據(jù)信號低
#define DATA_HIGH()(rGPEDAT|=(1<<15))// 數(shù)據(jù)信號高
// 配置 IO
rGPEUP = 0xc000;// 上拉無效
rGPECON = 5<<28;//GPE15 為 SIO_D , GPE14 為 SIO_C ,都為輸出
void delay(int a)
{
int k;
for(k=0;k
;
}
// 啟動(dòng) SCCB
void __inline SCCB_start(void)
{
CLOCK_HIGH();
DATA_HIGH();
delay(10);
DATA_LOW();
delay(10);
CLOCK_LOW();
delay(10);
}
// 結(jié)束 SCCB
void __inline SCCB_end(void)
{
DATA_LOW();
delay(10);
CLOCK_HIGH();
delay(10);
DATA_HIGH();
delay(10);
}
//SCCB 發(fā)送一個(gè)字節(jié)
void __inline SCCB_sendbyte(unsigned char data)
{
int i=0;
// 并行數(shù)據(jù)轉(zhuǎn)串行輸出,串行數(shù)據(jù)輸出的順序?yàn)橄雀呶辉俚臀?/p>
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);
}
評論