最近做項目需要用到OV7725,於是花了些時間研究。由於OV7725對於工作頻率的要求較高,因此使用帶FIFO的攝像頭模塊。代碼參考自正點原子官方。
OV7725資源
引腳說明
以下時關於十八個引腳的說明(來自正點原子的用戶手冊)
其中,OV_SCL和OV_SDA組成SCCB,即串行攝像頭控制總線,它的通信機制類似於IIC,有使用過IIC總線的較容易理解。OV_VSYNC爲幀同步信號,該引腳產生信號時,意味着一幀數據傳輸完成後,下一幀數據傳輸即將開始(這裏,從OV7725傳輸至FIFO)。FIFO_D[7:0] 是FIFO的數據引腳,用於數據傳輸。當發生幀同步信號時,復位FIFO_WRST寫指針信號,使能FIFO_WEN寫使能信號,則OV7725開始往FIFO寫數據,並置位幀中斷標誌位(該標誌位在讀數據完成後被清零),保證FIFO的數據被讀取完成之前不會被覆蓋,具體見下面的中斷服務程序。幀中斷標誌位有效時,就復位RIFO_RRST讀指針信號,然後在每個FIFO_RCLK讀時鐘信號,使用STM32去讀取FIFO_D[7:0] 的數據。FIFO_OE片選信號在初始化之後就拉低,使之有效。
寄存器
這是來自datasheet的寄存器描述,看手冊,英文很重要:
這些寄存器在代碼裏表現爲一堆宏定義
/*OV7725寄存器宏定義*/
#define GAIN 0x00
#define BLUE 0x01
#define RED 0x02
#define GREEN 0x03
#define BAVG 0x05
#define GAVG 0x06
…………
模塊初始化
引腳定義
//D0~D7:PA0~PA7 VSYNC:PA8
//WRST:PB13 RRST:PB14 OE:PB5 RCLK:PB6 WEN:PB7 SDA:PB8 SCL:PB9
#define OV7725_VSYNC PAin(8)
#define OV7725_WRST PBout(13)
#define OV7725_WREN PBout(7)
#define OV7725_RCK_H GPIOB->BSRR=1<<6
#define OV7725_RCK_L GPIOB->BRR=1<<6
#define OV7725_RRST PBout(14)
#define OV7725_CS PBout(5)
#define SCCB_SCL PBout(9) //SCL
#define SCCB_SDA PBout(8) //SDA
#define SCCB_READ_SDA PBin(8) //ÊäÈëSDA
我使用的是杜邦線連接如,IO口是自己重新定義的(全使用普通IO即可),STM32F1系列的PB3,PB4,PA13,PA14,PA15用於JTAG,如果有使用到其中的引腳,需要進行特殊配置,具體可參考網上更多教程。當時使用PB3,PB4作爲SCCB的引腳,出現問題才發現這個原因。
初始化
寫寄存器的函數,寄存器的配置都是通過這個函數
u8 SCCB_WR_Reg(u8 reg,u8 data)
{
u8 res=0;
SCCB_Start(); //啓動SCCB傳輸
if(SCCB_WR_Byte(SCCB_ID))res=1; //寫器件ID,爲0x42
delay_us(100);
if(SCCB_WR_Byte(reg))res=1; //寫寄存器地址,直接寫對應的寄存器地址
delay_us(100);
if(SCCB_WR_Byte(data))res=1; //寫數據,根據寄存器功能寫對應數據
SCCB_Stop();
return res;
}
將要配置的寄存器地址和對應的值,存在一個二維數組裏邊
//初始化寄存器系列及其對應的值
const u8 ov7725_init_reg_tb1[][2]=
{
/*輸出窗口設置*/
{CLKRC, 0x00}, //clock config
{COM7, 0x06}, //VGA RGB565
{HSTART, 0x3f}, //水平起始位置
{HSIZE, 0x50}, //水平尺寸
{VSTRT, 0x03}, //垂直其實位置
......
初始化時,在循環語句調用寫寄存器的函數,依次寫入寄存器的地址和對應的值,即可完成寄存器的配置
//初始化OV7725,採用QVGA分辨率(320*240)
for(i=0;i<sizeof(ov7725_init_reg_tb1)/sizeof(ov7725_init_reg_tb1[0]);i++)
{
SCCB_WR_Reg(ov7725_init_reg_tb1[i][0],ov7725_init_reg_tb1[i][1]);
}
幀中斷和數據處理
發生幀中斷時
u8 ov_sta; //幀中斷標記
//中斷處理函數
void EXTI9_5_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line8)==SET)//是8線的中斷
{
if(ov_sta==0)
{
OV7725_WRST=0; //復位寫指針
OV7725_WRST=1;
OV7725_WREN=1; //允許寫入FIFO
ov_sta++; //幀中斷加1
}else OV7725_WREN=0;//禁止寫入FIFO
}
EXTI_ClearITPendingBit(EXTI_Line8); //清除中斷標誌位
}
數據處理
if(ov_sta)//判斷是否有幀中斷髮生
{
OV7725_RRST=0; //復
OV7725_RCK_L; //位
OV7725_RCK_H; //讀
OV7725_RCK_L; //指
OV7725_RRST=1; //針
OV7725_RCK_H;
for(i=0;i<OV7725_WINDOW_HEIGHT;i++)//循環語句讀取FIFO的數據
{
for(j=0;j<OV7725_WINDOW_WIDTH;j++)
{
//將數據填入相應緩衝區
......
}
}
ov_sta=0; //清零幀中斷標誌
}
以上是對於OV7725的初步理解,還有很多不懂的地方,後續有進一步研究再補充