Line 23... |
Line 23... |
--
|
--
|
-- VHDL Entity: o8_hd44780_if
|
-- VHDL Entity: o8_hd44780_if
|
-- Description: Provides low-level timing of the control signals in 8-bit mode
|
-- Description: Provides low-level timing of the control signals in 8-bit mode
|
-- (required by o8_hd44780_if)
|
-- (required by o8_hd44780_if)
|
--
|
--
|
|
-- Note: This code attempts to implement the timing diagram in the HD44780U
|
|
-- LCD II datasheet with a few simplifications. Chiefly, DQ is updated
|
|
-- at the start of E, rather than attempting to assert within Tds of
|
|
-- the falling edge of E. Further, both RS and DQ are asserted until
|
|
-- the end of Tcycle, where Tcycle is defined as TcycleE + Tas
|
|
|
-- Revision History
|
-- Revision History
|
-- Author Date Change
|
-- Author Date Change
|
------------------ -------- ---------------------------------------------------
|
------------------ -------- ---------------------------------------------------
|
-- Seth Henry 04/12/21 Design Start
|
-- Seth Henry 04/12/21 Design Start
|
|
-- Seth Henry 09/19/23 Rewrote IF to use a single cycle timer
|
|
|
library ieee;
|
library ieee;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_unsigned.all;
|
use ieee.std_logic_unsigned.all;
|
use ieee.std_logic_arith.all;
|
use ieee.std_logic_arith.all;
|
use ieee.std_logic_misc.all;
|
use ieee.std_logic_misc.all;
|
|
|
entity hd44780_8b is
|
entity hd44780_8b is
|
generic(
|
generic(
|
Tsu : integer := 40; -- ns
|
Tas : integer := 50; -- ns
|
Tpw : integer := 250; -- nS
|
Tpwe : integer := 450; -- ns
|
Tcyc : integer := 500; -- nS
|
Tcyce : integer := 1000; -- ns
|
Clock_Frequency : real := 50000000.0; -- Hz
|
Clock_Frequency : real := 100000000.0; -- Hz
|
Reset_Level : std_logic := '1'
|
Reset_Level : std_logic := '1'
|
);
|
);
|
port(
|
port(
|
Clock : in std_logic;
|
Clock : in std_logic;
|
Reset : in std_logic;
|
Reset : in std_logic;
|
Line 74... |
Line 81... |
return retval;
|
return retval;
|
end function;
|
end function;
|
|
|
constant CONV_NANOSECS : real := 0.000000001;
|
constant CONV_NANOSECS : real := 0.000000001;
|
|
|
constant Tsu_r : real := CONV_NANOSECS * real(Tsu);
|
constant Tas_r : real := CONV_NANOSECS * real(Tas);
|
constant Tpw_r : real := CONV_NANOSECS * real(Tpw);
|
constant Tpwe_r : real := CONV_NANOSECS * real(Tpwe + Tas);
|
constant Tcyc_r : real := CONV_NANOSECS * real(Tcyc);
|
constant Tcyc_r : real := CONV_NANOSECS * real(Tcyce + Tas);
|
|
|
constant TCYC_i : integer := integer(Clock_Frequency * Tcyc_r);
|
constant TCYC_i : integer := integer(Clock_Frequency * Tcyc_r);
|
constant TCYC_BITS : integer := ceil_log2(TCYC_i);
|
constant TCYC_BITS : integer := ceil_log2(TCYC_i);
|
|
|
constant TCYC_DELAY : std_logic_vector(TCYC_BITS-1 downto 0) :=
|
constant TCYC_DELAY : std_logic_vector(TCYC_BITS-1 downto 0) :=
|
conv_std_logic_vector(TCYC_i-1, TCYC_BITS);
|
conv_std_logic_vector(TCYC_i-1, TCYC_BITS);
|
signal tcyc_timer : std_logic_vector(TCYC_BITS - 1 downto 0) :=
|
signal tcyc_timer : std_logic_vector(TCYC_BITS - 1 downto 0) :=
|
(others => '0');
|
(others => '0');
|
|
|
constant TPW_i : integer := integer(Clock_Frequency * Tpw_r);
|
constant TAS_i : integer := integer(Clock_Frequency * Tas_r);
|
constant TPW_DELAY : std_logic_vector(TCYC_BITS-1 downto 0) :=
|
constant TAS_DELAY : std_logic_vector(TCYC_BITS - 1 downto 0) :=
|
conv_std_logic_vector(TPW_i-1, TCYC_BITS);
|
conv_std_logic_vector(TAS_i-1,TCYC_BITS);
|
|
|
constant TSU_i : integer := integer(Clock_Frequency * Tsu_r);
|
constant TPWE_i : integer := integer(Clock_Frequency * Tpwe_r);
|
constant TSU_BITS : integer := ceil_log2(TSU_i);
|
constant TPWE_DELAY : std_logic_vector(TCYC_BITS-1 downto 0) :=
|
constant TSU_DELAY : std_logic_vector(TSU_BITS - 1 downto 0) :=
|
conv_std_logic_vector(TPWE_i-1, TCYC_BITS);
|
conv_std_logic_vector(TSU_i-1,TSU_BITS);
|
|
signal tsnh_timer : std_logic_vector(TSU_BITS-1 downto 0) :=
|
|
(others => '0');
|
|
|
|
type IO_STATES is (IDLE, INIT, IO_TAS, IO_TPW, IO_TCYC, DONE );
|
type IO_STATES is (IDLE, IO_TAS, IO_TPWE, IO_TCYC );
|
signal io_state : IO_STATES;
|
signal io_state : IO_STATES;
|
|
|
signal Wr_Buffer : std_logic_vector(8 downto 0);
|
signal Wr_Buffer : std_logic_vector(8 downto 0);
|
alias Wr_Buffer_A is Wr_Buffer(8);
|
alias Wr_Buffer_A is Wr_Buffer(8);
|
alias Wr_Buffer_D is Wr_Buffer(7 downto 0);
|
alias Wr_Buffer_D is Wr_Buffer(7 downto 0);
|
Line 111... |
Line 115... |
LCD_IO_proc: process( Clock, Reset )
|
LCD_IO_proc: process( Clock, Reset )
|
begin
|
begin
|
if( Reset = Reset_Level )then
|
if( Reset = Reset_Level )then
|
io_state <= IDLE;
|
io_state <= IDLE;
|
tcyc_timer <= (others => '0');
|
tcyc_timer <= (others => '0');
|
tsnh_timer <= (others => '0');
|
|
Wr_Buffer <= (others => '0');
|
Wr_Buffer <= (others => '0');
|
IO_Done <= '0';
|
IO_Done <= '0';
|
LCD_RS <= '0';
|
LCD_RS <= '0';
|
LCD_E <= '0';
|
LCD_E <= '0';
|
LCD_DQ <= (others => '0');
|
LCD_DQ <= (others => '0');
|
elsif( rising_edge(Clock) )then
|
elsif( rising_edge(Clock) )then
|
IO_Done <= '0';
|
IO_Done <= '0';
|
|
LCD_RS <= '0';
|
LCD_E <= '0';
|
LCD_E <= '0';
|
|
LCD_DQ <= x"00";
|
|
tcyc_timer <= tcyc_timer + 1;
|
|
|
case( io_state )is
|
case( io_state )is
|
when IDLE =>
|
when IDLE =>
|
|
tcyc_timer <= (others => '0');
|
if( Wr_En = '1' )then
|
if( Wr_En = '1' )then
|
Wr_Buffer <= Wr_Reg & Wr_Data;
|
Wr_Buffer <= Wr_Reg & Wr_Data;
|
io_state <= INIT;
|
|
end if;
|
|
|
|
when INIT =>
|
|
tsnh_timer <= TSU_DELAY;
|
|
tcyc_timer <= (others => '0');
|
|
LCD_RS <= Wr_Buffer_A;
|
|
io_state <= IO_TAS;
|
io_state <= IO_TAS;
|
|
end if;
|
|
|
when IO_TAS =>
|
when IO_TAS =>
|
tsnh_timer <= tsnh_timer - 1;
|
LCD_RS <= Wr_Buffer_A;
|
if( or_reduce(tsnh_timer) = '0' )then
|
if( tcyc_timer >= TAS_DELAY )then
|
io_state <= IO_TPW;
|
io_state <= IO_TPWE;
|
end if;
|
end if;
|
|
|
when IO_TPW =>
|
when IO_TPWE =>
|
tcyc_timer <= tcyc_timer + 1;
|
LCD_RS <= Wr_Buffer_A;
|
LCD_E <= '1';
|
LCD_E <= '1';
|
LCD_DQ <= Wr_Buffer_D;
|
LCD_DQ <= Wr_Buffer_D;
|
if( tcyc_timer = TPW_DELAY )then
|
if( tcyc_timer >= TPWE_DELAY )then
|
io_state <= IO_TCYC;
|
io_state <= IO_TCYC;
|
end if;
|
end if;
|
|
|
when IO_TCYC =>
|
when IO_TCYC =>
|
tcyc_timer <= tcyc_timer + 1;
|
LCD_RS <= Wr_Buffer_A;
|
|
LCD_DQ <= Wr_Buffer_D;
|
if( tcyc_timer >= TCYC_DELAY )then
|
if( tcyc_timer >= TCYC_DELAY )then
|
io_state <= DONE;
|
|
end if;
|
|
|
|
when DONE =>
|
|
IO_Done <= '1';
|
IO_Done <= '1';
|
LCD_RS <= '0';
|
|
LCD_DQ <= (others => '0');
|
|
io_state <= IDLE;
|
io_state <= IDLE;
|
|
end if;
|
|
|
when others =>
|
when others =>
|
null;
|
null;
|
end case;
|
end case;
|
end if;
|
end if;
|