(原創) 如何實現Real Time的Sobel Edge Detector? (SOC) (Verilog) (Image Processing) (DE2) (TRDB-DC2)
Abstract
之前討論過使用Verilog實現Sobel Edge Detector的原理與方式,用的是DE2-70平台,這次討論如何在DE2平台實現。
Introduction
使用環境:Quartus II 7.2 SP3 + DE2(Cyclone II EP2C35F627C6) + TRDB-DC2
在(原創) 如何實現Real Time的Sobel Edge Detector? (SOC) (Verilog) (Image Processing) (DE2-70) (TRDB-D5M),我曾經討論過用Verilog實現Sobel edge dector的原理與方式,用的是DE2-70,但DE2畢竟是大家最熟悉,也最流行的平台,所以這次來看看如何在DE2實現Sobel edge detector。
在DE2平台所需做的修改
我以DE2 CD的DE2_CCD範例為藍本,使用130萬像素的TRDB-DC2為輸入,VGA為輸出,將Sobel edge detector加到DE2上。Sobel.v的解釋請參考(原創) 如何實現Real Time的Sobel Edge Detector? (SOC) (Verilog) (Image Processing) (DE2-70) (TRDB-D5M),本文僅討論在DE2上所需做的修改。
Step 1:
修改Line Buffer長度
由於VGA為640 * 480,所以line buffer的長度只需640即可。
Step 2:
DE2_CCD.v所需的修改
DE2_CCD.v / Verilog
2 (C) OOMusou 2008 http://oomusou.cnblogs.com
3
4 Filename : DE2_CCD.v
5 Compiler : Quartus II 7.2 SP3
6 Description : Demo how to use 130m CMOS on DE2 with Sobel Edge Detector
7 Release : 08/30/2008 1.0
8 */
9
10 module DE2_CCD (
11 //////////////////////// Clock Input ////////////////////////
12 input CLOCK_27, // 27 MHz
13 input CLOCK_50, // 50 MHz
14 input EXT_CLOCK, // External Clock
15 //////////////////////// Push Button ////////////////////////
16 input [3:0] KEY, // Pushbutton[3:0]
17 //////////////////////// DPDT Switch ////////////////////////
18 input [17:0] SW, // Toggle Switch[17:0]
19 //////////////////////// 7-SEG Dispaly ////////////////////////
20 output [6:0] HEX0, // Seven Segment Digit 0
21 output [6:0] HEX1, // Seven Segment Digit 1
22 output [6:0] HEX2, // Seven Segment Digit 2
23 output [6:0] HEX3, // Seven Segment Digit 3
24 output [6:0] HEX4, // Seven Segment Digit 4
25 output [6:0] HEX5, // Seven Segment Digit 5
26 output [6:0] HEX6, // Seven Segment Digit 6
27 output [6:0] HEX7, // Seven Segment Digit 7
28 //////////////////////////// LED ////////////////////////////
29 output [8:0] LEDG, // LED Green[8:0]
30 output [17:0] LEDR, // LED Red[17:0]
31 //////////////////////////// UART ////////////////////////////
32 output UART_TXD, // UART Transmitter
33 input UART_RXD, // UART Receiver
34 //////////////////////////// IRDA ////////////////////////////
35 output IRDA_TXD, // IRDA Transmitter
36 input IRDA_RXD, // IRDA Receiver
37 /////////////////////// SDRAM Interface ////////////////////////
38 inout [15:0] DRAM_DQ, // SDRAM Data bus 16 Bits
39 output [11:0] DRAM_ADDR, // SDRAM Address bus 12 Bits
40 output DRAM_LDQM, // SDRAM Low-byte Data Mask
41 output DRAM_UDQM, // SDRAM High-byte Data Mask
42 output DRAM_WE_N, // SDRAM Write Enable
43 output DRAM_CAS_N, // SDRAM Column Address Strobe
44 output DRAM_RAS_N, // SDRAM Row Address Strobe
45 output DRAM_CS_N, // SDRAM Chip Select
46 output DRAM_BA_0, // SDRAM Bank Address 0
47 output DRAM_BA_1, // SDRAM Bank Address 0
48 output DRAM_CLK, // SDRAM Clock
49 output DRAM_CKE, // SDRAM Clock Enable
50 //////////////////////// Flash Interface ////////////////////////
51 inout [7:0] FL_DQ, // FLASH Data bus 8 Bits
52 output [21:0] FL_ADDR, // FLASH Address bus 22 Bits
53 output FL_WE_N, // FLASH Write Enable
54 output FL_RST_N, // FLASH Reset
55 output FL_OE_N, // FLASH Output Enable
56 output FL_CE_N, // FLASH Chip Enable
57 //////////////////////// SRAM Interface ////////////////////////
58 inout [15:0] SRAM_DQ, // SRAM Data bus 16 Bits
59 output [17:0] SRAM_ADDR, // SRAM Address bus 18 Bits
60 output SRAM_UB_N, // SRAM High-byte Data Mask
61 output SRAM_LB_N, // SRAM Low-byte Data Mask
62 output SRAM_WE_N, // SRAM Write Enable
63 output SRAM_CE_N, // SRAM Chip Enable
64 output SRAM_OE_N, // SRAM Output Enable
65 //////////////////// ISP1362 Interface ////////////////////////
66 inout [15:0] OTG_DATA, // ISP1362 Data bus 16 Bits
67 output [1:0] OTG_ADDR, // ISP1362 Address 2 Bits
68 output OTG_CS_N, // ISP1362 Chip Select
69 output OTG_RD_N, // ISP1362 Write
70 output OTG_WR_N, // ISP1362 Read
71 output OTG_RST_N, // ISP1362 Reset
72 output OTG_FSPEED, // USB Full Speed, 0 = Enable, Z = Disable
73 output OTG_LSPEED, // USB Low Speed, 0 = Enable, Z = Disable
74 input OTG_INT0, // ISP1362 Interrupt 0
75 input OTG_INT1, // ISP1362 Interrupt 1
76 input OTG_DREQ0, // ISP1362 DMA Request 0
77 input OTG_DREQ1, // ISP1362 DMA Request 1
78 output OTG_DACK0_N, // ISP1362 DMA Acknowledge 0
79 output OTG_DACK1_N, // ISP1362 DMA Acknowledge 1
80 //////////////////// LCD Module 16X2 ////////////////////////////
81 inout [7:0] LCD_DATA, // LCD Data bus 8 bits
82 output LCD_ON, // LCD Power ON/OFF
83 output LCD_BLON, // LCD Back Light ON/OFF
84 output LCD_RW, // LCD Read/Write Select, 0 = Write, 1 = Read
85 output LCD_EN, // LCD Enable
86 output LCD_RS, // LCD Command/Data Select, 0 = Command, 1 = Data
87 //////////////////// SD Card Interface ////////////////////////
88 inout SD_DAT, // SD Card Data
89 inout SD_DAT3, // SD Card Data 3
90 inout SD_CMD, // SD Card Command Signal
91 output SD_CLK, // SD Card Clock
92 //////////////////////// I2C ////////////////////////////////
93 inout I2C_SDAT, // I2C Data
94 output I2C_SCLK, // I2C Clock
95 //////////////////////// PS2 ////////////////////////////////
96 input PS2_DAT, // PS2 Data
97 input PS2_CLK, // PS2 Clock
98 //////////////////// USB JTAG link ////////////////////////////
99 input TDI, // CPLD -> FPGA (data in)
100 input TCK, // CPLD -> FPGA (clk)
101 input TCS, // CPLD -> FPGA (CS)
102 output TDO, // FPGA -> CPLD (data out)
103 //////////////////////// VGA ////////////////////////////
104 output VGA_CLK, // VGA Clock
105 output VGA_HS, // VGA H_SYNC
106 output VGA_VS, // VGA V_SYNC
107 output VGA_BLANK, // VGA BLANK
108 output VGA_SYNC, // VGA SYNC
109 output [9:0] VGA_R, // VGA Red[9:0]
110 output [9:0] VGA_G, // VGA Green[9:0]
111 output [9:0] VGA_B, // VGA Blue[9:0]
112 //////////////// Ethernet Interface ////////////////////////////
113 inout [15:0] ENET_DATA, // DM9000A DATA bus 16Bits
114 output ENET_CMD, // DM9000A Command/Data Select, 0 = Command, 1 = Data
115 output ENET_CS_N, // DM9000A Chip Select
116 output ENET_WR_N, // DM9000A Write
117 output ENET_RD_N, // DM9000A Read
118 output ENET_RST_N, // DM9000A Reset
119 input ENET_INT, // DM9000A Interrupt
120 output ENET_CLK, // DM9000A Clock 25 MHz
121 //////////////////// Audio CODEC ////////////////////////////
122 inout AUD_ADCLRCK, // Audio CODEC ADC LR Clock
123 input AUD_ADCDAT, // Audio CODEC ADC Data
124 inout AUD_DACLRCK, // Audio CODEC DAC LR Clock
125 output AUD_DACDAT, // Audio CODEC DAC Data
126 inout AUD_BCLK, // Audio CODEC Bit-Stream Clock
127 output AUD_XCK, // Audio CODEC Chip Clock
128 //////////////////// TV Devoder ////////////////////////////
129 input [7:0] TD_DATA, // TV Decoder Data bus 8 bits
130 input TD_HS, // TV Decoder H_SYNC
131 input TD_VS, // TV Decoder V_SYNC
132 output TD_RESET, // TV Decoder Reset
133 //////////////////////// GPIO ////////////////////////////////
134 inout [35:0] GPIO_0, // GPIO Connection 0
135 inout [35:0] GPIO_1 // GPIO Connection 1
136 );
137
138 // CCD
139 wire [9:0] CCD_DATA;
140 wire CCD_SDAT;
141 wire CCD_SCLK;
142 wire CCD_FLASH;
143 wire CCD_FVAL;
144 wire CCD_LVAL;
145 wire CCD_PIXCLK;
146 reg CCD_MCLK; // CCD Master Clock
147
148 wire [15:0] Read_DATA1;
149 wire [15:0] Read_DATA2;
150 wire VGA_CTRL_CLK;
151 wire AUD_CTRL_CLK;
152 wire [9:0] mCCD_DATA;
153 wire mCCD_DVAL;
154 wire mCCD_DVAL_d;
155 wire [10:0] X_Cont;
156 wire [10:0] Y_Cont;
157 wire [9:0] X_ADDR;
158 wire [31:0] Frame_Cont;
159 wire [9:0] mCCD_R;
160 wire [9:0] mCCD_G;
161 wire [9:0] mCCD_B;
162 wire DLY_RST_0;
163 wire DLY_RST_1;
164 wire DLY_RST_2;
165 wire Read;
166 reg [9:0] rCCD_DATA;
167 reg rCCD_LVAL;
168 reg rCCD_FVAL;
169 wire [9:0] sCCD_R;
170 wire [9:0] sCCD_G;
171 wire [9:0] sCCD_B;
172 wire sCCD_DVAL;
173
174 // sobel
175 wire [9:0] DISP_R;
176 wire [9:0] DISP_G;
177 wire [9:0] DISP_B;
178
179 wire [9:0] Gray_R;
180 wire [9:0] Gray_G;
181 wire [9:0] Gray_B;
182
183 wire [9:0] mVGA_R;
184 wire [9:0] mVGA_G;
185 wire [9:0] mVGA_B;
186 wire [9:0] Filter_Out;
187
188 assign LCD_ON = 1'b1;
189 assign LCD_BLON = 1'b1;
190 assign TD_RESET = 1'b1;
191
192 // All inout port turn to tri-state
193 assign FL_DQ = 8'hzz;
194 assign SRAM_DQ = 16'hzzzz;
195 assign OTG_DATA = 16'hzzzz;
196 assign LCD_DATA = 8'hzz;
197 assign SD_DAT = 1'bz;
198 assign I2C_SDAT = 1'bz;
199 assign ENET_DATA = 16'hzzzz;
200 assign AUD_ADCLRCK = 1'bz;
201 assign AUD_DACLRCK = 1'bz;
202 assign AUD_BCLK = 1'bz;
203
204
205 // For Sensor 1
206 assign CCD_DATA[0] = GPIO_1[0];
207 assign CCD_DATA[1] = GPIO_1[1];
208 assign CCD_DATA[2] = GPIO_1[5];
209 assign CCD_DATA[3] = GPIO_1[3];
210 assign CCD_DATA[4] = GPIO_1[2];
211 assign CCD_DATA[5] = GPIO_1[4];
212 assign CCD_DATA[6] = GPIO_1[6];
213 assign CCD_DATA[7] = GPIO_1[7];
214 assign CCD_DATA[8] = GPIO_1[8];
215 assign CCD_DATA[9] = GPIO_1[9];
216 assign GPIO_1[11] = CCD_MCLK;
217 assign CCD_FVAL = GPIO_1[13];
218 assign CCD_LVAL = GPIO_1[12];
219 assign CCD_PIXCLK = GPIO_1[10];
220
221 assign LEDR = SW;
222 assign LEDG = Y_Cont;
223 assign VGA_CTRL_CLK= CCD_MCLK;
224 assign VGA_CLK = ~CCD_MCLK;
225
226 // Gray
227 assign Gray_R = mVGA_G;
228 assign Gray_G = mVGA_G;
229 assign Gray_B = mVGA_G;
230
231 // To Display
232 assign DISP_R = SW[17] ? mVGA_G : // Gray
233 SW[16] ? Filter_Out : // Filter Out
234 mVGA_R ; // Color
235 assign DISP_G = SW[17] ? mVGA_G : // Gray
236 SW[16] ? Filter_Out : // Filter Out
237 mVGA_G; // Color
238 assign DISP_B = SW[17] ? mVGA_G : // Gray
239 SW[16] ? Filter_Out : // Filter Out
240 mVGA_B; // Color
241
242 assign mVGA_R = Read_DATA2[9:0];
243 assign mVGA_G = {Read_DATA1[14:10],Read_DATA2[14:10]};
244 assign mVGA_B = Read_DATA1[9:0];
245
246 always@(posedge CLOCK_50)
247 CCD_MCLK <= ~CCD_MCLK;
248
249 always@(posedge CCD_PIXCLK) begin
250 rCCD_DATA <= CCD_DATA;
251 rCCD_LVAL <= CCD_LVAL;
252 rCCD_FVAL <= CCD_FVAL;
253 end
254
255 VGA_Controller vga0 (
256 // Host Side
257 .oRequest(Read),
258 .iRed(DISP_R),
259 .iGreen(DISP_G),
260 .iBlue(DISP_B),
261 // VGA Side
262 .oVGA_R(VGA_R),
263 .oVGA_G(VGA_G),
264 .oVGA_B(VGA_B),
265 .oVGA_H_SYNC(VGA_HS),
266 .oVGA_V_SYNC(VGA_VS),
267 .oVGA_SYNC(VGA_SYNC),
268 .oVGA_BLANK(VGA_BLANK),
269 // Control Signal
270 .iCLK(VGA_CTRL_CLK),
271 .iRST_N(DLY_RST_2)
272 );
273
274 Reset_Delay reset0 (
275 .iCLK(CLOCK_50),
276 .iRST(KEY[0]),
277 .oRST_0(DLY_RST_0),
278 .oRST_1(DLY_RST_1),
279 .oRST_2(DLY_RST_2)
280 );
281
282 CCD_Capture capture0 (
283 .oDATA(mCCD_DATA),
284 .oDVAL(mCCD_DVAL),
285 .oX_Cont(X_Cont),
286 .oY_Cont(Y_Cont),
287 .oFrame_Cont(Frame_Cont),
288 .iDATA(rCCD_DATA),
289 .iFVAL(rCCD_FVAL),
290 .iLVAL(rCCD_LVAL),
291 .iSTART(!KEY[3]),
292 .iEND(!KEY[2]),
293 .iCLK(CCD_PIXCLK),
294 .iRST(DLY_RST_1)
295 );
296
297 RAW2RGB rgb0 (
298 .oRed(mCCD_R),
299 .oGreen(mCCD_G),
300 .oBlue(mCCD_B),
301 .oDVAL(mCCD_DVAL_d),
302 .iX_Cont(X_Cont),
303 .iY_Cont(Y_Cont),
304 .iDATA(mCCD_DATA),
305 .iDVAL(mCCD_DVAL),
306 .iCLK(CCD_PIXCLK),
307 .iRST(DLY_RST_1)
308 );
309
310 SEG7_LUT_8 seg0 (
311 .oSEG0(HEX0),
312 .oSEG1(HEX1),
313 .oSEG2(HEX2),
314 .oSEG3(HEX3),
315 .oSEG4(HEX4),
316 .oSEG5(HEX5),
317 .oSEG6(HEX6),
318 .oSEG7(HEX7),
319 .iDIG(Frame_Cont)
320 );
321
322 Sdram_Control_4Port sdram0 (
323 // HOST Side
324 .REF_CLK(CLOCK_50),
325 .RESET_N(1'b1),
326 // FIFO Write Side 1
327 .WR1_DATA({sCCD_G[9:5], sCCD_B[9:0]}),
328 .WR1(sCCD_DVAL),
329 .WR1_ADDR(0),
330 .WR1_MAX_ADDR(640*512),
331 .WR1_LENGTH(9'h100),
332 .WR1_LOAD(!DLY_RST_0),
333 .WR1_CLK(CCD_PIXCLK),
334 // FIFO Write Side 2
335 .WR2_DATA({sCCD_G[4:0], sCCD_R[9:0]}),
336 .WR2(sCCD_DVAL),
337 .WR2_ADDR(22'h100000),
338 .WR2_MAX_ADDR(22'h100000+640*512),
339 .WR2_LENGTH(9'h100),
340 .WR2_LOAD(!DLY_RST_0),
341 .WR2_CLK(CCD_PIXCLK),
342 // FIFO Read Side 1
343 .RD1_DATA(Read_DATA1),
344 .RD1(Read),
345 .RD1_ADDR(640*16),
346 .RD1_MAX_ADDR(640*496),
347 .RD1_LENGTH(9'h100),
348 .RD1_LOAD(!DLY_RST_0),
349 .RD1_CLK(VGA_CTRL_CLK),
350 // FIFO Read Side 2
351 .RD2_DATA(Read_DATA2),
352 .RD2(Read),
353 .RD2_ADDR(22'h100000+640*16),
354 .RD2_MAX_ADDR(22'h100000+640*496),
355 .RD2_LENGTH(9'h100),
356 .RD2_LOAD(!DLY_RST_0),
357 .RD2_CLK(VGA_CTRL_CLK),
358 // SDRAM Side
359 .SA(DRAM_ADDR),
360 .BA({DRAM_BA_1,DRAM_BA_0}),
361 .CS_N(DRAM_CS_N),
362 .CKE(DRAM_CKE),
363 .RAS_N(DRAM_RAS_N),
364 .CAS_N(DRAM_CAS_N),
365 .WE_N(DRAM_WE_N),
366 .DQ(DRAM_DQ),
367 .DQM({DRAM_UDQM,DRAM_LDQM}),
368 .SDR_CLK(DRAM_CLK)
369 );
370
371 I2C_CCD_Config ccd_config0 (
372 // Host Side
373 .iCLK(CLOCK_50),
374 .iRST_N(KEY[1]),
375 .iExposure(SW[15:0]),
376 // I2C Side
377 .I2C_SCLK(GPIO_1[14]),
378 .I2C_SDAT(GPIO_1[15])
379 );
380
381 Mirror_Col mirror0 (
382 // Input Side
383 .iCCD_R(mCCD_R),
384 .iCCD_G(mCCD_G),
385 .iCCD_B(mCCD_B),
386 .iCCD_DVAL(mCCD_DVAL_d),
387 .iCCD_PIXCLK(CCD_PIXCLK),
388 .iRST_N(DLY_RST_1),
389 // Output Side
390 .oCCD_R(sCCD_R),
391 .oCCD_G(sCCD_G),
392 .oCCD_B(sCCD_B),
393 .oCCD_DVAL(sCCD_DVAL)
394 );
395
396 Sobel sobel0 (
397 .iCLK(VGA_CTRL_CLK),
398 .iRST_N(DLY_RST_2),
399 .iDATA(mVGA_G),
400 .iDVAL(Read),
401 .iTHRESHOLD(8'h18),
402 .oDATA(Filter_Out)
403 );
404
405 endmodule
396行
.iCLK(VGA_CTRL_CLK),
.iRST_N(DLY_RST_2),
.iDATA(mVGA_G),
.iDVAL(Read),
.iTHRESHOLD(8'h18),
.oDATA(Filter_Out)
);
改用VGA Controller所跑的VGA_CTRL_CLK。在DE2-70,因為曝光值是由KEY[1]所控制,所以可以用SW[9:2]來設定Sobel的threshold;但在DE2_CCD,預設SW[15:0]已經被用來設定曝光值,所以在此threshold就先給定值8'h18,你可以依你的環境需求更改此值。
231行
assign DISP_R = SW[17] ? mVGA_G : // Gray
SW[16] ? Filter_Out : // Filter Out
mVGA_R ; // Color
assign DISP_G = SW[17] ? mVGA_G : // Gray
SW[16] ? Filter_Out : // Filter Out
mVGA_G; // Color
assign DISP_B = SW[17] ? mVGA_G : // Gray
SW[16] ? Filter_Out : // Filter Out
mVGA_B; // Color
原本在DE2-70用的是SW[15]與SW[14],因為這兩個SW被設定曝光值所占用,所以改用SW[17]與SW[16]。
255行
// Host Side
.oRequest(Read),
.iRed(DISP_R),
.iGreen(DISP_G),
.iBlue(DISP_B),
// VGA Side
.oVGA_R(VGA_R),
.oVGA_G(VGA_G),
.oVGA_B(VGA_B),
.oVGA_H_SYNC(VGA_HS),
.oVGA_V_SYNC(VGA_VS),
.oVGA_SYNC(VGA_SYNC),
.oVGA_BLANK(VGA_BLANK),
// Control Signal
.iCLK(VGA_CTRL_CLK),
.iRST_N(DLY_RST_2)
);
從DE2-70的touch_tcon改成VGA_Controller,直接輸入RGB即可。
操作方式
KEY[0]:reset
KEY[1]:接受曝光值設定
KEY[2]:capture
KEY[3]:free run
SW[15:0]:設定曝光值
SW[17]:on:灰階模式,off:彩色模式
SW[17] off + SW[16] on:Sobel edge模式
建議最佳Sobel edge模式:SW[16]、SW[12]、SW[11]為on,其他SW為off。
執行結果
依次為:彩色模式、灰階模式、Sobel edge模式
完整程式碼下載
DE2_CCD_sobel.7z (DE2 + TRDB-DC2 + VGA)
DE2_LCM_CCD_sobel.7z (DE2 + TRDB-DC2 + TRDB-LCM)
Conclusion
此範例目前無法動態修改Sobel edge的threshold值是個遺憾,要改成如DE2-70那樣可以動態設定並不難,大家可以自行修改。
See Also
(原創) 如何實現Real Time的Sobel Edge Detector? (SOC) (Verilog) (Image Processing) (DE2-70) (TRDB-D5M)
(原創) 如何實現Sobel Edge Detector? (Image Processing) (C/C++) (C++/CLI) (C)
(原創) 如何Real Time產生灰階影像? (SOC) (DE2) (TRDB-DC2)
(原創) 如何Real Time產生灰階影像? (SOC) (DE2-70) (TRDB-D5M)
(原創) 如何設計乘加電路? (SOC) (Verilog) (MegaCore)
(原創) 如何將DE2_70_TV範例加上Sobel Edge Detector? (SOC) (Verilog) (Image Processing) (DE2-70)