日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【正点原子FPGA连载】第四十三章MT9V034摄像头RGB-LCD显示实验 -摘自【正点原子】新起点之FPGA开发指南_V2.1

發布時間:2024/3/24 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【正点原子FPGA连载】第四十三章MT9V034摄像头RGB-LCD显示实验 -摘自【正点原子】新起点之FPGA开发指南_V2.1 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1)實驗平臺:正點原子新起點V2開發板
2)平臺購買地址:https://detail.tmall.com/item.htm?id=609758951113
2)全套實驗源碼+手冊+視頻下載地址:http://www.openedv.com/thread-300792-1-1.html
3)對正點原子FPGA感興趣的同學可以加群討論:994244016
4)關注正點原子公眾號,獲取最新資料更新

第四十三章MT9V034攝像頭RGB-LCD顯示實驗

MT9V034是ON Semiconductor(安森美半導體)公司生產的一顆CMOS圖像傳感器,該傳感器功耗低、可靠性高以及采集速率快,主要應用機器視覺,雙目視覺,寬溫度工業場合等領域。本章我們將使用FPGA開發板實現對MT9V034的數字圖像采集并通過LCD實時顯示。
本章包括以下幾個部分:
4242.1簡介
42.2實驗任務
42.3硬件設計
42.4程序設計
42.5下載驗證
43.1簡介
MT9V034是一款1/3英寸單芯片圖像傳感器,其感光陣列最大可達到752*480,能實現最快60fps VGA分辨率的圖像采集,具有全局曝光和高動態范圍(HDR)操作。這款CMOS圖像傳感器具有安森美半導體的突破性功能,實現了CCD圖像質量的低噪聲和CMOS成像技術(基于信噪比和低光靈敏度),同時保持固有尺寸、成本和CMOS的集成優勢。下表為幾個攝像頭的功能對比。

通過上述的對比可以看出,相對于其他2款攝像頭MT9V034的優勢在于HDR模式和全局曝光。HDR模式的原理是根據不同的曝光時間的LDR(Low-Dynamic Range)圖像,利用每個曝光時間相對應最佳細節的LDR圖像來合成最終HDR圖像,與普通的圖像相比,可以提供更多的動態范圍和圖像細節。下圖是線性模式和HDR模式的對比圖。

圖 43.1.1 HDR模式

圖 43.1.2 線性模式
通過對比可以發現,開啟了 HDR,會使拍到的圖像亮度比較高的地方變暗,亮度比較低的地方變亮,總的來說就是使圖像顯示的更均衡。
卷簾曝光的原理是通過Sensor逐行曝光的方式實現的。在曝光開始的時候,Sensor逐行掃描逐行進行曝光,直至所有像素點都被曝光。與卷簾曝光不同 ,全局曝光整幅場景在同一時間曝光實現的,Sensor所有像素點同時收集光線,同時曝光。下面為兩種模式的對比圖。

圖 43.1.3 全局曝光拍攝圖

圖 43.1.4 卷簾曝光拍攝圖
當拍攝快速移動的物體時,全局曝光拍攝到的物體比較清晰,不會發生形變,而卷簾曝光拍攝的圖片會出現部分曝光(partial exposure)、斜坡圖形(skew)、晃動(wobble) 等現象,也就是傳說中的果凍了。這是全局曝光其優勢的一面,相對于卷簾曝光也有其劣勢的一面。當全局曝光的曝光時間長(如大于500μs)時,其噪點情況嚴重,而運用卷簾曝光后,圖片會有更低的噪聲和更快的幀速。
下圖為MT9V034的功能框圖:

圖 43.1.5 MT9V034功能框圖
由上圖可知,除了傳統的并行邏輯輸出,MT9V034還具有串行低壓差分信號(LVDS)輸出。該傳感器可以在立體聲相機中操作,并且該傳感器被指定為立體聲主機時,可以合并來自本身的立體聲,還可以將從屬傳感器的數據合并為一個串行LVDS流。本次實驗只采用傳統的并行邏輯輸出。
MT9V034通過兩線串行接口將寄存器寫入MT9V034和從中讀取,以此來配置窗口大小和行場分辨率等寄存器。MT9V034是具有四個可能ID(0x90、0x98、0xB0和0xB8)由S_CTRL_ADR0和S_CTRL_ADR1輸入引腳確定,本次實驗所用的MT9V034的寫器件ID是0x90。下圖是器件ID的相關內容。

圖 43.1.6 器件地址
MT9V034使用的是兩線式接口總線,該接口總線包括SCLK串行時鐘輸入線和SDATA串行雙向數據線,分別相當于IIC協議的SCL信號線和SDA信號線。本次實驗所用的兩線式接口總線兼容IIC協議,是所以不對相關協議詳細介紹,有關IIC協議的詳細介紹請大家參考“EEPROM讀寫實驗”章節。
兩線式接口總線的寫傳輸協議如下圖所示:

圖 43.1.7寫傳輸協議
上圖中的ADDR是由7位器件地址和1位讀寫控制位構成(0:寫 1:讀),MT9V034的器件地址為7’h5c,所以在寫傳輸協議中,ID Address(W) = 8’hb8(器件地址左移1位,低位補0);R0x09為8位寄存器地址,在MT9V034的數據手冊中有些寄存器是可改寫的,有些是只讀的,只有可改寫的寄存器才能正確寫入;Write Data為16位寫數據,每一個寄存器地址對應16位的配置數據。上圖中的第9位ACK表示從機應答,該位是由從機(此處指MT9V034)發出應答信號來響應主機表示當前器件地址、寄存器地址和寫數據是否傳輸完成,但是從機有可能不發出應答信號,因此主機(此處指FPGA)在此必須判斷此處是否有應答,有應答即說明當前傳輸完成,無應答表示傳輸未完成。
我們可以發現,MT9V034的兩線式接口總線和IIC寫傳輸協議是極為相似的,只是在兩線式接口總線寫傳輸協議中,一個寄存器地址寫入16位數據,而IIC寫傳輸協議一個地址只寫入8位數據。兩線式接口總線的讀傳輸協議和IIC有些差異,在IIC讀傳輸協議中,一個寄存器地址只讀出8位數據;而兩線式接口總線傳輸協議中一個寄存器地址只讀出16位數據,下圖為兩線式接口總線的讀傳輸協議。

圖 43.1.8 SCCB讀傳輸協議
由上圖可知,兩線式接口總線讀傳輸協議分為兩個部分。第一部分是寫器件地址和寄存器地址,即先進行一次虛寫操作,通過這種虛寫操作使地址指針指向虛寫操作中寄存器地址的位置,當然虛寫操作也可以通過前面介紹的寫傳輸協議來完成。第二部分是讀器件地址和讀數據,此時讀取到的數據才是寄存器地址對應的數據,注意ID Address(R) = 8’hB9(器件地址左移1位,低位補1)。上圖中的NACK位由主機(這里指FPGA)產生,由于兩線式接口總線不支持連續讀寫,因此NACK位必須為高電平。
MT9V034在上電后是存在默認寄存器的,即上電后就可以輸出752x480分辨率的圖像,如果大家需要其他的分辨率或模式就必須先對傳感器進行初始化,可通過配置寄存器使其工作在預期的工作模式,以得到較好畫質的圖像。因為兩線式接口總線的寫傳輸協議和IIC幾乎相同,因此我們可以直接使用IIC的驅動程序來配置攝像頭。當然這么多寄存器也并非都需要配置,很多寄存器可以采用默認的值。ON Semiconductor公司提供了MT9V034的軟件使用手冊(MT9V034,位于開發板所隨附的資料“7_硬件資料/7_MT9V034資料/MT9V034.pdf”),如果某些寄存器不知道如何配置可以參考此手冊,下表是本程序用到的關鍵寄存器的配置說明。

0Xd5 Fine Shutter Width Total 0x0000 細調曝光時間的寬度
MT9V034的寄存器較多,對于其它寄存器的描述可以參MT9V034的數據手冊。
下圖為MT9V034的一些特性。

圖 43.1.9 MT9V034的特性
從上圖可以看出,MT9V034的輸入時鐘頻率的范圍是13Mhz~27Mhz;本次實驗攝像頭的輸入時鐘為24Mhz,是由外部晶振提供的;兩線式接口總線的SCLK的時鐘頻率最大為400KHz。

圖 43.1.10 PIXCLK和SYSCLK的關系
結合圖 43.1.10和圖 43.1.9可知,PIXCLK和SYSCLK是同頻不同相的2個時鐘,本次實驗攝像頭的輸入時鐘為24Mhz,所以攝像頭的輸出時鐘也為24Mhz。
MT9V034在并行邏輯輸出的模式下僅支持10bit的YUV(亮度參量和色度參量分開表示的像素格式),不支持其他格式。由于攝像頭采集的圖像最終要在LCD上顯示,且新起點開發板上的數據接口為RGB888格式(詳情請參考“LCD彩條顯示實驗”章節),因此必須將MT9V034攝像頭輸出的YUV格式的圖像像素數據轉換為RGB888格式。下圖為攝像頭輸出的行時序圖。

圖 43.1.11 行時序圖
LINE_VALID:數據有效使能。當其為高時,輸出的數據為有效數據。
PIXCLK:像素時鐘。由MT9V034產生的對外輸出的時鐘信號。
DOUT:有效數據。攝像頭采集得到的像素數據,本次實驗取其高8位。

圖 43.1.12 場時序圖

圖 43.1.13 信號含義
LINE_VALID:數據有效使能。當其為高時,輸出的數據為有效數據。
FRAME_VALID:幀(場) 同步信號。當此信號有效的時候就表示開始顯示新的一幀數據。
43.2實驗任務
本節實驗任務是使用新起點開發板及MT9V034攝像頭實現圖像采集,并通過TFT-LCD接口驅動RGB LCD液晶屏(支持目前正點原子推出的所有RGB LCD屏),并實時顯示出圖像。
43.3硬件設計
新起點FPGA開發板上有一個攝像頭擴展接口,該接口可以用來連接MT9V034/OV5640等攝像頭模塊,攝像頭擴展接口原理圖如圖 43.3.1所示:

圖 43.3.1 攝像頭擴展接口原理圖

圖 43.3.2 攝像頭接口
ATK-MT9V034是正點原子推出的一款高性能36W像素高清攝像頭模塊。該模塊通過2*9排針(2.54mm間距)同外部連接,我們將攝像頭的排針直接插在開發板上的攝像頭接口即可,如下圖所示:

圖 43.3.3 MT9V034攝像頭連接開發板圖
前面說過,MT9V034在YUV模式中有效數據是D[9:0],而我們的攝像頭排針上數據引腳的個數是8位,而攝像頭排針上的8位數據連接的就是MT9V034傳感器的D[9:2],所以我們直接使用攝像頭排針上的8位數據引腳即可。
需要注意的是,由圖 43.3.1可知,攝像頭擴展口的第18個引腳定義為CMOS_PWDN,而我們的MT9V034攝像頭模塊的STB(CMOS_PWDN)引腳固定為低電平,也就是一直處于正常工作模式。MT9V034攝像頭接口的第18個引腳定義為EXP,這個引腳是攝像頭外部觸發脈沖的引腳,只在快照模式下啟用它。MT9V034攝像頭模塊內部自帶24M晶振的,所以不需要FPGA輸出時鐘給攝像頭。
由于LCD接口和SDRAM引腳數目較多且在前面相應的章節中已經給出它們的管腳列表,這里只列出攝像頭相關管腳分配,如下表所示:
表 43.3.1 MT9V034攝像頭管腳分配

攝像頭TCL約束文件如下:
set_location_assignment PIN_T14 -to cmos_data[7]
set_location_assignment PIN_R14 -to cmos_data[6]
set_location_assignment PIN_N6 -to cmos_data[5]
set_location_assignment PIN_P6 -to cmos_data[4]
set_location_assignment PIN_M8 -to cmos_data[3]
set_location_assignment PIN_N8 -to cmos_data[2]
set_location_assignment PIN_P8 -to cmos_data[1]
set_location_assignment PIN_K9 -to cmos_data[0]
set_location_assignment PIN_M9 -to cmos_href
set_location_assignment PIN_R13 -to cmos_pclk
set_location_assignment PIN_R12 -to cmos_pwdn
set_location_assignment PIN_L9 -to cmos_reset
set_location_assignment PIN_N9 -to cmos_scl
set_location_assignment PIN_L10 -to cmos_sda
set_location_assignment PIN_P9 -to cmos_vsync
43.4程序設計
圖 43.4.1是根據本章實驗任務畫出的系統框圖。

圖 43.4.1 頂層系統框圖
由上圖可知,時鐘模塊(pll_clk)為LCD頂層模塊、SDRAM控制模塊以及I2C驅動模塊提供驅動時鐘。I2C配置模塊和I2C驅動模塊控制著傳感器初始化的開始與結束,傳感器初始化完成后圖像采集模塊將采集到的數據寫入SDRAM控制模塊,LCD頂層模塊從SDRAM控制模塊中讀出數據,完成了數據的采集、緩存與顯示。需要注意的是圖像數據采集模塊是在SDRAM和傳感器都初始化完成之后才開始輸出數據的,避免了在SDRAM初始化過程中向里面寫入數據。
MT9V034雖然在上電后不配置寄存器也能正常工作,但是此時輸出的分辨率可能不是實驗需要的分辨率,所以必須通過配置寄存器的值來達到實驗所需要的分辨率。配置寄存器的協議和I2C協議在寫操作時幾乎一樣,所以需要一個I2C驅動模塊。為了使MT9V034在期望的模式下運行并且提高圖像顯示效果,需要配置較多的寄存器,這么多寄存器的地址與參數需要單獨放在一個模塊,因此還需要一個寄存配置信息的I2C配置模塊。在攝像頭配置完成后,開始輸出圖像數據,因此需要一個攝像頭圖像采集模塊來采集圖像;采集到的圖像先進入SDRAM存儲器進行緩存,最后LCD頂層模塊讀取SDRAM緩存的數據以達到最終實時顯示的效果。
對比“OV7725攝像頭TFT-LCD顯示實驗”的系統框圖可以發現,本次實驗只是把外設OV7725模塊替換成了MT9V034模塊,替換了圖像采集模塊和IIC配置模塊,修改了IIC驅動模塊和SDRAM讀寫模塊,其余模塊基本相同。替換圖像采集模塊和修改圖像采集頂層模塊的原因在于OV7725攝像頭輸出的是RGB565格式的16bit數據,而MT9V034輸出的是YUV格式的8bit數據;替換IIC配置模塊和修改IIC驅動模塊的原因在于OV7725的一個寄存器地址只寫8bit數據,而MT9V034的一個寄存器地址可以寫16bit數據;本次實驗所采用的攝像頭 MT9V034的幀率為62幀,而LCD的屏幕的幀率有的比攝像頭低,有的比攝線頭高,而之前所采用的攝像頭OV5640和OV7725的幀率都比LCD屏的幀率低,因此兩幀的乒乓操作足以滿足之前的設計需求,但相對于本次實驗來說兩幀的乒乓操作已經不能滿足設計需求,所以需要修改SDRAM讀寫模塊。SDRAM讀寫模塊修改后的幀切換原理如下所示:

圖 43.4.2 寫比讀快的示意圖

圖 43.4.3 讀比寫快的示意圖
在圖 43.4.2中的圖2是寫操作完成了一幀的存儲,換了一個存儲空間繼續寫,而讀操作還沒有讀完一幀數據,繼續讀原來的存儲空間;因為讀幀率和寫幀率的幀率比沒有2倍,所以寫操作端的第二幀還沒有寫完,讀操作端已經讀完了第一幀,換了一個存儲空間繼續讀,如圖3所示; 圖4中寫操作端完成了第二幀的存儲,而讀操作還沒有讀完第二幀數據;同理圖5中寫操作端完成了第三幀的存儲,開始第四幀的寫入,而讀操作將要讀完第二幀數據;圖6表示讀操作讀完第二幀數據,而寫操作端沒有完成第四幀的存儲,這里將存儲空間跳轉了2個,就是為了防止寫操作追上讀操作,出現畫面撕裂的現象。
在圖 43.4.3中圖2是讀操作讀出了一幀的數據,而本次實驗是根據寫存儲空間來判斷讀存儲空間的,所以繼續讀之前的存儲空間;圖3是寫操作端完成了第一幀的存儲,而讀操作還沒有讀完第二幀數據;圖4是讀操作端讀完第二幀數據,而寫操作還沒有完成了第二幀的存儲。
頂層模塊的原理圖如下圖所示:

圖 43.4.4 頂層模塊原理圖
FPGA頂層模塊(mt9v034_rgb565_lcd)例化了以下六個模塊:時鐘模塊(pll_clk)、I2C驅動模塊(i2c_dri)、I2C配置模塊(i2c_cfg)、圖像采集頂層模塊(cmos_data_top)、SDRAM控制模塊(sdram_top)和LCD頂層模塊(lcd_rgb_top)。
時鐘模塊(pll_clk):時鐘模塊通過調用PLL IP核實現,共輸出3個時鐘,頻率分別為100Mhz(SDRAM參考時鐘)、100Mhz偏移負75度時鐘(用于SDRAM輸出采樣的偏移時鐘)和50Mhz時鐘,50Mhz時鐘作為I2C驅動模塊和LCD頂層模塊的驅動時鐘。
I2C驅動模塊(i2c_dri):I2C驅動模塊負責驅動MT9V034的兩線式接口總線,用戶可根據該模塊提供的用戶接口可以很方便的對MT9V034的寄存器進行配置,該模塊和“EEPROM讀寫實驗”章節中用到的I2C驅動模塊為同一個模塊,有關該模塊的詳細介紹請大家參考“EEPROM讀寫實驗”章節。
I2C配置模塊(i2c_cfg):I2C配置模塊的驅動時鐘是由I2C驅動模塊輸出的時鐘提供的,這樣方便了I2C驅動模塊和I2C配置模塊之間的數據交互。該模塊寄存需要配置的寄存器地址和數據,同時該模塊輸出MT9V034的寄存器地址和數據以及控制I2C驅動模塊開始執行的控制信號,直接連接到I2C驅動模塊的用戶接口,從而完成對MT9V034傳感器的配置。
圖像采集頂層模塊(top_cmos_data):攝像頭采集模塊在像素時鐘的驅動下將傳感器輸出的場同步信號、行同步信號以及8位數據轉換成SDRAM控制模塊的寫使能信號和16位寫數據信號,完成對MT9V034傳感器圖像的采集。如果LCD屏的分辨率小于MT9V034的分辨率,還要對MT9V034采集的數據進行裁剪,以匹配LCD屏的分辨率。
SDRAM控制模塊(sdram_top):SDRAM讀寫控制器模塊負責驅動SDRAM片外存儲器,緩存圖像傳感器輸出的圖像數據。該模塊將復雜的讀寫操作封裝成類似FIFO的用戶接口,非常方便用戶的使用。有關SDRAM控制模塊的詳細介紹請大家參考“SDRAM讀寫實驗”章節。
LCD頂層模塊(lcd_rgb_top):LCD頂層模塊負責驅動LCD屏的驅動信號的輸出,同時為其他模塊提供屏體參數、場同步信號和數據請求信號。有關LCD驅動模塊的詳細介紹請大家參考“OV7725攝像頭RGB-LCD顯示實驗”章節。
頂層模塊大部分的代碼在介紹“OV7725攝像頭RGB-LCD顯示實驗”章節時已經介紹過了,這里不再詳述,但還有部分代碼做了改動,改動的代碼如下:

41 //parameter define 42 parameter SLAVE_ADD = 7'b1001_000 ; //slave address 43 parameter BIT_CTRL = 1'b0 ; //MT9V034的字節地址為8位 0:8位 1:16位 44 parameter DATA_CTRL = 1'b1 ; //MT9V034的數據為16位 0:8位 1:16位 45 parameter CLK_FREQ = 26'd50_000_000 ; //i2c_dri模塊的驅動時鐘頻率 50.0MHz 46 parameter I2C_FREQ = 18'd250_000 ; //I2C的SCL時鐘頻率,不超過400KHz

程序的第42行,修改了器件的地址。
程序的第44行,添加了參數DATA_CTRL,用以區分一個寄存器地址是寫16位數據還是8位數據。

135 //圖像采集頂層模塊 136 cmos_data_top u_cmos_data_top( 137 .rst_n (sys_init_done), //系統初始化完成之后再開始采集數據 138 .clk_cmos (clk_24m), //24MHz CMOS Driver clock input 139 .cam_pclk (cmos_pclk), 140 .cmos_xclk (cmos_xclk), //24MHz drive clock 141 .cam_vsync (cmos_vsync), 142 .cam_href (cmos_href), 143 .cam_data (cmos_data), 144 .lcd_id (lcd_id), 145 .h_disp (h_disp), 146 .v_disp (v_disp), 147 .h_pixel (h_pixel), 148 .v_pixel (v_pixel), 149 .sdram_addr_max (sdram_addr_max), 150 .cmos_frame_vsync (cmos_frame_vsync), 151 .cmos_frame_href (cmos_frame_href), 152 .cmos_frame_valid (cmos_frame_valid), //數據有效使能信號 153 .cmos_frame_data (wr_data) //有效數據 154 );

在程序的第139行,信號cmos_pclk是攝像頭產生的輸入時鐘,即攝像頭數據的采樣時鐘。
在程序的第140行,信號cmos_xclk是攝像頭的輸入時鐘,但本次實驗的攝像頭采用的是外接24M時鐘的晶振,所以不需要cmos_xclk,但這里還是將這個信號保留下來。
I2C配置模塊寄存需要配置的寄存器地址、數據以及控制初始化的開始與結束,代碼如下所示:

1 module i2c_cfg( 2 input clk , 3 input rst_n , 4 input i2c_done , 5 output reg i2c_exec , 6 output reg [7:0] i2c_addr , 7 output reg [15:0] i2c_wr_data , 8 output reg cfg_done //配置寄存器結束 9 ); 10 //parameter define 11 parameter DELAY_MAX = 8'hff ; 12 parameter ROW_NUM = 16'd480; //行數 13 parameter COL_NUM = 16'd640; //列數 14 15 //reg define 16 reg [7:0] delay_cnt ; 17 reg delay_done ; 18 reg [3:0] cfg_cnt ; 19 20 //***************************************************** 21 //** main code 22 //***************************************************** 23 24 always @(posedge clk or negedge rst_n) 25 begin 26 if(rst_n==1'b0) begin 27 delay_cnt <= 1'b0 ; 28 delay_done <= 1'b0 ; 29 end 30 else begin 31 delay_done <= 1'b0 ; 32 if(i2c_done) begin 33 delay_cnt <= 1'b0 ; 34 end 35 else if(delay_cnt<DELAY_MAX) begin 36 delay_cnt <= delay_cnt +1'b1 ; 37 if(delay_cnt==DELAY_MAX-1'b1) begin 38 delay_done <= 1'b1 ; 39 end 40 end 41 end 42 end 43 44 always @(posedge clk or negedge rst_n) 45 begin 46 if(rst_n==1'b0) begin 47 i2c_exec <= 1'b0; 48 i2c_addr <= 1'b0; 49 i2c_wr_data <= 1'b0; 50 cfg_cnt <= 1'b0; 51 end 52 else begin 53 i2c_exec <= 1'b0; 54 if(cfg_done==1'b0) begin 55 if(delay_done) begin 56 cfg_cnt <= cfg_cnt + 1'b1; 57 case(cfg_cnt) 58 4'd0 : begin 59 i2c_exec <= 1'b1; 60 i2c_addr <= 8'h03;//03 61 i2c_wr_data <= ROW_NUM; 62 end 63 4'd1 : begin 64 i2c_exec <= 1'b1; 65 i2c_addr <= 8'h04; 66 i2c_wr_data <= COL_NUM; 67 end 68 default : ; 69 endcase 70 end 71 end 72 end 73 end 74 75 always @(posedge clk or negedge rst_n)begin 76 if(rst_n==1'b0) 77 cfg_done <= 1'b0 ; 78 else if(cfg_cnt=='d2 && i2c_done) 79 cfg_done <= 1'b1 ; 80 else 81 cfg_done <= cfg_done ; 82 end 83 84 endmodule

在程序的第11行,定義了一個DELAY_MAX參數,用以保證在上電的時候不會立即配置寄存器,而是等待一段時間后再配置。
在程序的第12和13行定義了2個參數,即本次實驗所需要的攝像頭的分辨率。
在程序的第24至第42行,是用來對延時的計數器進行計數和清零。
在程序的第44行和73行,是對攝像頭的行場分辨率進行配置。在第58行是設置需要配置寄存器的個數。
在程序的第75行和82行,是產生寄存器配置結束信號。
I2C驅動模塊做了以下修改:

116 st_addr8: begin //8位字地址 117 if(st_done) begin 118 if(wr_flag==1'b0) //讀寫判斷 119 if(!data_ctrl) 120 next_state = st_data_wr_8; 121 else 122 next_state = st_data_wr_16; 123 else 124 next_state = st_addr_rd; 125 end 126 else begin 127 next_state = st_addr8; 128 end 129 end 130 st_data_wr_16: begin //寫數據(8 bit) 131 if(st_done) 132 next_state = st_data_wr_8; 133 else 134 next_state = st_data_wr_16; 135 end 136 st_data_wr_8: begin //寫數據(8 bit) 137 if(st_done) 138 next_state = st_stop; 139 else 140 next_state = st_data_wr_8; 141 end

代碼116行至129行表示當狀態發生跳轉并且data_ctrl為1的時候,將狀態跳轉到st_data_wr_16,進行16位數據的讀寫,否則跳轉到其他狀態。
代碼130行至135行表示當st_data_wr_16狀態完成時,將狀態跳轉到st_data_wr_8,因為我們的16位數據讀寫其實是分兩部分完成的st_data_wr_16只進行了高8位的讀寫,剩下低8位的數據還是在st_data_wr_8狀態完成的。

337 st_data_wr_16: begin //寫高數據(8 bit) 338 case(cnt) 339 7'd0: begin 340 sda_out <= data_wr_t[15]; //I2C寫高8位數據 341 sda_dir <= 1'b1; 342 end 343 7'd1 : scl <= 1'b1; 344 7'd3 : scl <= 1'b0; 345 7'd4 : sda_out <= data_wr_t[14]; 346 7'd5 : scl <= 1'b1; 347 7'd7 : scl <= 1'b0; 348 7'd8 : sda_out <= data_wr_t[13]; 349 7'd9 : scl <= 1'b1; 350 7'd11: scl <= 1'b0; 351 7'd12: sda_out <= data_wr_t[12]; 352 7'd13: scl <= 1'b1; 353 7'd15: scl <= 1'b0; 354 7'd16: sda_out <= data_wr_t[11]; 355 7'd17: scl <= 1'b1; 356 7'd19: scl <= 1'b0; 357 7'd20: sda_out <= data_wr_t[10]; 358 7'd21: scl <= 1'b1; 359 7'd23: scl <= 1'b0; 360 7'd24: sda_out <= data_wr_t[9]; 361 7'd25: scl <= 1'b1; 362 7'd27: scl <= 1'b0; 363 7'd28: sda_out <= data_wr_t[8]; 364 7'd29: scl <= 1'b1; 365 7'd31: scl <= 1'b0; 366 7'd32: begin 367 sda_dir <= 1'b0; 368 sda_out <= 1'b1; 369 end 370 7'd33: scl <= 1'b1; 371 7'd34: begin //從機應答 372 st_done <= 1'b1; 373 if(sda_in == 1'b1) //高電平表示未應答 374 i2c_ack <= 1'b1; //拉高應答標志位 375 end 376 7'd35: begin 377 scl <= 1'b0; 378 cnt <= 1'b0; 379 end 380 default : ; 381 endcase 382 end 383 st_data_wr_8: begin //寫數據(8 bit) 384 case(cnt) 385 7'd0: begin 386 sda_out <= data_wr_t[7]; //I2C寫低8位數據 387 sda_dir <= 1'b1; 388 end 389 7'd1 : scl <= 1'b1; 390 7'd3 : scl <= 1'b0; 391 7'd4 : sda_out <= data_wr_t[6]; 392 7'd5 : scl <= 1'b1; 393 7'd7 : scl <= 1'b0; 394 7'd8 : sda_out <= data_wr_t[5]; 395 7'd9 : scl <= 1'b1; 396 7'd11: scl <= 1'b0; 397 7'd12: sda_out <= data_wr_t[4]; 398 7'd13: scl <= 1'b1; 399 7'd15: scl <= 1'b0; 400 7'd16: sda_out <= data_wr_t[3]; 401 7'd17: scl <= 1'b1; 402 7'd19: scl <= 1'b0; 403 7'd20: sda_out <= data_wr_t[2]; 404 7'd21: scl <= 1'b1; 405 7'd23: scl <= 1'b0; 406 7'd24: sda_out <= data_wr_t[1]; 407 7'd25: scl <= 1'b1; 408 7'd27: scl <= 1'b0; 409 7'd28: sda_out <= data_wr_t[0]; 410 7'd29: scl <= 1'b1; 411 7'd31: scl <= 1'b0; 412 7'd32: begin 413 sda_dir <= 1'b0; 414 sda_out <= 1'b1; 415 end 416 7'd33: scl <= 1'b1; 417 7'd34: begin //從機應答 418 st_done <= 1'b1; 419 if(sda_in == 1'b1) //高電平表示未應答 420 i2c_ack <= 1'b1; //拉高應答標志位 421 end 422 7'd35: begin 423 scl <= 1'b0; 424 cnt <= 1'b0; 425 end 426 default : ; 427 endcase 428 end

代碼337行至382行,表示寫入數據的高8位。
代碼383行至428行,表示寫入數據的低8位。
圖像采集頂層模塊的原理圖如下圖所示:

圖 43.4.5 圖像采集頂層模塊原理圖(局部)
圖像采集頂層模塊(top_cmos_data)例化了以下二個模塊:圖像采集模塊(cmos_capture_raw_gray)、圖像裁剪模塊(cmos_tailor)。有關圖像采集頂層模塊的詳細介紹請大家參考“OV7725攝像頭TFT-LCD顯示實驗”章節。
由上圖可知,圖像采集模塊(cmos_capture_raw_gray)為其他模塊提供攝像頭8bit輸入數據和數據使能以及攝像頭穩定后的行場信號。圖像裁剪模塊(cmos_tailor)只有在LCD的器件ID為16’h4342時起作用,即攝像頭的分辨率大于LCD屏的分辨率,起到裁剪圖像數據,使圖像的有效數據達到匹配LCD屏的尺寸。有關圖像裁剪模塊的詳細介紹請大家參考“OV7725攝像頭TFT-LCD顯示實驗”章節。
圖像采集模塊的代碼如下:

1 module cmos_capture_raw_gray 2 #( 3 parameter CMOS_FRAME_WAITCNT = 4'd10 //等待數據穩定所需要的幀數 4 5 ) 6 ( 7 //global clock 8 input clk_cmos, //鎖相環分頻時鐘 9 input rst_n, //復位信號,低有效 10 11 //CMOS Sensor Interface 12 input cmos_pclk, //攝像頭輸入時鐘 13 output cmos_xclk, //攝像頭驅動時鐘 14 input cmos_vsync, //攝像頭場信號 15 input cmos_href, //攝像頭行信號 16 input [7:0] cmos_data, //攝像頭數據 17 18 //CMOS SYNC Data output 19 output cmos_frame_vsync, //攝像頭場有效信號 20 output cmos_frame_href, //攝像頭行有效信號 21 output[15:0]wr_data, //攝像頭有效數據 22 output cmos_frame_clken, //攝像頭數據有效使能 23 24 //user interface 25 output[7:0] cmos_fps_rate //攝像頭幀率 26 ); 27 28 //parameter define 29 localparam DELAY_TOP = 2 * 24_000000; //2s delay 30 31 //reg define 32 reg [27:0] delay_cnt; 33 reg frame_sync_flag; 34 reg [3:0] cmos_fps_cnt; 35 reg [1:0] cmos_vsync_r, cmos_href_r; 36 reg [7:0] cmos_data_r0, cmos_data_r1; 37 reg [8:0] cmos_fps_cnt2; 38 reg [7:0] cmos_fps_rate; 39 40 //wire define 41 wire cmos_vsync_end; 42 wire delay_2s; 43 wire [7:0] cmos_frame_data; 44 45 //***************************************************** 46 //** main code 47 //***************************************************** 48 49 assign cmos_vsync_end = (cmos_vsync_r[1] & ~cmos_vsync_r[0]) ? 1'b1 : 1'b0; 50 assign cmos_xclk = clk_cmos; //24MHz CMOS XCLK output 51 assign cmos_frame_clken = frame_sync_flag ? cmos_href_r[1] : 1'b0; 52 assign cmos_frame_vsync = frame_sync_flag ? cmos_vsync_r[1] : 1'b0;//DFF 2 clocks 53 assign cmos_frame_href = frame_sync_flag ? cmos_href_r[1] : 1'b0; //DFF 2 clocks 54 assign cmos_frame_data = frame_sync_flag ? cmos_data_r1 : 8'd0; //DFF 2 clocks 55 assign delay_2s = (delay_cnt == DELAY_TOP - 1'b1) ? 1'b1 : 1'b0; 56 assign wr_data = {cmos_frame_data[7:3],cmos_frame_data[7:2],cmos_frame_data[7:3]}; 57 58 always@(posedge cmos_pclk or negedge rst_n)begin 59 if(!rst_n) 60 begin 61 cmos_vsync_r <= 0; 62 cmos_href_r <= 0; 63 {cmos_data_r1, cmos_data_r0} <= 0; 64 end 65 else 66 begin 67 cmos_vsync_r <= {cmos_vsync_r[0], cmos_vsync}; 68 cmos_href_r <= {cmos_href_r[0], cmos_href}; 69 {cmos_data_r1, cmos_data_r0} <= {cmos_data_r0, cmos_data}; 70 end 71 end 72 73 //Wait for Sensor output Data valid 10 Frame of OmniVision 74 always@(posedge cmos_pclk or negedge rst_n)begin 75 if(!rst_n) 76 cmos_fps_cnt <= 0; 77 else //Wait until cmos init complete 78 begin 79 if(cmos_fps_cnt < CMOS_FRAME_WAITCNT) 80 cmos_fps_cnt <= cmos_vsync_end ? cmos_fps_cnt + 1'b1 : cmos_fps_cnt; 81 else 82 cmos_fps_cnt <= CMOS_FRAME_WAITCNT; 83 end 84 end 85 86 //Come ture frame synchronization to ignore error frame or has not capture when vsync begin 87 always@(posedge cmos_pclk or negedge rst_n)begin 88 if(!rst_n) 89 frame_sync_flag <= 0; 90 else if(cmos_fps_cnt == CMOS_FRAME_WAITCNT && cmos_vsync_end == 1) 91 frame_sync_flag <= 1; 92 else 93 frame_sync_flag <= frame_sync_flag; 94 end 95 96 //Delay 2s for cmos fps counter 97 always@(posedge cmos_pclk or negedge rst_n)begin 98 if(!rst_n) 99 delay_cnt <= 0; 100 else if(delay_cnt < DELAY_TOP - 1'b1) 101 delay_cnt <= delay_cnt + 1'b1; 102 else 103 delay_cnt <= 0; 104 end 105 106 //cmos image output rate counter 107 always@(posedge cmos_pclk or negedge rst_n)begin 108 if(!rst_n) 109 begin 110 cmos_fps_cnt2 <= 0; 111 cmos_fps_rate <= 0; 112 end 113 else if(delay_2s == 1'b0) //time is not reached 114 begin 115 cmos_fps_cnt2 <= cmos_vsync_end ? cmos_fps_cnt2 + 1'b1 : cmos_fps_cnt2; 116 cmos_fps_rate <= cmos_fps_rate; 117 end 118 else //time up 119 begin 120 cmos_fps_cnt2 <= 0; 121 cmos_fps_rate <= cmos_fps_cnt2[8:1]; //divide by 2 122 end 123 end 124 125 endmodule

CMOS圖像采集模塊第3行定義了參數CMOS_FRAME_WAITCNT(寄存器數據穩定等待的幀個數),這里設置等待幀是為了保證攝像頭輸出穩定后才采樣數據。這里采集場同步信號的上升沿來統計幀數,計數器計數超過10次之后產生數據有效的標志(frame_sync_flag),開始采集圖像。
在程序的第56行實現了8位數據轉16位數據的功能,這里將8位的灰度數據按照高位賦值的方式將數據按照RGB565的格式分別賦給各個顏色分量。需要注意的是攝像頭的圖像數據是在像素時鐘(cam_pclk)下輸出的,因此攝像頭的圖像數據必須使用像素鐘來采集,否則會造成數據采集錯誤。
在程序的第97行至104行,是對2s的時間進行計數。
在程序的第107行至123行,是對攝像頭的幀率進行計數。在113行至117行,當2s的時間未到且當場信號的下降沿到來時,對幀率計數器進行累加,當2s的時間到來時,對幀率計數器進行清零,把幀率計數器除以2的值賦給幀率寄存器。
SDRAM讀寫模塊做了以下修改:

135 //sdram寫地址產生模塊 136 always @(posedge clk_ref or negedge rst_n) begin 137 if (!rst_n) begin 138 sdram_wr_addr <= 24'd0; 139 sw_bank_en <= 1'b0; 140 rw_bank_flag <= 1'b0; 141 end 142 else if(wr_load_flag) begin //檢測到寫端口復位信號時,寫地址復位 143 sdram_wr_addr <= wr_min_addr; 144 sw_bank_en <= 1'b0; 145 rw_bank_flag <= 1'b0; 146 end 147 else if(write_done_flag) begin //若突發寫SDRAM結束,更改寫地址 148 //若未到達寫SDRAM的結束地址,則寫地址累加 149 if(sdram_pingpang_en) begin //SDRAM 讀寫乒乓使能 150 if(sdram_wr_addr[21:0] < wr_max_addr - wr_length) 151 sdram_wr_addr <= sdram_wr_addr + wr_length; 152 else begin //切換BANK 153 rw_bank_flag <= rw_bank_flag+1; 154 sw_bank_en <= 1'b1; //拉高切換BANK使能信號 155 end 156 end 157 //若突發寫SDRAM結束,更改寫地址 158 else if(sdram_wr_addr < wr_max_addr - wr_length) 159 sdram_wr_addr <= sdram_wr_addr + wr_length; 160 else //到達寫SDRAM的結束地址,回到寫起始地址 161 sdram_wr_addr <= wr_min_addr; 162 end 163 else if(sw_bank_en) begin //到達寫SDRAM的結束地址,回到寫起始地址 164 sw_bank_en <= 1'b0; 165 sdram_wr_addr <= {rw_bank_flag,wr_min_addr[21:0]}; 166 end 167 end 168 169 //sdram讀地址產生模塊 170 always @(posedge clk_ref or negedge rst_n) begin 171 if(!rst_n) begin 172 sdram_rd_addr <= 24'd0; 173 end 174 else if(rd_load_flag) //檢測到讀端口復位信號時,讀地址復位 175 sdram_rd_addr <= rd_min_addr; 176 else if(read_done_flag) begin //突發讀SDRAM結束,更改讀地址 177 //若未到達讀SDRAM的結束地址,則讀地址累加 178 if(sdram_pingpang_en) begin //SDRAM 讀寫乒乓使能 179 if(sdram_rd_addr[21:0] < rd_max_addr - rd_length) 180 sdram_rd_addr <= sdram_rd_addr + rd_length; 181 else begin //到達讀SDRAM的結束地址,回到讀起始地址 182 sdram_rd_addr <= {rw_bank_flag+2,rd_min_addr[21:0]}; 183 end 184 end 185 //若突發寫SDRAM結束,更改寫地址 186 else if(sdram_rd_addr < rd_max_addr - rd_length) 187 sdram_rd_addr <= sdram_rd_addr + rd_length; 188 else //到達寫SDRAM的結束地址,回到寫起始地址 189 sdram_rd_addr <= rd_min_addr; 190 end 191 end

SDRAM控制模塊的改動是非常小的,主要就是讀寫地址乒乓操作稍微改了一下,在上文我們已經講解過,因為攝像頭輸入速率和LCD顯示屏不匹配(有的輸入大于輸出有的輸入小于輸出)原本的的雙BANK乒乓操作已經不再適用,會有畫面撕裂的現象。因此本節實驗使用四個BANK去進行讀寫切換,確保讀寫不會發生沖突。在代碼的第153行定義了寫地址BANK的累加,每當完成一幀圖片的寫入,BANK地址就會加一,之后在代碼第165行更新寫地址。而代碼182行則是讀地址的切換操作,每當讀完一幀圖片信息后,讀地址的BANK會根據當前寫地址BANK進行切換,始終保持和寫BANK地址相差2,這樣寫就不會追上讀了,確保圖片不會出現撕裂現象。
到這里本節實驗的程序設計部分就全部講解完了,如果有不清楚的可以去翻看前面的例程。
43.5下載驗證
首先將FPC排線一端與RGB LCD模塊上的J1接口連接,另一端與新起點開發板上的RGB TFTLCD接口連接。連接時,先掀開FPC連接器上的黑色翻蓋,將FPC排線藍色面朝上插入連接器,最后將黑色翻蓋壓下以固定FPC排線,如圖 43.5.1和圖 43.5.2所示。

圖 43.5.1 正點原子RGBLCD模塊FPC連接器

圖 43.5.2 A7開發板連接RGB LCD液晶屏
接下來分別連接JTAG接口和電源線,并打開電源開關。
最后將下載器一端連電腦,另一端與開發板上的JTAG端口連接,連接電源線并打開電源開關。
接下來我們下載程序,驗證MT9V034 TFT-LCD實時顯示功能。下載完成后觀察RGB LCD模塊顯示的圖案如下圖所示,說明MT9V034 TFT-LCD實時顯示程序下載驗證成功。

圖 43.5.3 RGB TFT-LCD實時顯示圖像

總結

以上是生活随笔為你收集整理的【正点原子FPGA连载】第四十三章MT9V034摄像头RGB-LCD显示实验 -摘自【正点原子】新起点之FPGA开发指南_V2.1的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。