188 lines
5.4 KiB
VHDL
188 lines
5.4 KiB
VHDL
-- altera vhdl_input_version vhdl_2008
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
use ieee.math_real.all;
|
|
|
|
entity LCDDriver is
|
|
generic (
|
|
F_CLK : natural -- Board frequency in Hz
|
|
);
|
|
port (
|
|
clk : in std_logic;
|
|
rst_n : in std_logic;
|
|
|
|
data_in : in std_logic_vector(15 downto 0);
|
|
empty_in : in std_logic;
|
|
refresh_in : in std_logic;
|
|
|
|
cmd_en_in : in std_logic;
|
|
cmd_dcx_in : in std_logic;
|
|
cmd_data_in : in std_logic_vector(7 downto 0);
|
|
|
|
data_out : out std_logic_vector(15 downto 0);
|
|
rd_n : out std_logic;
|
|
wr_n : out std_logic;
|
|
rs : out std_logic;
|
|
cs_n : out std_logic;
|
|
|
|
lcd_rdreq : out std_logic;
|
|
|
|
busy : out std_logic
|
|
);
|
|
end LCDDriver;
|
|
|
|
architecture Behavioral of LCDDriver is
|
|
|
|
constant F_LCD : natural := natural(real(25)*10**(6.0));
|
|
constant F_LCD_MIN : natural := natural(real(12.5)*10**(6.0));
|
|
constant F_LCD_MAX : natural := natural(real(30)*10**(6.0));
|
|
|
|
constant lcd_clk_en : std_logic := '1' ;
|
|
signal lcd_clk : std_logic;
|
|
|
|
type GState is (tx, cmd, ready, std_wait,cmd_wait);
|
|
type SNDState is (init, wrx, tx, done);
|
|
|
|
signal snds_reg, snds_next : SNDState;
|
|
signal gs_reg, gs_next : GState;
|
|
|
|
signal data_reg : std_logic_vector(15 downto 0);
|
|
|
|
signal cmd_dcx_reg : std_logic := '1';
|
|
signal cmd_data_reg : std_logic_vector(7 downto 0);
|
|
|
|
signal rdreq_limiter : std_logic;
|
|
|
|
begin
|
|
|
|
busy <= '0' when gs_reg = ready else '1';
|
|
|
|
--Global State Process
|
|
process (all) begin
|
|
gs_next <= gs_reg;
|
|
snds_next <= snds_reg;
|
|
|
|
case gs_reg is
|
|
when ready =>
|
|
if cmd_en_in = '1' then
|
|
if lcd_clk = '1' then
|
|
gs_next <= cmd;
|
|
snds_next <= wrx;
|
|
else
|
|
gs_next <= cmd_wait;
|
|
end if;
|
|
elsif refresh_in = '1' then
|
|
gs_next <= std_wait;
|
|
end if;
|
|
when cmd_wait =>
|
|
if lcd_clk = '1' then
|
|
gs_next <= cmd;
|
|
snds_next <= wrx;
|
|
end if;
|
|
when std_wait =>
|
|
if empty_in = '0' then
|
|
if lcd_clk = '1' then
|
|
gs_next <= tx;
|
|
snds_next <= init;
|
|
end if;
|
|
end if;
|
|
when tx =>
|
|
if snds_reg = done then
|
|
gs_next <= ready;
|
|
end if;
|
|
when cmd =>
|
|
if snds_reg = done then
|
|
gs_next <= ready;
|
|
end if;
|
|
end case;
|
|
|
|
if (gs_reg = cmd or gs_reg = tx) then
|
|
case snds_reg is
|
|
when wrx =>
|
|
snds_next <= tx;
|
|
when tx =>
|
|
if gs_reg = cmd then
|
|
snds_next <= done;
|
|
elsif gs_reg = tx then
|
|
if empty_in = '1' then
|
|
snds_next <= done;
|
|
else
|
|
snds_next <= wrx;
|
|
end if;
|
|
end if;
|
|
when init =>
|
|
snds_next <= wrx;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end if;
|
|
end process;
|
|
|
|
rs <= cmd_dcx_reg when gs_reg = cmd else '1'; -- DCX when CMD else Keep high
|
|
cs_n <= not rst_n; -- Chip Select
|
|
wr_n <= '0' when (gs_reg = cmd or gs_reg = tx) and
|
|
snds_reg = wrx else '1'; -- Write data on rising edge
|
|
rd_n <= '1'; -- Unused, Read data on rising edge
|
|
|
|
data_out <= data_reg when gs_reg = tx else
|
|
"00000000" & cmd_data_reg when gs_reg = cmd else
|
|
(others => '0');
|
|
|
|
lcd_rdreq <= '1' when (gs_reg = ready and gs_next = std_wait) or
|
|
(snds_reg /= init and snds_next = init) or
|
|
(rdreq_limiter = '0' and gs_reg = tx and snds_reg = tx) else '0';
|
|
|
|
-- Clock Sync & State Handler
|
|
process (clk, rst_n) begin
|
|
if rst_n = '0' then
|
|
gs_reg <= ready;
|
|
snds_reg <= wrx;
|
|
|
|
data_reg <= (others => '0');
|
|
|
|
cmd_dcx_reg <= '0';
|
|
cmd_data_reg <= (others => '0');
|
|
elsif rising_edge(clk) then
|
|
|
|
gs_reg <= gs_next;
|
|
if lcd_clk = '1' then
|
|
snds_reg <= snds_next; -- We run the SND at 25Mhz to respect state timings
|
|
|
|
if (snds_reg = tx or snds_reg = init) then
|
|
data_reg <= data_in;
|
|
end if;
|
|
if (snds_reg = wrx) then
|
|
rdreq_limiter <= '0';
|
|
end if;
|
|
end if;
|
|
|
|
if lcd_rdreq = '1' then
|
|
rdreq_limiter <= '1';
|
|
end if;
|
|
|
|
if gs_reg = ready and (cmd_en_in = '1') then
|
|
cmd_dcx_reg <= cmd_dcx_in;
|
|
cmd_data_reg <= cmd_data_in;
|
|
end if;
|
|
|
|
end if;
|
|
end process;
|
|
|
|
-- WS output clock
|
|
clkgen_ent : entity work.ClkGen
|
|
generic map (
|
|
F_CLK => F_CLK,
|
|
F_OUT => integer(F_LCD),
|
|
F_MIN => integer(F_LCD_MIN),
|
|
F_MAX => integer(F_LCD_MAX)
|
|
)
|
|
port map (
|
|
clk => clk,
|
|
rst_n => rst_n,
|
|
clk_o => lcd_clk,
|
|
en => lcd_clk_en
|
|
);
|
|
|
|
|
|
end Behavioral; |