Project

General

Profile

Download (7.89 KB) Statistics
| Branch: | Tag: | Revision:
1
--------------------------------------------------------------------------------
2
--| @file led.vhd
3
--| @brief controls a number of led displays, 8 segment LEDs, there
4
--| is no enable, just write 0 to the displays to turn them off.
5
--|
6
--| @author     Richard James Howe.
7
--| @copyright  Copyright 2013 Richard James Howe.
8
--| @license    MIT
9
--| @email      howe.r.j.89@gmail.com
10
--|
11
--------------------------------------------------------------------------------
12
library ieee,work;
13
use ieee.std_logic_1164.all;
14
use ieee.numeric_std.all;
15

    
16
package led_pkg is
17
	constant character_length: positive := 4;
18

    
19
	subtype led_character is std_ulogic_vector(character_length - 1 downto 0);
20
	subtype led_8_segment is std_ulogic_vector(7 downto 0);
21

    
22
	component led_8_segment_display is
23
		generic(
24
			clock_frequency:        positive;
25
			use_bcd_not_hex:        boolean := true;
26
			refresh_rate_us:        natural := 1500;
27
			number_of_led_displays: positive := 4);
28
		port(
29
			clk:      in   std_ulogic;
30
			rst:      in   std_ulogic;
31

    
32
			leds_we:  in   std_ulogic;
33
			leds:     in   std_ulogic_vector((number_of_led_displays * character_length) - 1 downto 0);
34

    
35
			-- Physical outputs
36
			an:       out  std_ulogic_vector(number_of_led_displays - 1 downto 0);  -- anodes, controls on/off
37
			ka:       out  std_ulogic_vector(7 downto 0)); -- cathodes, data on display
38
	end component;
39

    
40
end package;
41

    
42

    
43
--| This module implements a 8 segment display driver, with 4 displays in total:
44
--|
45
--|    _____________________ an (selects segment)
46
--|    |     |     |     |
47
--|   __    __    __    __
48
--|  |  |  |  |  |  |  |  |
49
--|  |__|  |__|  |__|  |__|
50
--|  |  |  |  |  |  |  |  |
51
--|  |__|. |__|. |__|. |__|.
52
--|   |____|_____|_____|____ ka (value to display on segment)
53
--|
54
--| Each of the display shares a common anode for all of its LEDs, this can be
55
--| used to select an individual display
56

    
57
library ieee,work;
58
use ieee.std_logic_1164.all;
59
use ieee.numeric_std.all;
60
use work.util.reg;
61
use work.util.timer_us;
62
use work.util.invert;
63
use work.led_pkg.all;
64

    
65
entity led_8_segment_display is
66
	generic(
67
		clock_frequency:        positive;
68
		use_bcd_not_hex:        boolean  := true;
69
		refresh_rate_us:        natural  := 1500;
70
		number_of_led_displays: positive := 4);
71
	port(
72
		clk:      in   std_ulogic;
73
		rst:      in   std_ulogic;
74

    
75
		leds_we:  in   std_ulogic;
76
		leds:     in   std_ulogic_vector((number_of_led_displays * character_length) - 1 downto 0);
77

    
78
		-- Physical outputs
79
		an:       out  std_ulogic_vector(number_of_led_displays - 1 downto 0);  -- anodes, controls on/off
80
		ka:       out  std_ulogic_vector(7 downto 0)); -- cathodes, data on display
81
end;
82

    
83
architecture rtl of led_8_segment_display is
84

    
85
	-- 8 Segment LED lookup table converts a BCD character into a value
86
	-- that can be displayed on an 8 segment display. The layout of which
87
	-- is as follows:
88
	--
89
	--       A
90
	--      ---
91
	--   F |   | B
92
	--     |___|
93
	--   E | G | C
94
	--     |___| . DP
95
	--       D
96
	--
97
	-- The following encoding is used to convert the input BCD character
98
	-- into a value that can be put onto the display.
99
	--
100
	--  -----------------------------------------
101
	-- |   | DP| G | F | E | D | C | B | A | Hex |
102
	-- |BCD| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |Hi Lo|
103
	--  -----------------------------------------
104
	-- | 0 |   |   | 1 | 1 | 1 | 1 | 1 | 1 | 3 F |
105
	-- | 1 |   |   |   |   |   | 1 | 1 |   | 0 6 |
106
	-- | 2 |   | 1 |   | 1 | 1 |   | 1 | 1 | 5 B |
107
	-- | 3 |   | 1 |   |   | 1 | 1 | 1 | 1 | 4 F |
108
	-- | 4 |   | 1 | 1 |   |   | 1 | 1 |   | 6 6 |
109
	-- | 5 |   | 1 | 1 |   | 1 | 1 |   | 1 | 6 D |
110
	-- | 6 |   | 1 | 1 | 1 | 1 | 1 |   | 1 | 7 D |
111
	-- | 7 |   |   |   |   |   | 1 | 1 | 1 | 0 7 |
112
	-- | 8 |   | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 7 F |
113
	-- | 9 |   | 1 | 1 |   | 1 | 1 | 1 | 1 | 6 F |
114
	-- |   |   |   |   |   |   |   |   |   | 0 0 |
115
	-- | . | 1 |   |   |   |   |   |   |   | 8 0 |
116
	-- | - |   | 1 |   |   |   |   |   |   | 4 0 |
117
	--  -----------------------------------------
118
	-- | A |   | 1 | 1 | 1 |   | 1 | 1 | 1 | 7 7 |
119
	-- | b |   | 1 | 1 | 1 | 1 | 1 |   |   | 7 C |
120
	-- | C |   |   | 1 | 1 | 1 |   |   | 1 | 3 9 |
121
	-- | d |   | 1 |   | 1 | 1 | 1 | 1 |   | 5 E |
122
	-- | E |   | 1 | 1 | 1 | 1 |   |   | 1 | 7 9 |
123
	-- | F |   | 1 | 1 | 1 |   |   |   | 1 | 7 1 |
124
	--  -----------------------------------------
125
	--
126
	-- The table is then inverted before it goes to the output.
127
	--
128

    
129
	function hex_to_8segment(a: led_character) return led_8_segment is
130
		variable r: std_ulogic_vector(7 downto 0);
131
	begin
132
		case a is
133
			when "0000" => r := x"3F"; -- 0
134
			when "0001" => r := x"06"; -- 1
135
			when "0010" => r := x"5B"; -- 2
136
			when "0011" => r := x"4F"; -- 3
137
			when "0100" => r := x"66"; -- 4
138
			when "0101" => r := x"6D"; -- 5
139
			when "0110" => r := x"7D"; -- 6
140
			when "0111" => r := x"07"; -- 7
141
			when "1000" => r := x"7F"; -- 8
142
			when "1001" => r := x"6F"; -- 9
143
			when "1010" => r := x"77"; -- A
144
			when "1011" => r := x"7C"; -- b
145
			when "1100" => r := x"39"; -- C
146
			when "1101" => r := x"5E"; -- d
147
			when "1110" => r := x"79"; -- E
148
			when "1111" => r := x"71"; -- F
149
			when others => r := x"00"; -- Unused
150
		end case;
151
		return r;
152
	end function;
153

    
154
	function bcd_to_8segment(a: led_character) return led_8_segment is
155
		variable r: std_ulogic_vector(7 downto 0);
156
	begin
157
		case a is
158
			when "0000" => r := x"3F"; -- 0
159
			when "0001" => r := x"06"; -- 1
160
			when "0010" => r := x"5B"; -- 2
161
			when "0011" => r := x"4F"; -- 3
162
			when "0100" => r := x"66"; -- 4
163
			when "0101" => r := x"6D"; -- 5
164
			when "0110" => r := x"7D"; -- 6
165
			when "0111" => r := x"07"; -- 7
166
			when "1000" => r := x"7F"; -- 8
167
			when "1001" => r := x"6F"; -- 9
168
			when "1010" => r := x"00"; -- Blank
169
			when "1011" => r := x"80"; -- .
170
			when "1100" => r := x"40"; -- -
171
			when "1101" => r := x"00"; -- Unused
172
			when "1110" => r := x"00"; -- Unused
173
			when "1111" => r := x"00"; -- Unused
174
			when others => r := x"00"; -- Unused
175
		end case;
176
		return r;
177
	end function;
178

    
179
	function char_to_8segment(a: led_character) return led_8_segment is
180
	begin
181
		if use_bcd_not_hex then
182
			return invert(bcd_to_8segment(a));
183
		else
184
			return invert(hex_to_8segment(a));
185
		end if;
186
	end function;
187

    
188
	signal leds_o: std_ulogic_vector(leds'range) := (others => '0');
189

    
190
	signal do_shift:  std_ulogic := '0';
191
	signal shift_reg: std_ulogic_vector(number_of_led_displays - 1 downto 0) := (0 => '1', others => '0');
192

    
193

    
194
	signal leds_reg_o: std_ulogic_vector(leds'range) := (others => '0');
195
	signal leds_reg_we_o: std_ulogic := '0';
196
begin
197
	an <= invert(shift_reg);
198

    
199
	segment_reg: entity work.reg
200
		generic map(N => number_of_led_displays * character_length)
201
		port map(
202
			clk => clk,
203
			rst => rst,
204
			we  => leds_we,
205
			di  => leds,
206
			do  => leds_reg_o);
207

    
208
	segment_reg_re: entity work.reg
209
		generic map(N => 1)
210
		port map(
211
			clk   => clk,
212
			rst   => rst,
213
			we    => '1',
214
			di(0) => leds_we,
215
			do(0) => leds_reg_we_o);
216

    
217
	led_gen: for i in number_of_led_displays - 1 downto 0 generate
218
		led_i: entity work.reg
219
			generic map(
220
				N   => character_length)
221
			port map(
222
				clk => clk,
223
				rst => rst,
224
				we  => leds_reg_we_o,
225
				di  => leds_reg_o((i*character_length) + character_length - 1 downto (i*character_length)),
226
				do  => leds_o((i*character_length) + character_length - 1 downto (i*character_length)));
227
	end generate;
228

    
229
	timer: entity work.timer_us
230
		generic map(
231
			clock_frequency => clock_frequency,
232
			timer_period_us => refresh_rate_us)
233
		port map(
234
			clk             => clk,
235
			rst             => rst,
236
			co              => do_shift);
237

    
238
	process(clk, do_shift, shift_reg)
239
	begin
240
		if rising_edge(clk) then
241
			if do_shift = '1' then
242
				shift_reg <= shift_reg(number_of_led_displays - 2 downto 0) & shift_reg(number_of_led_displays - 1);
243
			end if;
244
		else
245
			shift_reg <= shift_reg;
246
		end if;
247
	end process;
248

    
249
	process(leds_o, shift_reg)
250
	begin
251
		ka <= (others => '0');
252

    
253
		for i in  number_of_led_displays - 1 downto 0 loop
254
			if '1' = shift_reg(number_of_led_displays - i - 1) then
255
				ka <= char_to_8segment(leds_o(i*character_length + character_length - 1 downto (i*character_length)));
256
			end if;
257
		end loop;
258
	end process;
259
end architecture;
260

    
(2-2/4)