original link:http://www.cnblogs.com/oomusou/archive/2008/08/25/verilog_sobel_edge_detector.html
Abstract
本文使用Verilog在DE2-70實現Sobel Edge Detector,並深入探討Line Buffer在Video Processing上的應用。
Introduction
使用環境:Quartus II 8.0 + DE2-70 (Cyclone II EP2C70F896C6N) + TRDB-D5M + TRDB-LTM
Sobel Edge Detector是常用的Edge Detection演算法,在(原創) 如何實現Sobel Edge Detector? (Image Processing) (C/C++) (C++/CLI) (C)中,我曾經使用C與C++/CLI以軟體的方式實現, 在本文,我會用Verilog以硬體的方式在FPGA上實現。
用Verilog做影像處理所遇到的難題
用C做影像處理,大抵都是先將每個pixel的RGB放在二維的array中,由於C本身語言的特性,或許你會改用一維array,但觀念上其實仍是二維array。不過不管怎樣,總是有個記憶體位址能實際掌握每個pixel的RGB資訊。
但用Verilog做影像處理,由於是real time,SDRAM只是frame buffer,可以看成是一個FIFO,影像不斷地從CMOS進來,經過SDRAM之後,不斷地從VGA出去,我們並無法使用記憶體位址的概念去存取每個pixel的RGB資訊,也無法建立一個二維array來存取,這是用Verilog做影像處理所面臨最大的挑戰。
Sobel Edge Detector
詳細的Sobel演算法流程,我就不再多談,請參考Sobel Edge Detector。下圖的Gx與Gy是Sobel edge detector在X方向與Y方向的kernel,將與P5這個pixel做convolution。
雖然是對P5運算,卻必須同時知道P1、P2、P3、P4、P6、P7、P8、P9的資訊,這在C不是問題,因為都在array內,只要改變一下array的index就可得到,但在Verilog卻做不到。
系統架構圖
使用Verilog實現Sobel Edge Detector
Sobel.v / Verilog
1
/*
2
(C) OOMusou 2008
http://oomusou.cnblogs.com
3
4
Filename : Sobel.v
5
Compiler : Quartus II 8.0
6
Description : Demo how to implement Sobel Edge Detector on DE2-70
7
Release : 09/27/2008 1.0
8
*/
9
10
module
Sobel (
11
input
iCLK,
12
input
iRST_N,
13
input
[
7
:
0
] iTHRESHOLD,
14
input
iDVAL,
15
input
[
9
:
0
] iDATA,
16
output
reg
oDVAL,
17
output
reg
[
9
:
0
] oDATA
18
);
19
20
//
mask x
21
parameter
X1
=
8
'
hff, X2 = 8
'
h00, X3
=
8
'
h01;
22
parameter
X4
=
8
'
hfe, X5 = 8
'
h00, X6
=
8
'
h02;
23
parameter
X7
=
8
'
hff, X8 = 8
'
h00, X9
=
8
'
h01;
24
25
//
mask y
26
parameter
Y1
=
8
'
h01, Y2 = 8
'
h02, Y3
=
8
'
h01;
27
parameter
Y4
=
8
'
h00, Y5 = 8
'
h00, Y6
=
8
'
h00;
28
parameter
Y7
=
8
'
hff, Y8 = 8
'
hfe, Y9
=
8
'
hff;
29
30
wire
[
7
:
0
] Line0;
31
wire
[
7
:
0
] Line1;
32
wire
[
7
:
0
] Line2;
33
34
wire
[
17
:
0
] Mac_x0;
35
wire
[
17
:
0
] Mac_x1;
36
wire
[
17
:
0
] Mac_x2;
37
38
wire
[
17
:
0
] Mac_y0;
39
wire
[
17
:
0
] Mac_y1;
40
wire
[
17
:
0
] Mac_y2;
41
42
wire
[
19
:
0
] Pa_x;
43
wire
[
19
:
0
] Pa_y;
44
45
wire
[
15
:
0
] Abs_mag;
46
47
LineBuffer_3 b0 (
48
.clken(iDVAL),
49
.clock(iCLK),
50
.shiftin(iDATA[
9
:
2
]),
51
.taps0x(Line0),
52
.taps1x(Line1),
53
.taps2x(Line2)
54
);
55
56
//
X
57
MAC_3 x0 (
58
.aclr0(
!
iRST_N),
59
.clock0(iCLK),
60
.dataa_0(Line0),
61
.datab_0(X9),
62
.datab_1(X8),
63
.datab_2(X7),
64
.result(Mac_x0)
65
);
66
67
MAC_3 x1 (
68
.aclr0(
!
iRST_N),
69
.clock0(iCLK),
70
.dataa_0(Line1),
71
.datab_0(X6),
72
.datab_1(X5),
73
.datab_2(X4),
74
.result(Mac_x1)
75
);
76
77
MAC_3 x2 (
78
.aclr0(
!
iRST_N),
79
.clock0(iCLK),
80
.dataa_0(Line2),
81
.datab_0(X3),
82
.datab_1(X2),
83
.datab_2(X1),
84
.result(Mac_x2)
85
);
86
87
//
Y
88
MAC_3 y0 (
89
.aclr0(
!
iRST_N),
90
.clock0(iCLK),
91
.dataa_0(Line0),
92
.datab_0(Y9),
93
.datab_1(Y8),
94
.datab_2(Y7),
95
.result(Mac_y0)
96
);
97
98
MAC_3 y1 (
99
.aclr0(
!
iRST_N),
100
.clock0(iCLK),
101
.dataa_0(Line1),
102
.datab_0(Y6),
103
.datab_1(Y5),
104
.datab_2(Y4),
105
.result(Mac_y1)
106
);
107
108
MAC_3 y2 (
109
.aclr0(
!
iRST_N),
110
.clock0(iCLK),
111
.dataa_0(Line2),
112
.datab_0(Y3),
113
.datab_1(Y2),
114
.datab_2(Y1),
115
.result(Mac_y2)
116
);
117
118
PA_3 pa0 (
119
.clock(iCLK),
120
.data0x(Mac_x0),
121
.data1x(Mac_x1),
122
.data2x(Mac_x2),
123
.result(Pa_x)
124
);
125
126
PA_3 pa1 (
127
.clock(iCLK),
128
.data0x(Mac_y0),
129
.data1x(Mac_y1),
130
.data2x(Mac_y2),
131
.result(Pa_y)
132
);
133
134
SQRT sqrt0 (
135
.clk(iCLK),
136
.radical(Pa_x
*
Pa_x
+
Pa_y
*
Pa_y),
137
.q(Abs_mag)
138
);
139
140
always
@(
posedge
iCLK,
negedge
iRST_N)
begin
141
if
(
!
iRST_N)
142
oDVAL
<=
0
;
143
else
begin
144
oDVAL
<=
iDVAL;
145
146
if
(iDVAL)
147
oDATA
<=
(Abs_mag
>
iTHRESHOLD)
?
0
:
1023
;
148
else
149
oDATA
<=
0
;
150
end
151
end
152
153
endmodule
19行
//
mask x
parameter
X1
=
8
'
hff, X2 = 8
'
h00, X3
=
8
'
h01;
parameter
X4
=
8
'
hfe, X5 = 8
'
h00, X6
=
8
'
h02;
parameter
X7
=
8
'
hff, X8 = 8
'
h00, X9
=
8
'
h01;
//
mask y
parameter
Y1
=
8
'
h01, Y2 = 8
'
h02, Y3
=
8
'
h01;
parameter
Y4
=
8
'
h00, Y5 = 8
'
h00, Y6
=
8
'
h00;
parameter
Y7
=
8
'
hff, Y8 = 8
'
hfe, Y9
=
8
'
hff;
定義Sobel的Gx與Gy兩個kernel,X1因為是-1,所以用的是2's complement。
48行
LineBuffer_3 b0 (
.clken(iDVAL),
.clock(iCLK),
.shiftin(iDATA[
9
:
2
]),
.taps0x(Line0),
.taps1x(Line1),
.taps2x(Line2)
);
本文最關鍵的地方就在這個Line Buffer,也是最難理解的地方,為了講解方便,先假設一個frame只有9個pixel,欲搭配Gx做運算,如下圖所示:
根據Sobel edge detector演算法:
P5對Gx的Magnitude
=
X1 * P1 + X2 * P2 + X3 * P3 + X4 * P4 + X5 * P5 + X6 * P6 + X7 * P7 + X8 * P8 + X9 * P9
X1 ~ X9沒問題,都已經在parameter上了,但 P1 ~ P9的取得就是大問題, 他是P1、P2、P3....P9依序的傳入,沒有C的位址概念,也沒有2維array概念,為此我特別設計了3條line buffer做以上的運算。
3條line buffer使用Megafunction的altshift_tab達成,與Gx乘加的部分由Megafunction的altmult_add與parallel_add完成。
為了加強了解,我特別設計了只有3條line buffer,每條line buffer只有3個pixel的小程式來仿真:
我們可以發現,在最後一個pixel:9輸入後,下一個clock得到的是pixel 1、4、7,在下一個clock是2、5、8、最後一個clock是9、6、3,也就是Line0依次得到9、8、7,Line1得到6、5、 4,Line3得到3、2、1,所以Line0必須與X9、X8、X7做乘加,其餘同理,所以在58行
//
X
MAC_3 x0 (
.aclr0(
!
iRST_N),
.clock0(iCLK),
.dataa_0(Line0),
.datab_0(X9),
.datab_1(X8),
.datab_2(X7),
.result(Mac_x0)
);
Mac_3是Megafunction的altmult_add,其餘的x1、x2與y0、y1、y2同理。
119行
PA_3 pa0 (
.clock(iCLK),
.data0x(Mac_x0),
.data1x(Mac_x1),
.data2x(Mac_x2),
.result(Pa_x)
);
使用Megafunction的parallel_add做加總,pa1同理。
135行
SQRT sqrt0 (
.clk(iCLK),
.radical(Pa_x
*
Pa_x
+
Pa_y
*
Pa_y),
.q(Abs_mag)
);
根據Sobel演算法,要平方相加再開根號,其實只是為了取正值而已,也可以簡單的用 |Pa_x| + |Pa_y|計算。
46行
assign
oDATA
=
(Abs_mag
>
iTHRESHOLD)
?
0
:
1023
;
判斷threshold值。
在DE2-70實現Sobel Edge Detector
我是以DE2-70 CD中的DE2_70_D5M_LTM為藍本修改而成,這是一個以DE2-70 + 500萬像素CMOS:TRDB-D5M + 4.3寸 800x400 LTM為平台的範例。
DE2_70.v / Verilog
1
/*
2
(C) OOMusou 2008
http://oomusou.cnblogs.com
3
4
Filename : DE2_70.v
5
Compiler : Quartus II 8.0
6
Description : Demo how to implement Sobel Edge Detector on DE2-70
7
Release : 08/25/2008 1.0
8
*/
9
10
module
DE2_70 (
11
////////////////////////
Clock Input
////////////////////////
12
input
iCLK_28,
//
28.63636 MHz
13
input
iCLK_50,
//
50 MHz
14
input
iCLK_50_2,
//
50 MHz
15
input
iCLK_50_3,
//
50 MHz
16
input
iCLK_50_4,
//
50 MHz
17
input
iEXT_CLOCK,
//
External Clock
18
////////////////////////
Push Button
////////////////////////
19
input
[
3
:
0
] iKEY,
//
Pushbutton[3:0]
20
////////////////////////
DPDT Switch
////////////////////////
21
input
[
17
:
0
] iSW,
//
Toggle Switch[17:0]
22
////////////////////////
7-SEG Dispaly
////////////////////////
23
output
[
6
:
0
] oHEX0_D,
//
Seven Segment Digit 0
24
output
oHEX0_DP,
//
Seven Segment Digit 0 decimal point
25
output
[
6
:
0
] oHEX1_D,
//
Seven Segment Digit 1
26
output
oHEX1_DP,
//
Seven Segment Digit 1 decimal point
27
output
[
6
:
0
] oHEX2_D,
//
Seven Segment Digit 2
28
output
oHEX2_DP,
//
Seven Segment Digit 2 decimal point
29
output
[
6
:
0
] oHEX3_D,
//
Seven Segment Digit 3
30
output
oHEX3_DP,
//
Seven Segment Digit 3 decimal point
31
output
[
6
:
0
] oHEX4_D,
//
Seven Segment Digit 4
32
output
oHEX4_DP,
//
Seven Segment Digit 4 decimal point
33
output
[
6
:
0
] oHEX5_D,
//
Seven Segment Digit 5
34
output
oHEX5_DP,
//
Seven Segment Digit 5 decimal point
35
output
[
6
:
0
] oHEX6_D,
//
Seven Segment Digit 6
36
output
oHEX6_DP,
//
Seven Segment Digit 6 decimal point
37
output
[
6
:
0
] oHEX7_D,
//
Seven Segment Digit 7
38
output
oHEX7_DP,
//
Seven Segment Digit 7 decimal point
39
///////////////////////////
/ LED
///////////////////////////
/
40
output
[
8
:
0
] oLEDG,
//
LED Green[8:0]
41
output
[
17
:
0
] oLEDR,
//
LED Red[17:0]
42
///////////////////////////
/ UART
///////////////////////////
/
43
output
oUART_TXD,
//
UART Transmitter
44
input
iUART_RXD,
//
UART Receiver
45
output
oUART_CTS,
//
UART Clear To Send
46
input
iUART_RTS,
//
UART Requst To Send
47
///////////////////////////
/ IRDA
///////////////////////////
/
48
output
oIRDA_TXD,
//
IRDA Transmitter
49
input
iIRDA_RXD,
//
IRDA Receiver
50
/////////////////////
// SDRAM Interface
////////////////////////
51
inout
[
31
:
0
] DRAM_DQ,
//
SDRAM Data bus 32 Bits
52
output
[
12
:
0
] oDRAM0_A,
//
SDRAM0 Address bus 13 Bits
53
output
[
12
:
0
] oDRAM1_A,
//
SDRAM1 Address bus 13 Bits
54
output
oDRAM0_LDQM0,
//
SDRAM0 Low-byte Data Mask
55
output
oDRAM1_LDQM0,
//
SDRAM1 Low-byte Data Mask
56
output
oDRAM0_UDQM1,
//
SDRAM0 High-byte Data Mask
57
output
oDRAM1_UDQM1,
//
SDRAM1 High-byte Data Mask
58
output
oDRAM0_WE_N,
//
SDRAM0 Write Enable
59
output
oDRAM1_WE_N,
//
SDRAM1 Write Enable
60
output
oDRAM0_CAS_N,
//
SDRAM0 Column Address Strobe
61
output
oDRAM1_CAS_N,
//
SDRAM1 Column Address Strobe
62
output
oDRAM0_RAS_N,
//
SDRAM0 Row Address Strobe
63
output
oDRAM1_RAS_N,
//
SDRAM1 Row Address Strobe
64
output
oDRAM0_CS_N,
//
SDRAM0 Chip Select
65
output
oDRAM1_CS_N,
//
SDRAM1 Chip Select
66
output
[
1
:
0
] oDRAM0_BA,
//
SDRAM0 Bank Address
67
output
[
1
:
0
] oDRAM1_BA,
//
SDRAM1 Bank Address
68
output
oDRAM0_CLK,
//
SDRAM0 Clock
69
output
oDRAM1_CLK,
//
SDRAM1 Clock
70
output
oDRAM0_CKE,
//
SDRAM0 Clock Enable
71
output
oDRAM1_CKE,
//
SDRAM1 Clock Enable
72
////////////////////////
Flash Interface
////////////////////////
73
inout
[
14
:
0
] FLASH_DQ,
//
FLASH Data bus 15 Bits (0 to 14)
74
inout
FLASH_DQ15_AM1,
//
FLASH Data bus Bit 15 or Address A-1
75
output
[
21
:
0
] oFLASH_A,
//
FLASH Address bus 26 Bits
76
output
oFLASH_WE_N,
//
FLASH Write Enable
77
output
oFLASH_RST_N,
//
FLASH Reset
78
output
oFLASH_WP_N,
//
FLASH Write Protect /Programming Acceleration
79
input
iFLASH_RY_N,
//
FLASH Ready/Busy output
80
output
oFLASH_BYTE_N,
//
FLASH Byte/Word Mode Configuration
81
output
oFLASH_OE_N,
//
FLASH Output Enable
82
output
oFLASH_CE_N,
//
FLASH Chip Enable
83
////////////////////////
SRAM Interface
////////////////////////
84
inout
[
31
:
0
] SRAM_DQ,
//
SRAM Data Bus 32 Bits
85
inout
[
3
:
0
] SRAM_DPA,
//
SRAM Parity Data Bus
86
output
[
18
:
0
] oSRAM_A,
//
SRAM Address bus 21 Bits
87
output
oSRAM_ADSC_N,
//
SRAM Controller Address Status
88
output
oSRAM_ADSP_N,
//
SRAM Processor Address Status
89
output
oSRAM_ADV_N,
//
SRAM Burst Address Advance
90
output
[
3
:
0
] oSRAM_BE_N,
//
SRAM Byte Write Enable
91
output
oSRAM_CE1_N,
//
SRAM Chip Enable
92
output
oSRAM_CE2,
//
SRAM Chip Enable
93
output
oSRAM_CE3_N,
//
SRAM Chip Enable
94
output
oSRAM_CLK,
//
SRAM Clock
95
output
oSRAM_GW_N,
//
SRAM Global Write Enable
96
output
oSRAM_OE_N,
//
SRAM Output Enable
97
output
oSRAM_WE_N,
//
SRAM Write Enable
98
//////////////////
// ISP1362 Interface
////////////////////////
99
inout
[
15
:
0
] OTG_D,
//
ISP1362 Data bus 16 Bits
100
output
[
1
:
0
] oOTG_A,
//
ISP1362 Address 2 Bits
101
output
oOTG_CS_N,
//
ISP1362 Chip Select
102
output
oOTG_OE_N,
//
ISP1362 Read
103
output
oOTG_WE_N,
//
ISP1362 Write
104
output
oOTG_RESET_N,
//
ISP1362 Reset
105
inout
OTG_FSPEED,
//
USB Full Speed, 0 = Enable, Z = Disable
106
inout
OTG_LSPEED,
//
USB Low Speed, 0 = Enable, Z = Disable
107
input
iOTG_INT0,
//
ISP1362 Interrupt 0
108
input
iOTG_INT1,
//
ISP1362 Interrupt 1
109
input
iOTG_DREQ0,
//
ISP1362 DMA Request 0
110
input
iOTG_DREQ1,
//
ISP1362 DMA Request 1
111
output
oOTG_DACK0_N,
//
ISP1362 DMA Acknowledge 0
112
output
oOTG_DACK1_N,
//
ISP1362 DMA Acknowledge 1
113
//////////////////
// LCD Module 16X2
///////////////////////////
/
114
inout
[
7
:
0
] LCD_D,
//
LCD Data bus 8 bits
115
output
oLCD_ON,
//
LCD Power ON/OFF
116
output
oLCD_BLON,
//
LCD Back Light ON/OFF
117
output
oLCD_RW,
//
LCD Read/Write Select, 0 = Write, 1 = Read
118
output
oLCD_EN,
//
LCD Enable
119
output
oLCD_RS,
//
LCD Command/Data Select, 0 = Command, 1 = Data
120
//////////////////
// SD Card Interface
////////////////////////
121
inout
SD_DAT,
//
SD Card Data
122
inout
SD_DAT3,
//
SD Card Data 3
123
inout
SD_CMD,
//
SD Card Command Signal
124
output
oSD_CLK,
//
SD Card Clock
125
////////////////////////
I2C
//////////////////////////////
//
126
inout
I2C_SDAT,
//
I2C Data
127
output
oI2C_SCLK,
//
I2C Clock
128
////////////////////////
PS2
//////////////////////////////
//
129
inout
PS2_KBDAT,
//
PS2 Keyboard Data
130
inout
PS2_KBCLK,
//
PS2 Keyboard Clock
131
inout
PS2_MSDAT,
//
PS2 Mouse Data
132
inout
PS2_MSCLK,
//
PS2 Mouse Clock
133
////////////////////////
VGA
///////////////////////////
/
134
output
oVGA_CLOCK,
//
VGA Clock
135
output
oVGA_HS,
//
VGA H_SYNC
136
output
oVGA_VS,
//
VGA V_SYNC
137
output
oVGA_BLANK_N,
//
VGA BLANK
138
output
oVGA_SYNC_N,
//
VGA SYNC
139
output
[
9
:
0
] oVGA_R,
//
VGA Red[9:0]
140
output
[
9
:
0
] oVGA_G,
//
VGA Green[9:0]
141
output
[
9
:
0
] oVGA_B,
//
VGA Blue[9:0]
142
///////////////
/ Ethernet Interface
///////////////////////////
/
143
inout
[
15
:
0
] ENET_D,
//
DM9000A DATA bus 16Bits
144
output
oENET_CMD,
//
DM9000A Command/Data Select, 0 = Command, 1 = Data
145
output
oENET_CS_N,
//
DM9000A Chip Select
146
output
oENET_IOW_N,
//
DM9000A Write
147
output
oENET_IOR_N,
//
DM9000A Read
148
output
oENET_RESET_N,
//
DM9000A Reset
149
input
iENET_INT,
//
DM9000A Interrupt
150
output
oENET_CLK,
//
DM9000A Clock 25 MHz
151
//////////////////
// Audio CODEC
///////////////////////////
/
152
inout
AUD_ADCLRCK,
//
Audio CODEC ADC LR Clock
153
input
iAUD_ADCDAT,
//
Audio CODEC ADC Data
154
inout
AUD_DACLRCK,
//
Audio CODEC DAC LR Clock
155
output
oAUD_DACDAT,
//
Audio CODEC DAC Data
156
inout
AUD_BCLK,
//
Audio CODEC Bit-Stream Clock
157
output
oAUD_XCK,
//
Audio CODEC Chip Clock
158
//////////////////
// TV Devoder
///////////////////////////
/
159
input
iTD1_CLK27,
//
TV Decoder1 Line_Lock Output Clock
160
input
[
7
:
0
] iTD1_D,
//
TV Decoder1 Data bus 8 bits
161
input
iTD1_HS,
//
TV Decoder1 H_SYNC
162
input
iTD1_VS,
//
TV Decoder1 V_SYNC
163
output
oTD1_RESET_N,
//
TV Decoder1 Reset
164
input
iTD2_CLK27,
//
TV Decoder2 Line_Lock Output Clock
165
input
[
7
:
0
] iTD2_D,
//
TV Decoder2 Data bus 8 bits
166
input
iTD2_HS,
//
TV Decoder2 H_SYNC
167
input
iTD2_VS,
//
TV Decoder2 V_SYNC
168
output
oTD2_RESET_N,
//
TV Decoder2 Reset
169
////////////////////////
GPIO
//////////////////////////////
//
170
inout
[
31
:
0
] GPIO_0,
//
GPIO Connection 0 I/O
171
input
GPIO_CLKIN_N0,
//
GPIO Connection 0 Clock Input 0
172
input
GPIO_CLKIN_P0,
//
GPIO Connection 0 Clock Input 1
173
inout
GPIO_CLKOUT_N0,
//
GPIO Connection 0 Clock Output 0
174
inout
GPIO_CLKOUT_P0,
//
GPIO Connection 0 Clock Output 1
175
inout
[
31
:
0
] GPIO_1,
//
GPIO Connection 1 I/O
176
input
GPIO_CLKIN_N1,
//
GPIO Connection 1 Clock Input 0
177
input
GPIO_CLKIN_P1,
//
GPIO Connection 1 Clock Input 1
178
inout
GPIO_CLKOUT_N1,
//
GPIO Connection 1 Clock Output 0
179
inout
GPIO_CLKOUT_P1
//
GPIO Connection 1 Clock Output 1
180
);
181
182
wire
[
11
:
0
] CCD_DATA;
183
wire
CCD_SDAT;
184
wire
CCD_SCLK;
185
wire
CCD_FLASH;
186
wire
CCD_FVAL;
187
wire
CCD_LVAL;
188
wire
CCD_PIXCLK;
189
wire
CCD_MCLK;
//
CCD Master Clock
190
191
wire
[
15
:
0
] Read_DATA1;
192
wire
[
15
:
0
] Read_DATA2;
193
wire
VGA_CTRL_CLK;
194
wire
[
11
:
0
] mCCD_DATA;
195
wire
mCCD_DVAL;
196
wire
mCCD_DVAL_d;
197
wire
[
15
:
0
] X_Cont;
198
wire
[
15
:
0
] Y_Cont;
199
wire
[
9
:
0
] X_ADDR;
200
wire
[
31
:
0
] Frame_Cont;
201
wire
DLY_RST_0;
202
wire
DLY_RST_1;
203
wire
DLY_RST_2;
204
wire
Read;
205
reg
[
11
:
0
] rCCD_DATA;
206
reg
rCCD_LVAL;
207
reg
rCCD_FVAL;
208
wire
[
11
:
0
] sCCD_R;
209
wire
[
11
:
0
] sCCD_G;
210
wire
[
11
:
0
] sCCD_B;
211
wire
sCCD_DVAL;
212
reg
[
1
:
0
] rClk;
213
wire
sdram_ctrl_clk;
214
215
216
//
Touch panel signal
217
wire
[
7
:
0
] ltm_r;
//
LTM Red Data 8 Bits
218
wire
[
7
:
0
] ltm_g;
//
LTM Green Data 8 Bits
219
wire
[
7
:
0
] ltm_b;
//
LTM Blue Data 8 Bits
220
wire
ltm_nclk;
//
LTM Clcok
221
wire
ltm_hd;
222
wire
ltm_vd;
223
wire
ltm_den;
224
wire
adc_dclk;
225
wire
adc_cs;
226
wire
adc_penirq_n;
227
wire
adc_busy;
228
wire
adc_din;
229
wire
adc_dout;
230
wire
adc_ltm_sclk;
231
wire
ltm_grst;
232
//
LTM Config
233
wire
ltm_sclk;
234
wire
ltm_sda;
235
wire
ltm_scen;
236
wire
ltm_3wirebusy_n;
237
238
assign
CCD_DATA[
0
]
=
GPIO_1[
11
];
239
assign
CCD_DATA[
1
]
=
GPIO_1[
10
];
240
assign
CCD_DATA[
2
]
=
GPIO_1[
9
];
241
assign
CCD_DATA[
3
]
=
GPIO_1[
8
];
242
assign
CCD_DATA[
4
]
=
GPIO_1[
7
];
243
assign
CCD_DATA[
5
]
=
GPIO_1[
6
];
244
assign
CCD_DATA[
6
]
=
GPIO_1[
5
];
245
assign
CCD_DATA[
7
]
=
GPIO_1[
4
];
246
assign
CCD_DATA[
8
]
=
GPIO_1[
3
];
247
assign
CCD_DATA[
9
]
=
GPIO_1[
2
];
248
assign
CCD_DATA[
10
]
=
GPIO_1[
1
];
249
assign
CCD_DATA[
11
]
=
GPIO_1[
0
];
250
assign
GPIO_CLKOUT_N1
=
CCD_MCLK;
251
assign
CCD_FVAL
=
GPIO_1[
18
];
252
assign
CCD_LVAL
=
GPIO_1[
17
];
253
assign
CCD_PIXCLK
=
GPIO_CLKIN_N1;
254
assign
GPIO_1[
15
]
=
1
'
b1; // tRIGGER
255
assign
GPIO_1[
14
]
=
DLY_RST_1;
256
257
assign
oLEDR
=
iSW;
258
assign
oLEDG
=
Y_Cont;
259
260
assign
oTD1_RESET_N
=
1
'
b1;
261
assign
oVGA_CLOCK
=
VGA_CTRL_CLK;
262
263
assign
CCD_MCLK
=
rClk[
0
];
264
265
assign
oUART_TXD
=
iUART_RXD;
266
267
assign
adc_penirq_n
=
GPIO_CLKIN_N0;
268
assign
adc_dout
=
GPIO_0[
0
];
269
assign
adc_busy
=
GPIO_CLKIN_P0;
270
assign
GPIO_0[
1
]
=
adc_din;
271
assign
GPIO_0[
2
]
=
adc_ltm_sclk;
272
assign
GPIO_0[
3
]
=
ltm_b[
3
];
273
assign
GPIO_0[
4
]
=
ltm_b[
2
];
274
assign
GPIO_0[
5
]
=
ltm_b[
1
];
275
assign
GPIO_0[
6
]
=
ltm_b[
0
];
276
assign
GPIO_0[
7
]
=~
ltm_nclk;
277
assign
GPIO_0[
8
]
=
ltm_den;
278
assign
GPIO_0[
9
]
=
ltm_hd;
279
assign
GPIO_0[
10
]
=
ltm_vd;
280
assign
GPIO_0[
11
]
=
ltm_b[
4
];
281
assign
GPIO_0[
12
]
=
ltm_b[
5
];
282
assign
GPIO_0[
13
]
=
ltm_b[
6
];
283
assign
GPIO_CLKOUT_N0
=
ltm_b[
7
];
284
assign
GPIO_0[
14
]
=
ltm_g[
0
];
285
assign
GPIO_CLKOUT_P0
=
ltm_g[
1
];
286
assign
GPIO_0[
15
]
=
ltm_g[
2
];
287
assign
GPIO_0[
16
]
=
ltm_g[
3
];
288
assign
GPIO_0[
17
]
=
ltm_g[
4
];
289
assign
GPIO_0[
18
]
=
ltm_g[
5
];
290
assign
GPIO_0[
19
]
=
ltm_g[
6
];
291
assign
GPIO_0[
20
]
=
ltm_g[
7
];
292
assign
GPIO_0[
21
]
=
ltm_r[
0
];
293
assign
GPIO_0[
22
]
=
ltm_r[
1
];
294
assign
GPIO_0[
23
]
=
ltm_r[
2
];
295
assign
GPIO_0[
24
]
=
ltm_r[
3
];
296
assign
GPIO_0[
25
]
=
ltm_r[
4
];
297
assign
GPIO_0[
26
]
=
ltm_r[
5
];
298
assign
GPIO_0[
27
]
=
ltm_r[
6
];
299
assign
GPIO_0[
28
]
=
ltm_r[
7
];
300
assign
GPIO_0[
29
]
=
ltm_grst;
301
assign
GPIO_0[
30
]
=
ltm_scen;
302
assign
GPIO_0[
31
]
=
ltm_sda;
303
304
assign
ltm_grst
=
iKEY[
0
];
305
assign
adc_ltm_sclk
=
ltm_sclk ;
306
307
308
309
310
311
312
always
@(
posedge
iCLK_50)
313
rClk
<=
rClk
+
1
;
314
315
always
@(
posedge
CCD_PIXCLK)
begin
316
rCCD_DATA
<=
CCD_DATA;
317
rCCD_LVAL
<=
CCD_LVAL;
318
rCCD_FVAL
<=
CCD_FVAL;
319
end
320
321
Reset_Delay reset0 (
322
.iCLK(iCLK_50),
323
.iRST(iKEY[
0
]),
324
.oRST_0(DLY_RST_0),
325
.oRST_1(DLY_RST_1),
326
.oRST_2(DLY_RST_2)
327
);
328
329
CCD_Capture capture0 (
330
.oDATA(mCCD_DATA),
331
.oDVAL(mCCD_DVAL),
332
.oX_Cont(X_Cont),
333
.oY_Cont(Y_Cont),
334
.oFrame_Cont(Frame_Cont),
335
.iDATA(rCCD_DATA),
336
.iFVAL(rCCD_FVAL),
337
.iLVAL(rCCD_LVAL),
338
.iSTART(
!
iKEY[
3
]),
339
.iEND(
!
iKEY[
2
]),
340
.iCLK(CCD_PIXCLK),
341
.iRST(DLY_RST_2)
342
);
343
344
RAW2RGB raw0 (
345
.iCLK(CCD_PIXCLK),
346
.iRST_n(DLY_RST_1),
347
.iData(mCCD_DATA),
348
.iDval(mCCD_DVAL),
349
.oRed(sCCD_R),
350
.oGreen(sCCD_G),
351
.oBlue(sCCD_B),
352
.oDval(sCCD_DVAL),
353
.iMIRROR(iSW[
17
]),
354
.iX_Cont(X_Cont),
355
.iY_Cont(Y_Cont)
356
);
357
358
SEG7_LUT_8 seg0 (
359
.oSEG0(oHEX0_D),
360
.oSEG1(oHEX1_D),
361
.oSEG2(oHEX2_D),
362
.oSEG3(oHEX3_D),
363
.oSEG4(oHEX4_D),
364
.oSEG5(oHEX5_D),
365
.oSEG6(oHEX6_D),
366
.oSEG7(oHEX7_D),
367
.iDIG(Frame_Cont[
31
:
0
])
368
);
369
370
vga_pll vga_pll0 (
371
.inclk0(iCLK_50_2),
372
.c0(ltm_nclk)
373
);
374
375
sdram_pll sdram_pll0 (
376
.inclk0(iCLK_50_3),
377
.c0(sdram_ctrl_clk),
378
.c1(oDRAM0_CLK),
379
.c2(oDRAM1_CLK)
380
);
381
382
Sdram_Control_4Port sdram0 (
383
//
HOST Side
384
.REF_CLK(iCLK_50),
385
.RESET_N(
1
'
b1),
386
.CLK(sdram_ctrl_clk),
387
//
FIFO Write Side 1
388
.WR1_DATA({sCCD_G[
11
:
7
], sCCD_B[
11
:
2
]}),
389
.WR1(sCCD_DVAL),
390
.WR1_ADDR(
0
),
391
.WR1_MAX_ADDR(
800
*
480
),
392
.WR1_LENGTH(
9
'
h100),
393
.WR1_LOAD(
!
DLY_RST_0),
394
.WR1_CLK(CCD_PIXCLK),
395
//
FIFO Read Side 1
396
.RD1_DATA(Read_DATA1),
397
.RD1(wDAL_sobel),
398
.RD1_ADDR(
0
),
399
.RD1_MAX_ADDR(
800
*
480
),
400
.RD1_LENGTH(
9
'
h100),
401
.RD1_LOAD(
!
DLY_RST_0),
402
.RD1_CLK(
~
ltm_nclk),
403
//
SDRAM Side
404
.SA(oDRAM0_A[
11
:
0
]),
405
.BA(oDRAM0_BA),
406
.CS_N(oDRAM0_CS_N),
407
.CKE(oDRAM0_CKE),
408
.RAS_N(oDRAM0_RAS_N),
409
.CAS_N(oDRAM0_CAS_N),
410
.WE_N(oDRAM0_WE_N),
411
.DQ(DRAM_DQ[
15
:
0
]),
412
.DQM({oDRAM0_UDQM1,oDRAM0_LDQM0})
413
);
414
415
Sdram_Control_4Port sdram1 (
416
//
HOST Side
417
.REF_CLK(iCLK_50),
418
.RESET_N(
1
'
b1),
419
.CLK(sdram_ctrl_clk),
420
//
FIFO Write Side 1
421
.WR1_DATA({sCCD_G[
6
:
2
], sCCD_R[
11
:
2
]}),
422
.WR1(sCCD_DVAL),
423
.WR1_ADDR(
0
),
424
.WR1_MAX_ADDR(
800
*
480
),
425
.WR1_LENGTH(
9
'
h100),
426
.WR1_LOAD(
!
DLY_RST_0),
427
.WR1_CLK(CCD_PIXCLK),
428
//
FIFO Read Side 1
429
.RD1_DATA(Read_DATA2),
430
.RD1(wDAL_sobel),
431
.RD1_ADDR(
0
),
432
.RD1_MAX_ADDR(
800
*
480
),
433
.RD1_LENGTH(
9
'
h100),
434
.RD1_LOAD(
!
DLY_RST_0),
435
.RD1_CLK(
~
ltm_nclk),
436
//
SDRAM Side
437
.SA(oDRAM1_A[
11
:
0
]),
438
.BA(oDRAM1_BA),
439
.CS_N(oDRAM1_CS_N),
440
.CKE(oDRAM1_CKE),
441
.RAS_N(oDRAM1_RAS_N),
442
.CAS_N(oDRAM1_CAS_N),
443
.WE_N(oDRAM1_WE_N),
444
.DQ(DRAM_DQ[
31
:
16
]),
445
.DQM({oDRAM1_UDQM1,oDRAM1_LDQM0})
446
);
447
448
I2C_CCD_Config i2c_ccd_config0 (
449
//
Host Side
450
.iCLK(iCLK_50),
451
.iRST_N(DLY_RST_1),
452
.iEXPOSURE_ADJ(iKEY[
1
]),
453
.iEXPOSURE_DEC_p(iSW[
0
]),
454
.iMIRROR_SW(iSW[
17
]),
455
//
I2C Side
456
.I2C_SCLK(GPIO_1[
20
]),
457
.I2C_SDAT(GPIO_1[
19
])
458
);
459
460
touch_tcon vga0 (
461
.iCLK(ltm_nclk),
462
.iRST_n(DLY_RST_2),
463
//
sdram side
464
.iREAD_DATA1({wDISP_G[
9
:
5
], wDISP_B}),
465
.iREAD_DATA2({wDISP_G[
4
:
0
], wISP_R}),
466
.oREAD_SDRAM_EN(Read),
467
//
lcd side
468
.oLCD_R(ltm_r),
469
.oLCD_G(ltm_g),
470
.oLCD_B(ltm_b),
471
.oHD(ltm_hd),
472
.oVD(ltm_vd),
473
.oDEN(ltm_den)
474
);
475
476
lcd_3wire_config lcd_config0 (
477
//
Host Side
478
.iCLK(iCLK_50),
479
.iRST_n(DLY_RST_0),
480
//
3 wire Side
481
.o3WIRE_SCLK(ltm_sclk),
482
.io3WIRE_SDAT(ltm_sda),
483
.o3WIRE_SCEN(ltm_scen),
484
.o3WIRE_BUSY_n(ltm_3wirebusy_n)
485
);
486
487
//
sobel ----------------------------------------------------
488
//
RGB
489
wire
[
9
:
0
] wVGA_R
=
Read_DATA2[
9
:
0
];
490
wire
[
9
:
0
] wVGA_G
=
{Read_DATA1[
14
:
10
],Read_DATA2[
14
:
10
]};
491
wire
[
9
:
0
] wVGA_B
=
Read_DATA1[
9
:
0
];
492
493
//
sobel
494
wire
wDVAL_sobel;
495
wire
[
9
:
0
] wSobel;
496
497
Sobel sobel0 (
498
.iCLK(ltm_nclk),
499
.iRST_N(DLY_RST_2),
500
.iTHRESHOLD(iSW[
9
:
2
]),
501
.iDVAL(Read),
502
.iDATA(wVGA_G),
//
gray
503
.oDVAL(wDAL_sobel),
504
.oDATA(wSobel)
505
);
506
507
//
gray
508
wire
[
9
:
0
] wGray_R
=
wVGA_G;
509
wire
[
9
:
0
] wGray_G
=
wVGA_G;
510
wire
[
9
:
0
] wGray_B
=
wVGA_G;
511
512
//
to display
513
wire
[
9
:
0
] wDISP_R
=
iSW[
15
]
?
wGray_R :
//
Gray
514
iSW[
14
]
?
wSobel :
//
Sobel
515
wVGA_R;
//
Color
516
wire
[
9
:
0
] wDISP_G
=
iSW[
15
]
?
wGray_G :
//
Gray
517
iSW[
14
]
?
wSobel :
//
Sobel
518
wVGA_G;
//
Color
519
wire
[
9
:
0
] wDISP_B
=
iSW[
15
]
?
wGray_B :
//
Gray
520
iSW[
14
]
?
wSobel :
//
Sobel
521
wVGA_B;
//
Color
522
523
endmodule
497行
Sobel sobel0 (
.iCLK(ltm_nclk),
.iRST_N(DLY_RST_2),
.iTHRESHOLD(iSW[
9
:
2
]),
.iDVAL(Read),
.iDATA(wVGA_G),
//
gray
.oDVAL(wDAL_sobel),
.oDATA(wSobel)
);
引用剛剛所建立的Sobel.v module,為什麼iDATA()傳入的是mVGA_G呢?因為Sobel edge detector處理的是灰階影像,在(原創) 如何Real Time產生灰階影像? (SOC) (DE2) (TRDB-DC2)曾經談到使用G來代表灰階影像的理由。而SW[9:2]則可動態的調整threshold值。
512行
//
to display
wire
[
9
:
0
] wDISP_R
=
iSW[
15
]
?
wGray_R :
//
Gray
iSW[
14
]
?
wSobel :
//
Sobel
wVGA_R;
//
Color
wire
[
9
:
0
] wDISP_G
=
iSW[
15
]
?
wGray_G :
//
Gray
iSW[
14
]
?
wSobel :
//
Sobel
wVGA_G;
//
Color
wire
[
9
:
0
] wDISP_B
=
iSW[
15
]
?
wGray_B :
//
Gray
iSW[
14
]
?
wSobel :
//
Sobel
wVGA_B;
//
Color
加上了SW控制,可切換顯示彩色、灰階與經過Sobel取過edge的影像。
操作方式
KEY[0]:reset
KEY[1]:調整曝光值
KEY[2]:capture
KEY[3]:free run
SW[0]:on:減少曝光值模式,off : 增加曝光值模式
SW[2] ~ SW[9]:調整threshold
SW[15]:on:灰階模式,off:彩色模式
SW[15] off + SW[14] on:Sobel edge模式
SW[17]:on:啟動mirror,off:不啟動mirror
建議最佳Sobel edge模式:SW[5]、SW[6]、SW[14]、SW[17]為on,其他SW為off。
執行結果
依次為:彩色模式、灰階模式、Sobel edge模式
完整程式碼下載
/Files/zhangzhi/DE2_70_D5M_LTM_sobel.7z
Conclusion
本文的重點在於學會使用altshift_tab做line buffer,這招學會後,就可以運用在很多電腦視覺的演算法上。若要將這個方法運用在其他平台,如DE2的DE2_CCD範例上,別忘了要將line buffer的長度改為640,因為VGA是640 * 480,而不是本範例的800。