OV7670/OV7725/OV5640開發記錄終於到最后一講了,還是蠻累的。
一、SDRAM緩存處理
很多攝像頭工程都用到了SDRAM作為中間緩存,很多人一臉懵逼,我也是思考了好一陣才明白。先假設 OV5640 和 VGA 直接相連,中間不采用任何緩存器件,那會出現什么情況呢?
OV5640 的幀率為 30fps, VGA 的幀率為 60fps,且時鍾也完全不一樣。假設分辨率是 3x2 = 6,數據為:1,2,3,4,5,6。OV5640 幀率小,生成一個像素的時間假設是2秒,而 VGA 幀率大,需要一個像素的時間假設是 1s。在 6s 的時間里,VGA就請求了一幀數據,可這個時間里 OV5640 只生成了1,2,3共三個像素,VGA那邊就出現了空數據的情況。在 12s 的時間里,VGA 請求了兩幀數據,可這個時間里 OV5640 只生成了一幀數據,怎么來說都是錯的。上述假設是簡化了時間點,實際情況是 OV5640 生成像素和 VGA 請求像素的時間不一致,導致VGA總是要不到一幀圖像正確的數據,也要不全一幀圖像正確的數據。因此,OV5640 和 VGA 之間需要加入一個緩存器件,用於緩存一幀的數據,這樣 VGA 每次要一幀數據都可以被滿足。加入緩存器件的根本原因就是兩端時鍾不一致,導致讀寫速率不一致。
采用什么緩存器件呢?FIFO 和 RAM 是最常用的,但是一幀的圖像數據往往是 640x480、1280x768、1920x1280,每個像素是 16bit。數據量大,FPGA的片內資源無法滿足。因此需要引入外部緩存器件,如 SDRAM、DDR2、DDR3等。
二、無乒乓操作
SDRAM 正常使用其實是無乒乓操作,無乒乓操作是考慮不周的,除非一幀圖像是瞬間生成,OV5640 幀率 30fps,VGA 幀率 60fps,仿佛剛好可以寫一幀讀兩幀。但是一幀圖像實際情況是一行行的生成和讀取的,所以會出現 VGA 從SDRAM處讀的上半幀是新幀,而由於SDRAM緩存的下半幀還沒有被 OV5640 寫完,VGA 從SDRAM處讀的下半幀還是老幀。示意圖如下所示,紅線為寫,黑線為讀。
將上述 5 幀圖像生成的時間點編號為 t1、t2、t3、t4、t5。在 t1、t3、t5 時刻圖像都是殘缺幀(新老幀參半),在 t2、t4 時刻圖像才是完整的一幀,而 VGA 那邊可不管,每個時間點都會要一幀圖像,這就是錯幀現象。而解決錯幀現象的方法則是乒乓操作。
三、乒乓操作
1、乒乓操作原理
乒乓操作,使用兩個緩存區,寫緩存區 1 時讀緩存區 2,寫緩存區 2 時讀緩存區 1,讀寫交替。示意圖如下,紅線為寫,黑線為讀。
由示意圖可以看出,乒乓操作中,每次讀的(黑線)都是完整的幀,每一幀讀 2 次,這樣便沒有出現讀殘缺幀的現象,解決了錯幀問題。
2、乒乓操作設計
在上述設計中,由於寫讀速率為1:2,所以寫一幀讀兩幀即可,但是很多時候寫讀速率的比例是其他數值,那怎么辦呢?
(1)寫端在緩存區1寫完一幀數據就切換到緩存區2寫下一幀,寫完后又切換回緩存區1寫再下一幀,如此反復。
(2)讀端在緩存區2讀完一幀:
①如果寫端仍然在緩存區1,則讀端不切換緩存區,而是繼續在緩存區2重讀一幀。
②如果寫端離開了緩存區1,即切換到緩存區2了,說明寫端已經在緩存區1寫完了,則讀端可以切換到緩存區1。這樣就能保證讀端每次讀的都是完整的幀,就算有一小段時間是讀寫端都在同一個緩存區,但是由於寫慢讀快,寫是不會追上讀的,讀還是能讀完舊幀,之后舊幀才被新幀覆蓋。
寫慢讀快這樣設計就行,那如果寫快讀慢呢?其實也是一樣的思想,反過來即可。無論誰快誰慢,都是快端照顧慢端,即慢端一幀結束就離開自身緩存區到另一緩存區。快端則一幀結束后,先檢測慢端是否離開自身緩存區,是則切換過去,否則不切換過去,而是重新在自身緩存區再工作一幀。示意圖如下所示:
3、SDRAM乒乓操作
用兩片SDRAM來進行乒乓操作有些太浪費了,可以直接利用SDRAM里面的bank進行乒乓操作即可。雖然讀寫只有一根總線,但是SDRAM時鍾高,讀寫足夠快,可以滿足乒乓操作的需求。具體實現可以看這篇博客《DDR2(5):DDR2自動讀寫控制器》,雖然是 DDR2,但道理是一樣的。
參考資料:
[1]正點原子FPGA教程
[2]小梅哥《OV5640圖像采集從原理到應用》
[3]開源騷客《SDRAM那些事兒》
[4]韓彬, 於瀟宇, 張雷鳴. FPGA設計技巧與案例開發詳解[M]. 電子工業出版社, 2014.