URL
https://opencores.org/ocsvn/forth-cpu/forth-cpu/trunk
Subversion Repositories forth-cpu
[/] [forth-cpu/] [trunk/] [led.vhd] - Rev 3
Compare with Previous | Blame | View Log
-------------------------------------------------------------------------------- --| @file led.vhd --| @brief controls a number of led displays, 8 segment LEDs, there --| is no enable, just write 0 to the displays to turn them off. --| --| @author Richard James Howe. --| @copyright Copyright 2013 Richard James Howe. --| @license MIT --| @email howe.r.j.89@gmail.com --| -------------------------------------------------------------------------------- library ieee,work; use ieee.std_logic_1164.all; use ieee.numeric_std.all; package led_pkg is constant character_length: positive := 4; subtype led_character is std_ulogic_vector(character_length - 1 downto 0); subtype led_8_segment is std_ulogic_vector(7 downto 0); component led_8_segment_display is generic( clock_frequency: positive; use_bcd_not_hex: boolean := true; refresh_rate_us: natural := 1500; number_of_led_displays: positive := 4); port( clk: in std_ulogic; rst: in std_ulogic; leds_we: in std_ulogic; leds: in std_ulogic_vector((number_of_led_displays * character_length) - 1 downto 0); -- Physical outputs an: out std_ulogic_vector(number_of_led_displays - 1 downto 0); -- anodes, controls on/off ka: out std_ulogic_vector(7 downto 0)); -- cathodes, data on display end component; end package; --| This module implements a 8 segment display driver, with 4 displays in total: --| --| _____________________ an (selects segment) --| | | | | --| __ __ __ __ --| | | | | | | | | --| |__| |__| |__| |__| --| | | | | | | | | --| |__|. |__|. |__|. |__|. --| |____|_____|_____|____ ka (value to display on segment) --| --| Each of the display shares a common anode for all of its LEDs, this can be --| used to select an individual display library ieee,work; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.util.reg; use work.util.timer_us; use work.util.invert; use work.led_pkg.all; entity led_8_segment_display is generic( clock_frequency: positive; use_bcd_not_hex: boolean := true; refresh_rate_us: natural := 1500; number_of_led_displays: positive := 4); port( clk: in std_ulogic; rst: in std_ulogic; leds_we: in std_ulogic; leds: in std_ulogic_vector((number_of_led_displays * character_length) - 1 downto 0); -- Physical outputs an: out std_ulogic_vector(number_of_led_displays - 1 downto 0); -- anodes, controls on/off ka: out std_ulogic_vector(7 downto 0)); -- cathodes, data on display end; architecture rtl of led_8_segment_display is -- 8 Segment LED lookup table converts a BCD character into a value -- that can be displayed on an 8 segment display. The layout of which -- is as follows: -- -- A -- --- -- F | | B -- |___| -- E | G | C -- |___| . DP -- D -- -- The following encoding is used to convert the input BCD character -- into a value that can be put onto the display. -- -- ----------------------------------------- -- | | DP| G | F | E | D | C | B | A | Hex | -- |BCD| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |Hi Lo| -- ----------------------------------------- -- | 0 | | | 1 | 1 | 1 | 1 | 1 | 1 | 3 F | -- | 1 | | | | | | 1 | 1 | | 0 6 | -- | 2 | | 1 | | 1 | 1 | | 1 | 1 | 5 B | -- | 3 | | 1 | | | 1 | 1 | 1 | 1 | 4 F | -- | 4 | | 1 | 1 | | | 1 | 1 | | 6 6 | -- | 5 | | 1 | 1 | | 1 | 1 | | 1 | 6 D | -- | 6 | | 1 | 1 | 1 | 1 | 1 | | 1 | 7 D | -- | 7 | | | | | | 1 | 1 | 1 | 0 7 | -- | 8 | | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 7 F | -- | 9 | | 1 | 1 | | 1 | 1 | 1 | 1 | 6 F | -- | | | | | | | | | | 0 0 | -- | . | 1 | | | | | | | | 8 0 | -- | - | | 1 | | | | | | | 4 0 | -- ----------------------------------------- -- | A | | 1 | 1 | 1 | | 1 | 1 | 1 | 7 7 | -- | b | | 1 | 1 | 1 | 1 | 1 | | | 7 C | -- | C | | | 1 | 1 | 1 | | | 1 | 3 9 | -- | d | | 1 | | 1 | 1 | 1 | 1 | | 5 E | -- | E | | 1 | 1 | 1 | 1 | | | 1 | 7 9 | -- | F | | 1 | 1 | 1 | | | | 1 | 7 1 | -- ----------------------------------------- -- -- The table is then inverted before it goes to the output. -- function hex_to_8segment(a: led_character) return led_8_segment is variable r: std_ulogic_vector(7 downto 0); begin case a is when "0000" => r := x"3F"; -- 0 when "0001" => r := x"06"; -- 1 when "0010" => r := x"5B"; -- 2 when "0011" => r := x"4F"; -- 3 when "0100" => r := x"66"; -- 4 when "0101" => r := x"6D"; -- 5 when "0110" => r := x"7D"; -- 6 when "0111" => r := x"07"; -- 7 when "1000" => r := x"7F"; -- 8 when "1001" => r := x"6F"; -- 9 when "1010" => r := x"77"; -- A when "1011" => r := x"7C"; -- b when "1100" => r := x"39"; -- C when "1101" => r := x"5E"; -- d when "1110" => r := x"79"; -- E when "1111" => r := x"71"; -- F when others => r := x"00"; -- Unused end case; return r; end function; function bcd_to_8segment(a: led_character) return led_8_segment is variable r: std_ulogic_vector(7 downto 0); begin case a is when "0000" => r := x"3F"; -- 0 when "0001" => r := x"06"; -- 1 when "0010" => r := x"5B"; -- 2 when "0011" => r := x"4F"; -- 3 when "0100" => r := x"66"; -- 4 when "0101" => r := x"6D"; -- 5 when "0110" => r := x"7D"; -- 6 when "0111" => r := x"07"; -- 7 when "1000" => r := x"7F"; -- 8 when "1001" => r := x"6F"; -- 9 when "1010" => r := x"00"; -- Blank when "1011" => r := x"80"; -- . when "1100" => r := x"40"; -- - when "1101" => r := x"00"; -- Unused when "1110" => r := x"00"; -- Unused when "1111" => r := x"00"; -- Unused when others => r := x"00"; -- Unused end case; return r; end function; function char_to_8segment(a: led_character) return led_8_segment is begin if use_bcd_not_hex then return invert(bcd_to_8segment(a)); else return invert(hex_to_8segment(a)); end if; end function; signal leds_o: std_ulogic_vector(leds'range) := (others => '0'); signal do_shift: std_ulogic := '0'; signal shift_reg: std_ulogic_vector(number_of_led_displays - 1 downto 0) := (0 => '1', others => '0'); signal leds_reg_o: std_ulogic_vector(leds'range) := (others => '0'); signal leds_reg_we_o: std_ulogic := '0'; begin an <= invert(shift_reg); segment_reg: entity work.reg generic map(N => number_of_led_displays * character_length) port map( clk => clk, rst => rst, we => leds_we, di => leds, do => leds_reg_o); segment_reg_re: entity work.reg generic map(N => 1) port map( clk => clk, rst => rst, we => '1', di(0) => leds_we, do(0) => leds_reg_we_o); led_gen: for i in number_of_led_displays - 1 downto 0 generate led_i: entity work.reg generic map( N => character_length) port map( clk => clk, rst => rst, we => leds_reg_we_o, di => leds_reg_o((i*character_length) + character_length - 1 downto (i*character_length)), do => leds_o((i*character_length) + character_length - 1 downto (i*character_length))); end generate; timer: entity work.timer_us generic map( clock_frequency => clock_frequency, timer_period_us => refresh_rate_us) port map( clk => clk, rst => rst, co => do_shift); process(clk, do_shift, shift_reg) begin if rising_edge(clk) then if do_shift = '1' then shift_reg <= shift_reg(number_of_led_displays - 2 downto 0) & shift_reg(number_of_led_displays - 1); end if; else shift_reg <= shift_reg; end if; end process; process(leds_o, shift_reg) begin ka <= (others => '0'); for i in number_of_led_displays - 1 downto 0 loop if '1' = shift_reg(number_of_led_displays - i - 1) then ka <= char_to_8segment(leds_o(i*character_length + character_length - 1 downto (i*character_length))); end if; end loop; end process; end architecture;