Код
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all; -- for conversions to std_logic_vector from natural
entity lcd_controller is
generic(LCD_DATA_SIZE : natural := 7;
LCD_ROW_SIZE : natural := 2;
LCD_COLUMN_SIZE : natural := 16);
port(reset, clk : in std_logic;
lcd_rs, lcd_rw, lcd_e : out std_logic;
lcd_data : out std_logic_vector(LCD_DATA_SIZE downto 0));
end entity lcd_controller;
architecture behavioural of lcd_controller is
-- PCI_clk = 66 MHz => T_clk = 15 ns => T_count = 2 * T_clk = 30 ns
constant delay_30ms : natural := 1000000;
constant delay_6ms : natural := 200000;
constant delay_2ms : natural := 60000;
constant delay_2x2ms : natural := 120000;
constant delay_3x2ms : natural := 180000;
constant delay_4x2ms : natural := 240000;
constant delay_5x2ms : natural := 300000;
constant delay_6x2ms : natural := 360000;
constant delay_7x2ms : natural := 420000;
constant delay_8x2ms : natural := 480000;
constant lcd_init_state_0 : natural := 0;
constant lcd_init_state_1 : natural := delay_30ms;
constant lcd_init_state_2 : natural := lcd_init_state_1 + delay_6ms;
constant lcd_init_state_3 : natural := lcd_init_state_2 + delay_2ms;
constant lcd_init_state_4 : natural := lcd_init_state_3 + delay_2ms;
constant lcd_init_state_5 : natural := lcd_init_state_4 + delay_2ms;
constant lcd_init_state_6 : natural := lcd_init_state_5 + delay_2ms;
constant lcd_init_state_7 : natural := lcd_init_state_6 + delay_2ms;
constant lcd_init_state_8 : natural := lcd_init_state_7 + delay_2ms;
constant lcd_init_state_9 : natural := lcd_init_state_8 + delay_2ms;
constant lcd_init_state_10 : natural := lcd_init_state_9 + delay_2ms;
constant lcd_init_state_11 : natural := lcd_init_state_10 + delay_2ms;
constant lcd_init_state_12 : natural := lcd_init_state_11 + delay_2ms;
constant lcd_init_state_13 : natural := lcd_init_state_12 + delay_2ms;
constant lcd_init_state_14 : natural := lcd_init_state_13 + delay_2ms;
constant lcd_init_state_15 : natural := lcd_init_state_14 + delay_2ms;
constant lcd_init_state_16 : natural := lcd_init_state_15 + delay_2ms;
constant lcd_init_state_17 : natural := lcd_init_state_16 + delay_2ms;
constant lcd_init_state_18 : natural := lcd_init_state_17 + delay_2ms;
constant lcd_init_state_is_finished : natural := lcd_init_state_18 + delay_2ms;
signal lcd_rs_sig, lcd_rw_sig, lcd_e_sig : std_logic;
signal lcd_data_sig : std_logic_vector(LCD_DATA_SIZE downto 0) := X"00";
signal clk_counter : natural := 0;
-- lcd row and column place of the symbol
signal lcd_row : natural range 0 to LCD_ROW_SIZE := 1;
signal lcd_column : natural range 0 to LCD_COLUMN_SIZE := 1;
signal start_write_digit_state : natural := 0;
signal pci_to_lcd_data_sig : natural := 0;
signal lcd_is_initialized, write_digit_is_started : natural range 0 to 1 := 0;
-- calculation of symbol absolute position
pure function calculate_lcd_symbol_position(lcd_row_position : in natural; lcd_column_position : in natural) return natural is
constant LCD_FIRST_ROW_ADDRESS_CORRECTION : natural := 127;
constant LCD_SECOND_ROW_ADDRESS_CORRECTION : natural := 191;
begin
case lcd_row_position is
when 1 =>
return lcd_column_position + LCD_FIRST_ROW_ADDRESS_CORRECTION;
when 2 =>
return lcd_column_position + LCD_SECOND_ROW_ADDRESS_CORRECTION;
when others =>
return lcd_column_position + LCD_FIRST_ROW_ADDRESS_CORRECTION;
end case;
end function calculate_lcd_symbol_position;
-- ascii correction of the digit for correct lcd writing
pure function do_lcd_ascii_correction(ascii_lcd_digit : in natural) return natural is
constant ASCII_LCD_CORRECTION : natural := 48;
begin
return ascii_lcd_digit + ASCII_LCD_CORRECTION;
end function do_lcd_ascii_correction;
begin
lcd_init_and_write:
process(reset, clk, clk_counter)
begin
if (reset = '0') then
clk_counter <= 0;
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"00";
lcd_is_initialized <= 0;
start_write_digit_state <= 0;
write_digit_is_started <= 0;
else
if ((clk'event) and (clk = '1')) then
clk_counter <= clk_counter + 1;
if (lcd_is_initialized = 0) then
case clk_counter is
when lcd_init_state_0 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"00";
when lcd_init_state_1 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"38";
when lcd_init_state_2 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '1';
lcd_data_sig <= X"38";
when lcd_init_state_3 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"38";
when lcd_init_state_4 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '1';
lcd_data_sig <= X"38";
when lcd_init_state_5 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"38";
when lcd_init_state_6 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '1';
lcd_data_sig <= X"38";
when lcd_init_state_7 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"38";
when lcd_init_state_8 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '1';
lcd_data_sig <= X"38";
when lcd_init_state_9 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"38";
when lcd_init_state_10 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"0C";
when lcd_init_state_11 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '1';
lcd_data_sig <= X"0C";
when lcd_init_state_12 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"0C";
when lcd_init_state_13 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"01";
when lcd_init_state_14 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '1';
lcd_data_sig <= X"01";
when lcd_init_state_15 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"01";
when lcd_init_state_16 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"06";
when lcd_init_state_17 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '1';
lcd_data_sig <= X"06";
when lcd_init_state_18 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"06";
when lcd_init_state_is_finished =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"06";
lcd_is_initialized <= 1;
when others =>
end case;
else -- lcd is ready for data display
if (write_digit_is_started = 0) then
start_write_digit_state <= clk_counter;
write_digit_is_started <= 1;
end if;
if (clk_counter < (start_write_digit_state + delay_8x2ms)) then
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= conv_std_logic_vector(do_lcd_ascii_correction(pci_to_lcd_data_sig),LCD_DATA_SIZE + 1);
if (clk_counter < (start_write_digit_state + delay_7x2ms)) then
lcd_rs_sig <= '1';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= conv_std_logic_vector(do_lcd_ascii_correction(pci_to_lcd_data_sig),LCD_DATA_SIZE + 1);
if (clk_counter < (start_write_digit_state + delay_6x2ms)) then
lcd_rs_sig <= '1';
lcd_rw_sig <= '0';
lcd_e_sig <= '1';
lcd_data_sig <= conv_std_logic_vector(do_lcd_ascii_correction(pci_to_lcd_data_sig),LCD_DATA_SIZE + 1);
if (clk_counter < (start_write_digit_state + delay_5x2ms)) then
lcd_rs_sig <= '1';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= conv_std_logic_vector(do_lcd_ascii_correction(pci_to_lcd_data_sig),LCD_DATA_SIZE + 1);
if (clk_counter < (start_write_digit_state + delay_4x2ms)) then
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= conv_std_logic_vector(do_lcd_ascii_correction(pci_to_lcd_data_sig),LCD_DATA_SIZE + 1);
if (clk_counter < (start_write_digit_state + delay_3x2ms)) then
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= conv_std_logic_vector(calculate_lcd_symbol_position(lcd_row,lcd_column),LCD_DATA_SIZE + 1);
if (clk_counter < (start_write_digit_state + delay_2x2ms)) then
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '1';
lcd_data_sig <= conv_std_logic_vector(calculate_lcd_symbol_position(lcd_row,lcd_column),LCD_DATA_SIZE + 1);
if (clk_counter < (start_write_digit_state + delay_2ms)) then
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= conv_std_logic_vector(calculate_lcd_symbol_position(lcd_row,lcd_column),LCD_DATA_SIZE + 1);
end if;
end if;
end if;
end if;
end if;
end if;
end if;
else
write_digit_is_started <= 0;
end if;
end if;
end if;
end if;
end process lcd_init_and_write;
lcd_rs <= lcd_rs_sig;
lcd_rw <= lcd_rw_sig;
lcd_e <= lcd_e_sig;
lcd_data(LCD_DATA_SIZE downto 0) <= lcd_data_sig(LCD_DATA_SIZE downto 0);
end architecture behavioural;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all; -- for conversions to std_logic_vector from natural
entity lcd_controller is
generic(LCD_DATA_SIZE : natural := 7;
LCD_ROW_SIZE : natural := 2;
LCD_COLUMN_SIZE : natural := 16);
port(reset, clk : in std_logic;
lcd_rs, lcd_rw, lcd_e : out std_logic;
lcd_data : out std_logic_vector(LCD_DATA_SIZE downto 0));
end entity lcd_controller;
architecture behavioural of lcd_controller is
-- PCI_clk = 66 MHz => T_clk = 15 ns => T_count = 2 * T_clk = 30 ns
constant delay_30ms : natural := 1000000;
constant delay_6ms : natural := 200000;
constant delay_2ms : natural := 60000;
constant delay_2x2ms : natural := 120000;
constant delay_3x2ms : natural := 180000;
constant delay_4x2ms : natural := 240000;
constant delay_5x2ms : natural := 300000;
constant delay_6x2ms : natural := 360000;
constant delay_7x2ms : natural := 420000;
constant delay_8x2ms : natural := 480000;
constant lcd_init_state_0 : natural := 0;
constant lcd_init_state_1 : natural := delay_30ms;
constant lcd_init_state_2 : natural := lcd_init_state_1 + delay_6ms;
constant lcd_init_state_3 : natural := lcd_init_state_2 + delay_2ms;
constant lcd_init_state_4 : natural := lcd_init_state_3 + delay_2ms;
constant lcd_init_state_5 : natural := lcd_init_state_4 + delay_2ms;
constant lcd_init_state_6 : natural := lcd_init_state_5 + delay_2ms;
constant lcd_init_state_7 : natural := lcd_init_state_6 + delay_2ms;
constant lcd_init_state_8 : natural := lcd_init_state_7 + delay_2ms;
constant lcd_init_state_9 : natural := lcd_init_state_8 + delay_2ms;
constant lcd_init_state_10 : natural := lcd_init_state_9 + delay_2ms;
constant lcd_init_state_11 : natural := lcd_init_state_10 + delay_2ms;
constant lcd_init_state_12 : natural := lcd_init_state_11 + delay_2ms;
constant lcd_init_state_13 : natural := lcd_init_state_12 + delay_2ms;
constant lcd_init_state_14 : natural := lcd_init_state_13 + delay_2ms;
constant lcd_init_state_15 : natural := lcd_init_state_14 + delay_2ms;
constant lcd_init_state_16 : natural := lcd_init_state_15 + delay_2ms;
constant lcd_init_state_17 : natural := lcd_init_state_16 + delay_2ms;
constant lcd_init_state_18 : natural := lcd_init_state_17 + delay_2ms;
constant lcd_init_state_is_finished : natural := lcd_init_state_18 + delay_2ms;
signal lcd_rs_sig, lcd_rw_sig, lcd_e_sig : std_logic;
signal lcd_data_sig : std_logic_vector(LCD_DATA_SIZE downto 0) := X"00";
signal clk_counter : natural := 0;
-- lcd row and column place of the symbol
signal lcd_row : natural range 0 to LCD_ROW_SIZE := 1;
signal lcd_column : natural range 0 to LCD_COLUMN_SIZE := 1;
signal start_write_digit_state : natural := 0;
signal pci_to_lcd_data_sig : natural := 0;
signal lcd_is_initialized, write_digit_is_started : natural range 0 to 1 := 0;
-- calculation of symbol absolute position
pure function calculate_lcd_symbol_position(lcd_row_position : in natural; lcd_column_position : in natural) return natural is
constant LCD_FIRST_ROW_ADDRESS_CORRECTION : natural := 127;
constant LCD_SECOND_ROW_ADDRESS_CORRECTION : natural := 191;
begin
case lcd_row_position is
when 1 =>
return lcd_column_position + LCD_FIRST_ROW_ADDRESS_CORRECTION;
when 2 =>
return lcd_column_position + LCD_SECOND_ROW_ADDRESS_CORRECTION;
when others =>
return lcd_column_position + LCD_FIRST_ROW_ADDRESS_CORRECTION;
end case;
end function calculate_lcd_symbol_position;
-- ascii correction of the digit for correct lcd writing
pure function do_lcd_ascii_correction(ascii_lcd_digit : in natural) return natural is
constant ASCII_LCD_CORRECTION : natural := 48;
begin
return ascii_lcd_digit + ASCII_LCD_CORRECTION;
end function do_lcd_ascii_correction;
begin
lcd_init_and_write:
process(reset, clk, clk_counter)
begin
if (reset = '0') then
clk_counter <= 0;
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"00";
lcd_is_initialized <= 0;
start_write_digit_state <= 0;
write_digit_is_started <= 0;
else
if ((clk'event) and (clk = '1')) then
clk_counter <= clk_counter + 1;
if (lcd_is_initialized = 0) then
case clk_counter is
when lcd_init_state_0 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"00";
when lcd_init_state_1 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"38";
when lcd_init_state_2 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '1';
lcd_data_sig <= X"38";
when lcd_init_state_3 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"38";
when lcd_init_state_4 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '1';
lcd_data_sig <= X"38";
when lcd_init_state_5 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"38";
when lcd_init_state_6 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '1';
lcd_data_sig <= X"38";
when lcd_init_state_7 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"38";
when lcd_init_state_8 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '1';
lcd_data_sig <= X"38";
when lcd_init_state_9 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"38";
when lcd_init_state_10 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"0C";
when lcd_init_state_11 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '1';
lcd_data_sig <= X"0C";
when lcd_init_state_12 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"0C";
when lcd_init_state_13 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"01";
when lcd_init_state_14 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '1';
lcd_data_sig <= X"01";
when lcd_init_state_15 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"01";
when lcd_init_state_16 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"06";
when lcd_init_state_17 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '1';
lcd_data_sig <= X"06";
when lcd_init_state_18 =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"06";
when lcd_init_state_is_finished =>
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= X"06";
lcd_is_initialized <= 1;
when others =>
end case;
else -- lcd is ready for data display
if (write_digit_is_started = 0) then
start_write_digit_state <= clk_counter;
write_digit_is_started <= 1;
end if;
if (clk_counter < (start_write_digit_state + delay_8x2ms)) then
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= conv_std_logic_vector(do_lcd_ascii_correction(pci_to_lcd_data_sig),LCD_DATA_SIZE + 1);
if (clk_counter < (start_write_digit_state + delay_7x2ms)) then
lcd_rs_sig <= '1';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= conv_std_logic_vector(do_lcd_ascii_correction(pci_to_lcd_data_sig),LCD_DATA_SIZE + 1);
if (clk_counter < (start_write_digit_state + delay_6x2ms)) then
lcd_rs_sig <= '1';
lcd_rw_sig <= '0';
lcd_e_sig <= '1';
lcd_data_sig <= conv_std_logic_vector(do_lcd_ascii_correction(pci_to_lcd_data_sig),LCD_DATA_SIZE + 1);
if (clk_counter < (start_write_digit_state + delay_5x2ms)) then
lcd_rs_sig <= '1';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= conv_std_logic_vector(do_lcd_ascii_correction(pci_to_lcd_data_sig),LCD_DATA_SIZE + 1);
if (clk_counter < (start_write_digit_state + delay_4x2ms)) then
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= conv_std_logic_vector(do_lcd_ascii_correction(pci_to_lcd_data_sig),LCD_DATA_SIZE + 1);
if (clk_counter < (start_write_digit_state + delay_3x2ms)) then
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= conv_std_logic_vector(calculate_lcd_symbol_position(lcd_row,lcd_column),LCD_DATA_SIZE + 1);
if (clk_counter < (start_write_digit_state + delay_2x2ms)) then
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '1';
lcd_data_sig <= conv_std_logic_vector(calculate_lcd_symbol_position(lcd_row,lcd_column),LCD_DATA_SIZE + 1);
if (clk_counter < (start_write_digit_state + delay_2ms)) then
lcd_rs_sig <= '0';
lcd_rw_sig <= '0';
lcd_e_sig <= '0';
lcd_data_sig <= conv_std_logic_vector(calculate_lcd_symbol_position(lcd_row,lcd_column),LCD_DATA_SIZE + 1);
end if;
end if;
end if;
end if;
end if;
end if;
end if;
else
write_digit_is_started <= 0;
end if;
end if;
end if;
end if;
end process lcd_init_and_write;
lcd_rs <= lcd_rs_sig;
lcd_rw <= lcd_rw_sig;
lcd_e <= lcd_e_sig;
lcd_data(LCD_DATA_SIZE downto 0) <= lcd_data_sig(LCD_DATA_SIZE downto 0);
end architecture behavioural;