如何將CMOS所擷取的影像傳到PC端? (SOC) (DE2) (TRDB-DC2)

Abstract
DE2提供了Control Panel與Image Converter,可以將CMOS所擷取的影像傳到PC端,

Introduction
版權聲明:文中所有範例皆出自DE2光碟,版權歸友晶科技所有。
使用環境:Quartus II 7.2 SP1 + DE2(Cyclone II EP2C35F627C6) + TRDB_DC2

在友晶提供的DE2_CCD.7zDE2_CCD_detect.7z範例中,我們可以透過130萬像素的CMOS,將影像擷取到SDRAM中,若我們想將所擷取的影像傳到PC端作後續的處理, 可以透過DE2 Control Panel將SDRAM上的資料下載到PC,並使用Teasic Image Converter轉成bmp格式,所有的步驟在光碟中的TRDB_DC2 User Guide有詳細的說明。

這個方法套用在DE2_CCD.7z範例非常完美,可以擷取正確的影像,但若用相同的方式在DE2_CCD_detect.7z範例,將獲得如以下有問題的bmp影像。

capture1.gif


為什麼會這樣子呢?因為DE2_CCD.7zDE2_CCD_detect.7z兩個範例對於SDRAM使用的方式並不一樣。我們先來看看DE2_CCD.7z,在DE2_CCD.v的456行

 1  Sdram_Control_4Port u6 (
 2     //  HOST Side
 3    .REF_CLK(CLOCK_50),
 4    .RESET_N( 1 ' b1),
 5     //  FIFO Write Side 1
 6    .WR1_DATA({sCCD_G[ 9 : 5 ], sCCD_B[ 9 : 0 ]}),
 7    .WR1(sCCD_DVAL),
 8    .WR1_ADDR( 0 ),
 9    .WR1_MAX_ADDR( 640 * 512 ),
10    .WR1_LENGTH( 9 ' h100),
11    .WR1_LOAD( ! DLY_RST_0),
12    .WR1_CLK(CCD_PIXCLK),
13     //  FIFO Write Side 2
14    .WR2_DATA({sCCD_G[ 4 : 0 ], sCCD_R[ 9 : 0 ]}),
15    .WR2(sCCD_DVAL),
16    .WR2_ADDR( 22 ' h100000),
17    .WR2_MAX_ADDR( 22 ' h100000+640*512),
18    .WR2_LENGTH( 9 ' h100),
19    .WR2_LOAD( ! DLY_RST_0),
20    .WR2_CLK(CCD_PIXCLK),
21     //  FIFO Read Side 1
22    .RD1_DATA(Read_DATA1),
23    .RD1(Read),
24    .RD1_ADDR( 640 * 16 ),
25    .RD1_MAX_ADDR( 640 * 496 ),
26    .RD1_LENGTH( 9 ' h100),
27    .RD1_LOAD( ! DLY_RST_0),
28    .RD1_CLK(VGA_CTRL_CLK),
29     //  FIFO Read Side 2
30    .RD2_DATA(Read_DATA2),
31    .RD2(Read),
32    .RD2_ADDR( 22 ' h100000+640*16),
33    .RD2_MAX_ADDR( 22 ' h100000+640*496),
34    .RD2_LENGTH( 9 ' h100),
35    .RD2_LOAD( ! DLY_RST_0),
36    .RD2_CLK(VGA_CTRL_CLK),
37     //  SDRAM Side
38    .SA(DRAM_ADDR),
39    .BA({DRAM_BA_1,DRAM_BA_0}),
40    .CS_N(DRAM_CS_N),
41    .CKE(DRAM_CKE),
42    .RAS_N(DRAM_RAS_N),
43    .CAS_N(DRAM_CAS_N),
44    .WE_N(DRAM_WE_N),
45    .DQ(DRAM_DQ),
46    .DQM({DRAM_UDQM,DRAM_LDQM}),
47    .SDR_CLK(DRAM_CLK)
48  );


顯示了DE2_CCD.7z使用SDRAM的方式為

.WR1_DATA({sCCD_G[ 9 : 5 ], sCCD_B[ 9 : 0 ]}),
.WR2_DATA({sCCD_G[
4 : 0 ], sCCD_R[ 9 : 0 ]}),


這可以用以下的圖來表示

cmos_control_panel_00.gif


也就是說,DE2_CCD.7z用了兩個bank來存一個pixel的RGB,第一個bank存了R[9:0]與G[9:5],第二個bank存了G[4:0]與B[9:0],所以利用DE2 Control Panel分別抓下兩個bank的資料,再用Image Converter合併成bmp檔。

我們再來看看DE2_CCD_detect.7z如何使用SDRAM。在DE2_CCD_detect.v的450行

 1 Sdram_Control_4Port u6 (
 2    //  HOST Side
 3   .REF_CLK(CLOCK_50),
 4   .RESET_N( 1 ' b1),
 5    //  FIFO Write Side 1
 6   .WR1_DATA( {mCCD_R[9:5], mCCD_G[9:5], mCCD_B[9:5]}     ),
 7   .WR1(mCCD_DVAL_d),
 8   .WR1_ADDR( 0 ),
 9   .WR1_MAX_ADDR( 640 * 512 * 2 ),
10   .WR1_LENGTH( 9 ' h100),
11   .WR1_LOAD( ! DLY_RST_0),
12   .WR1_CLK(CCD_PIXCLK),
13    //  FIFO Read Side 1
14   .RD1_DATA(Read_DATA1),
15   .RD1(Read),
16   .RD1_ADDR( 640 * 16 ),
17   .RD1_MAX_ADDR( 640 * 496 ),
18   .RD1_LENGTH( 9 ' h100),
19   .RD1_LOAD( ! DLY_RST_0),
20   .RD1_CLK(VGA_CTRL_CLK),
21    //  FIFO Read Side 2
22   .RD2_DATA(Read_DATA2),
23   .RD2(Read),
24   .RD2_ADDR( 640 * 512 + 640 * 16 ),
25   .RD2_MAX_ADDR( 640 * 512 + 640 * 496 ),
26   .RD2_LENGTH( 9 ' h100),
27   .RD2_LOAD( ! DLY_RST_0),
28   .RD2_CLK(VGA_CTRL_CLK),
29    //  SDRAM Side
30   .SA(DRAM_ADDR),
31   .BA( {DRAM_BA_1,DRAM_BA_0} ),
32   .CS_N(DRAM_CS_N),
33   .CKE(DRAM_CKE),
34   .RAS_N(DRAM_RAS_N),
35   .CAS_N(DRAM_CAS_N),
36   .WE_N(DRAM_WE_N),
37   .DQ(DRAM_DQ),
38   .DQM( {DRAM_UDQM,DRAM_LDQM} ),
39   .SDR_CLK(DRAM_CLK)
40 );


顯示了DE2_CCD_detect.7z使用SDRAM的方式為

.WR1_DATA({mCCD_R[ 9 : 5 ], mCCD_G[ 9 : 5 ], mCCD_B[ 9 : 5 ]}),


若用圖表示則為

cmos_control_panel_01.gif


也就是說,DE2_CCD_detect.7z只用了一個bank來存1個pixel的RGB,可是每個bank只有16bit怎麼辦?只好犧牲一些畫質,只存R[9:5]、G[9:5]、B[9:5],所以若要從SDRAM抓下所擷取的影像,若用抓DE2_CCD.7z資料的方式,就會產生不正確的影像。

那要如何用DE2 Control Panel和Terasic Image Converter抓取DE2_CCD_detect.7z的影像呢?
Step1 :
從SDRAM抓取資料
一樣從SDRAM的記憶體位址0x2800開始抓,抓長度0x96000,存成檔名catpure2_gb.dat。

cmos_control_panel_02.gif


Step 2:
由capture2_gb.dat複製成capture2_gr.dat
TRDB_DC2 User Guide中要我們記憶體位址0x102800開始抓0x96000長度的資料存到capture2_gr.dat,但因為DE2_CCD_detect.7z只用了1個bank,所以我們不需這樣抓,只需將Step 1所抓的檔案複製成capture2_gr.dat即可。

Step 3:
使用Terasic Image Converter轉成bmp
利用Image Converter將capture2_gb.dat和capture2_gr.dat合併成capture2.bmp檔。

capture2.gif


眼尖的你一定發現,為什麼圖左右顛倒? 這是DE2_CCD_detect.7z範例的bug,請參閱(原創) 如何解決DE2範例DE2_CCD_detect左右相反的問題? (IC Design) (DE2) (Quartus II)

完整程式碼下載
友晶科技範例 DE2_CCD.7z
友晶科技範例 DE2_CCD_detect.7z
DE2 Control Panel
Teasic Image Converter

Conclusion
友晶原廠的TRDB_DC2 User Guide,只能針對DE2_CCD.7z,無法針對DE2_CCD_detect.7z,透過本文的方式,讓我們可以利用 DE2 Control PanelTeasic Image ConverterDE2_CCD_detect.7z所擷取的影像傳到PC端,也讓我們更清楚兩個範例使用SDRAM方式的不同。

Remark
或許你會問,我怎麼知道要從SDRAM記憶體位址的0x2800抓長度0x96000呢?在DE2_CCD.7z的DE2_CCD.v的480行

.RD1_ADDR( 640 * 16 ),
.RD1_MAX_ADDR(
640 * 496 ),


告訴我們從位址640*16開始讀取,最多讀到640*496。

640   *   16   =   10240   =   0x2800

640   *  ( 496 - 16 *   2   =   614400   =   0x96000


為什麼要*2呢?因為一個bank是16 bit,也就是2 byte,記憶體位址是用byte計算。

See Also
(原創) 如何解決DE2範例DE2_CCD_detect左右相反的問題? (IC Design) (DE2) (Quartus II)
(原創) 如何使用ANSI C讀寫24位元的BMP圖檔? (C/C++) (C) (Image Processing)
(原創) 如何使用ANSI C讀寫32位元的BMP圖檔? (C/C++) (C) (Image Processing)
(原創) 如何使用ANSI C讀寫24/32位元的BMP圖檔? (C/C++) (C) (Image Processing)
(原創) 如何將CMOS彩色影像轉換成灰階影像? (SOC) (DE2) 

你可能感兴趣的:(SOC)