1 |
2 |
wd5gnr |
/*
|
2 |
|
|
This file is part of Blue8.
|
3 |
|
|
|
4 |
|
|
These modules are from Ed Doering
|
5 |
|
|
|
6 |
|
|
|
7 |
|
|
*/
|
8 |
|
|
|
9 |
|
|
`timescale 1ns / 1ps
|
10 |
|
|
module DisplayHex (
|
11 |
|
|
// Digit display interface for Digilent DIO1, DIO4 and Spartan-3 boards
|
12 |
|
|
//
|
13 |
|
|
// - Accepts two 8-bit values on input, and displays the hexadecimal
|
14 |
|
|
// representation of each value on the four-digit seven-segment display
|
15 |
|
|
// - Uses multiplexed display scheme with 100 Hz refresh to minimize flicker.
|
16 |
|
|
// - Requires 50MHz master clock
|
17 |
|
|
// - Requires active-high master reset (all segments active on reset)
|
18 |
|
|
//
|
19 |
|
|
// Instantiation template:
|
20 |
|
|
/*
|
21 |
|
|
DigitDisplay instancename (
|
22 |
|
|
// System connections
|
23 |
|
|
.gClock( ),
|
24 |
|
|
.gReset( ), // Active high
|
25 |
|
|
|
26 |
|
|
// Data inputs
|
27 |
|
|
.iRight( ), // 8-bit value
|
28 |
|
|
.iLeft( ), // 8-bit value
|
29 |
|
|
|
30 |
|
|
// Direct connections to DIO1 or DIO4 board:
|
31 |
|
|
// Segment selectors
|
32 |
|
|
.oSegmentA( ),
|
33 |
|
|
.oSegmentB( ),
|
34 |
|
|
.oSegmentC( ),
|
35 |
|
|
.oSegmentD( ),
|
36 |
|
|
.oSegmentE( ),
|
37 |
|
|
.oSegmentF( ),
|
38 |
|
|
.oSegmentG( ),
|
39 |
|
|
.oSegmentDP( ),
|
40 |
|
|
|
41 |
|
|
// Digit selectors
|
42 |
|
|
.oDigitRight( ),
|
43 |
|
|
.oDigitMiddleRight( ),
|
44 |
|
|
.oDigitMiddleLeft( ),
|
45 |
|
|
.oDigitLeft( )
|
46 |
|
|
);
|
47 |
|
|
// Use 0 for DIO4 and Spartan-3 boards, 1 for DIO1 board (parameter defaults to 0
|
48 |
|
|
// when 'defparam' line is omitted).
|
49 |
|
|
*/
|
50 |
|
|
// End of instantiation template
|
51 |
|
|
//
|
52 |
|
|
// Author: Ed Doering
|
53 |
|
|
// Created: 21 Jan 2003
|
54 |
|
|
// Revised: 16 Mar 2004 (added parameter to choose digit select assertion level)
|
55 |
|
|
// 16 Aug 2005 (updated for Spartan-3; updated signal names)
|
56 |
|
|
|
57 |
|
|
// Global system resources:
|
58 |
|
|
input gClock, // System clock (50 MHz)
|
59 |
|
|
input gReset, // Master reset (active high)
|
60 |
|
|
|
61 |
|
|
// Inputs:
|
62 |
|
|
input [7:0] iRight, // Value to display on right two digits
|
63 |
|
|
input [7:0] iLeft, // Value to display on left two digits
|
64 |
|
|
input [3:0] indp, // input decimal points
|
65 |
|
|
|
66 |
|
|
// Outputs:
|
67 |
|
|
output reg oSegmentA, // LED segment a (active low)
|
68 |
|
|
output reg oSegmentB, // etc.
|
69 |
|
|
output reg oSegmentC,
|
70 |
|
|
output reg oSegmentD,
|
71 |
|
|
output reg oSegmentE,
|
72 |
|
|
output reg oSegmentF,
|
73 |
|
|
output reg oSegmentG,
|
74 |
|
|
output reg oSegmentDP, // LED decimal point
|
75 |
|
|
output reg oDigitRight, // Rightmost digit enable (active high)
|
76 |
|
|
output reg oDigitMiddleRight, // etc.
|
77 |
|
|
output reg oDigitMiddleLeft,
|
78 |
|
|
output reg oDigitLeft
|
79 |
|
|
);
|
80 |
|
|
|
81 |
|
|
// User-adjustable constants
|
82 |
|
|
parameter pClockFrequency = 50; // Clock frequency in MHz
|
83 |
|
|
parameter pRefreshFrequency = 100; // Display refresh rate (for entire display) in Hz
|
84 |
|
|
|
85 |
|
|
// Upper limit for frequency divider counter
|
86 |
|
|
parameter pUpperLimit = (pClockFrequency * 1000000) / (4 * pRefreshFrequency);
|
87 |
|
|
//parameter pUpperLimit = 2; // for simulation only
|
88 |
|
|
|
89 |
|
|
// Number of bits for frequency divider counter (will accommodate
|
90 |
|
|
// refresh frequencies down to 1 Hz)
|
91 |
|
|
parameter pDividerCounterBits = 24;
|
92 |
|
|
|
93 |
|
|
|
94 |
|
|
// Registered identifiers:
|
95 |
|
|
reg [pDividerCounterBits-1:0] rCycles;
|
96 |
|
|
reg [1:0] rDigitSelect;
|
97 |
|
|
reg [7:0] rNybble;
|
98 |
|
|
reg [3:0] rDigit;
|
99 |
|
|
reg wDecimalPoint;
|
100 |
|
|
reg [6:0] rCharacter;
|
101 |
|
|
|
102 |
|
|
// Frequency divider and 2-bit counter for digit selector
|
103 |
|
|
always @ (posedge gClock or posedge gReset)
|
104 |
|
|
if (gReset) begin
|
105 |
|
|
rCycles <= 0;
|
106 |
|
|
rDigitSelect <= 3;
|
107 |
|
|
end
|
108 |
|
|
else
|
109 |
|
|
if (rCycles == pUpperLimit) begin
|
110 |
|
|
rCycles <= 0;
|
111 |
|
|
rDigitSelect <= rDigitSelect - 1;
|
112 |
|
|
end
|
113 |
|
|
else
|
114 |
|
|
rCycles <= rCycles + 1;
|
115 |
|
|
|
116 |
|
|
// Decode the digit selector to four control lines
|
117 |
|
|
always @ (rDigitSelect)
|
118 |
|
|
case (rDigitSelect)
|
119 |
|
|
2'b00 : rDigit <= 4'b1110;
|
120 |
|
|
2'b01 : rDigit <= 4'b1101;
|
121 |
|
|
2'b10 : rDigit <= 4'b1011;
|
122 |
|
|
2'b11 : rDigit <= 4'b0111;
|
123 |
|
|
endcase
|
124 |
|
|
|
125 |
|
|
|
126 |
|
|
// MUX the four 4-bit inputs to a single 4-bit value
|
127 |
|
|
always @ (rDigitSelect or iRight or iLeft or indp)
|
128 |
|
|
case (rDigitSelect)
|
129 |
|
|
2'b00 : begin rNybble <= iRight[3:0]; wDecimalPoint <= indp[0]; end
|
130 |
|
|
2'b01 : begin rNybble <= iRight[7:4]; wDecimalPoint <= indp[1]; end
|
131 |
|
|
2'b10 : begin rNybble <= iLeft[3:0]; wDecimalPoint <= indp[2]; end
|
132 |
|
|
2'b11 : begin rNybble <= iLeft[7:4]; wDecimalPoint <= indp[3]; end
|
133 |
|
|
endcase
|
134 |
|
|
|
135 |
|
|
// Convert 4-bit value to character
|
136 |
|
|
always @ (rNybble)
|
137 |
|
|
case (rNybble) // abcdefg
|
138 |
|
|
4'h0 : rCharacter <= ~(7'b1111110);
|
139 |
|
|
4'h1 : rCharacter <= ~(7'b0110000);
|
140 |
|
|
4'h2 : rCharacter <= ~(7'b1101101);
|
141 |
|
|
4'h3 : rCharacter <= ~(7'b1111001);
|
142 |
|
|
4'h4 : rCharacter <= ~(7'b0110011);
|
143 |
|
|
4'h5 : rCharacter <= ~(7'b1011011);
|
144 |
|
|
4'h6 : rCharacter <= ~(7'b1011111);
|
145 |
|
|
4'h7 : rCharacter <= ~(7'b1110000);
|
146 |
|
|
4'h8 : rCharacter <= ~(7'b1111111);
|
147 |
|
|
4'h9 : rCharacter <= ~(7'b1111011);
|
148 |
|
|
4'ha : rCharacter <= ~(7'b1110111);
|
149 |
|
|
4'hb : rCharacter <= ~(7'b0011111);
|
150 |
|
|
4'hc : rCharacter <= ~(7'b1001110);
|
151 |
|
|
4'hd : rCharacter <= ~(7'b0111101);
|
152 |
|
|
4'he : rCharacter <= ~(7'b1001111);
|
153 |
|
|
4'hf : rCharacter <= ~(7'b1000111);
|
154 |
|
|
default : rCharacter <= ~(7'b1001001);
|
155 |
|
|
endcase
|
156 |
|
|
|
157 |
|
|
// Create registered outputs (for glitch-free output)
|
158 |
|
|
always @ (posedge gClock or posedge gReset)
|
159 |
|
|
if (gReset) begin
|
160 |
|
|
oSegmentA <= 0;
|
161 |
|
|
oSegmentB <= 0;
|
162 |
|
|
oSegmentC <= 0;
|
163 |
|
|
oSegmentD <= 0;
|
164 |
|
|
oSegmentE <= 0;
|
165 |
|
|
oSegmentF <= 0;
|
166 |
|
|
oSegmentG <= 0;
|
167 |
|
|
oSegmentDP <= 0;
|
168 |
|
|
oDigitRight <= 1'b1;
|
169 |
|
|
oDigitMiddleRight <= 1'b1;
|
170 |
|
|
oDigitMiddleLeft <= 1'b1;
|
171 |
|
|
oDigitLeft <= 1'b1;
|
172 |
|
|
end
|
173 |
|
|
else begin
|
174 |
|
|
oSegmentA <= rCharacter[6];
|
175 |
|
|
oSegmentB <= rCharacter[5];
|
176 |
|
|
oSegmentC <= rCharacter[4];
|
177 |
|
|
oSegmentD <= rCharacter[3];
|
178 |
|
|
oSegmentE <= rCharacter[2];
|
179 |
|
|
oSegmentF <= rCharacter[1];
|
180 |
|
|
oSegmentG <= rCharacter[0];
|
181 |
|
|
oSegmentDP <= wDecimalPoint;
|
182 |
|
|
oDigitRight <= rDigit[0];
|
183 |
|
|
oDigitMiddleRight <= rDigit[1];
|
184 |
|
|
oDigitMiddleLeft <= rDigit[2];
|
185 |
|
|
oDigitLeft <= rDigit[3];
|
186 |
|
|
end
|
187 |
|
|
|
188 |
|
|
endmodule
|
189 |
|
|
|
190 |
|
|
//-----------------------------------------------------------------------------
|
191 |
|
|
|
192 |
|
|
module Debouncer (
|
193 |
|
|
// Switch debouncer for Digilent FPGA boards
|
194 |
|
|
//
|
195 |
|
|
// Requires a 50MHz clock, and implements a 10ms wait period.
|
196 |
|
|
// Includes glitch suppression. Built-in synchronizer.
|
197 |
|
|
// Outputs include a debounced replica of the input signal, and
|
198 |
|
|
// single clock period pulse outputs to indicate rising edge and
|
199 |
|
|
// falling edge detected (of clean signal).
|
200 |
|
|
//
|
201 |
|
|
// 10ms at 50MHz is 500,000 master clock cycles, requiring 19 bits
|
202 |
|
|
// of register space.
|
203 |
|
|
|
204 |
|
|
// Global system resources:
|
205 |
|
|
input gClock, // System clock (must be 50 MHz)
|
206 |
|
|
input gReset, // Master reset (asynchronous, active high)
|
207 |
|
|
|
208 |
|
|
// Inputs:
|
209 |
|
|
input iBouncy, // Bouncy switch signal
|
210 |
|
|
|
211 |
|
|
// Outputs:
|
212 |
|
|
output reg oDebounced, // Debounced replica of switch signal
|
213 |
|
|
output reg oPulseOnRisingEdge, // Single pulse to indicate rising edge detected
|
214 |
|
|
output reg oPulseOnFallingEdge // Single pulse to indicate falling edge detected
|
215 |
|
|
);
|
216 |
|
|
|
217 |
|
|
// Constant parameters
|
218 |
|
|
parameter pInitialValue = 0;
|
219 |
|
|
parameter pTimerWidth = 19;
|
220 |
|
|
parameter pInitialTimerValue = 19'd500_000; // for synthesis
|
221 |
|
|
//parameter pInitialTimerValue = 19'd2; // for simulation
|
222 |
|
|
|
223 |
|
|
// Registered identifiers:
|
224 |
|
|
reg rInitializeTimer;
|
225 |
|
|
reg rWaitForTimer;
|
226 |
|
|
reg rSaveInput;
|
227 |
|
|
reg rBouncy_Syncd;
|
228 |
|
|
reg [pTimerWidth-1:0] rTimer;
|
229 |
|
|
|
230 |
|
|
// Wire identifiers:
|
231 |
|
|
wire wTransitionDetected;
|
232 |
|
|
wire wTimerFinished;
|
233 |
|
|
|
234 |
|
|
// Controller:
|
235 |
|
|
always @ (posedge gClock or posedge gReset)
|
236 |
|
|
if (gReset)
|
237 |
|
|
{rInitializeTimer,rWaitForTimer,rSaveInput} <= {3'b100};
|
238 |
|
|
else begin
|
239 |
|
|
rInitializeTimer <= rInitializeTimer && !wTransitionDetected ||
|
240 |
|
|
rSaveInput;
|
241 |
|
|
rWaitForTimer <= rInitializeTimer && wTransitionDetected ||
|
242 |
|
|
rWaitForTimer && !wTimerFinished;
|
243 |
|
|
rSaveInput <= rWaitForTimer && wTimerFinished;
|
244 |
|
|
end
|
245 |
|
|
|
246 |
|
|
// Datapath:
|
247 |
|
|
always @ (posedge gClock or posedge gReset)
|
248 |
|
|
if (gReset) begin
|
249 |
|
|
rBouncy_Syncd <= 0;
|
250 |
|
|
oDebounced <= pInitialValue;
|
251 |
|
|
oPulseOnRisingEdge <= 0;
|
252 |
|
|
oPulseOnFallingEdge <= 0;
|
253 |
|
|
rTimer <= pInitialTimerValue;
|
254 |
|
|
end
|
255 |
|
|
else begin
|
256 |
|
|
rBouncy_Syncd <= iBouncy;
|
257 |
|
|
oDebounced <= (rSaveInput) ? rBouncy_Syncd : oDebounced;
|
258 |
|
|
oPulseOnRisingEdge <= (rSaveInput && rBouncy_Syncd);
|
259 |
|
|
oPulseOnFallingEdge <= (rSaveInput && !rBouncy_Syncd);
|
260 |
|
|
rTimer <= (rInitializeTimer) ? pInitialTimerValue : rTimer - 1;
|
261 |
|
|
end
|
262 |
|
|
|
263 |
|
|
assign wTransitionDetected = rBouncy_Syncd ^ oDebounced;
|
264 |
|
|
assign wTimerFinished = (rTimer == 0);
|
265 |
|
|
|
266 |
|
|
endmodule
|