You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
332 lines
13 KiB
VHDL
332 lines
13 KiB
VHDL
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
library unisim;
|
|
use unisim.vcomponents.all;
|
|
|
|
library work;
|
|
use work.wishbone_types.all;
|
|
|
|
-- Interface for LCD/touchscreen connected to Arduino-compatible socket on Arty A7
|
|
entity lcd_touchscreen is
|
|
port (
|
|
clk : in std_ulogic;
|
|
rst : in std_ulogic;
|
|
wb_in : in wb_io_master_out;
|
|
wb_out : out wb_io_slave_out;
|
|
wb_sel : in std_ulogic;
|
|
tp : out std_ulogic;
|
|
|
|
lcd_din : in std_ulogic_vector(7 downto 0);
|
|
lcd_dout : out std_ulogic_vector(7 downto 0);
|
|
lcd_doe : out std_ulogic;
|
|
lcd_doe0 : out std_ulogic;
|
|
lcd_doe1 : out std_ulogic;
|
|
lcd_rd : out std_ulogic; -- note active low
|
|
lcd_wr : out std_ulogic; -- note active low
|
|
lcd_rs : out std_ulogic;
|
|
lcd_rsoe : out std_ulogic;
|
|
lcd_cs : out std_ulogic; -- note active low
|
|
lcd_csoe : out std_ulogic;
|
|
lcd_rst : out std_ulogic; -- note active low
|
|
|
|
-- Differential analog inputs from touchscreen
|
|
a2_p : in std_ulogic;
|
|
a2_n : in std_ulogic;
|
|
a3_p : in std_ulogic;
|
|
a3_n : in std_ulogic;
|
|
a4_p : in std_ulogic;
|
|
a4_n : in std_ulogic;
|
|
a5_p : in std_ulogic;
|
|
a5_n : in std_ulogic
|
|
);
|
|
end entity lcd_touchscreen;
|
|
|
|
architecture rtl of lcd_touchscreen is
|
|
|
|
type state_t is (idle, prep1, prep2, writing, wr_pause, reading, rd_recovery,
|
|
drp_lo, drp_hi);
|
|
|
|
signal state : state_t;
|
|
signal delay : unsigned(5 downto 0);
|
|
signal ack : std_ulogic;
|
|
signal idle1 : std_ulogic;
|
|
signal idle2 : std_ulogic;
|
|
|
|
signal rs : std_ulogic;
|
|
signal rsoe : std_ulogic;
|
|
signal cs : std_ulogic;
|
|
signal csoe : std_ulogic;
|
|
signal d0 : std_ulogic;
|
|
signal doe0 : std_ulogic;
|
|
signal doe1 : std_ulogic;
|
|
signal d1 : std_ulogic;
|
|
signal tsctrl : std_ulogic;
|
|
|
|
signal wr_data : std_ulogic_vector(31 downto 0);
|
|
signal rd_data : std_ulogic_vector(31 downto 0);
|
|
signal wr_sel : std_ulogic_vector(3 downto 0);
|
|
signal req_wr : std_ulogic;
|
|
|
|
signal xadc_di : std_ulogic_vector(15 downto 0);
|
|
signal xadc_do : std_ulogic_vector(15 downto 0);
|
|
signal xadc_addr : std_ulogic_vector(6 downto 0);
|
|
signal xadc_en : std_ulogic;
|
|
signal xadc_we : std_ulogic;
|
|
signal xadc_rdy : std_ulogic;
|
|
signal xadc_eoc : std_ulogic;
|
|
signal xadc_eos : std_ulogic;
|
|
signal xadc_busy : std_ulogic;
|
|
signal eoc_stat : std_ulogic;
|
|
signal eos_stat : std_ulogic;
|
|
|
|
-- Assume touchscreen is connected to the A2 - A5 analog inputs
|
|
|
|
begin
|
|
|
|
-- The connection of the analog A0 - A5 pins on the Arty
|
|
-- to FPGA pins is as follows:
|
|
-- A0 connects to AD4P/AD4N
|
|
-- A1 connects to AD5P/AD5N
|
|
-- A2 connects to AD6P/AD6N
|
|
-- A3 connects to AD7P/AD7N
|
|
-- A4 connects to AD15P/AD15N
|
|
-- A5 connects to AD0P/AD0N
|
|
xadc_0 : XADC
|
|
generic map (
|
|
init_42 => x"0400" -- adcclk = dclk / 4, i.e. 25MHz
|
|
)
|
|
port map (
|
|
di => xadc_di,
|
|
do => xadc_do,
|
|
daddr => xadc_addr,
|
|
den => xadc_en,
|
|
dwe => xadc_we,
|
|
dclk => clk,
|
|
drdy => xadc_rdy,
|
|
reset => rst,
|
|
convst => '0',
|
|
convstclk => '0',
|
|
vp => '0',
|
|
vn => '0',
|
|
vauxp => a4_p & "0000000" & a3_p & a2_p & "00000" & a5_p,
|
|
vauxn => a4_n & "0000000" & a3_n & a2_n & "00000" & a5_n,
|
|
eoc => xadc_eoc,
|
|
eos => xadc_eos,
|
|
busy => xadc_busy
|
|
);
|
|
|
|
-- for now; should make sure it is at least 10us wide
|
|
lcd_rst <= not rst;
|
|
|
|
wb_out.dat <= rd_data;
|
|
wb_out.ack <= ack;
|
|
wb_out.stall <= '0' when state = idle else '1';
|
|
|
|
lcd_doe0 <= doe0;
|
|
lcd_doe1 <= doe1;
|
|
lcd_rs <= rs;
|
|
lcd_rsoe <= rsoe;
|
|
lcd_cs <= cs;
|
|
lcd_csoe <= csoe;
|
|
|
|
tp <= tsctrl;
|
|
|
|
process (clk)
|
|
variable rdat : std_ulogic_vector(7 downto 0);
|
|
begin
|
|
if rising_edge(clk) then
|
|
ack <= '0';
|
|
xadc_en <= '0';
|
|
idle2 <= idle1;
|
|
if xadc_eoc = '1' then
|
|
eoc_stat <= '1';
|
|
end if;
|
|
if xadc_eos = '1' then
|
|
eos_stat <= '1';
|
|
end if;
|
|
if rst = '1' then
|
|
state <= idle;
|
|
delay <= to_unsigned(0, 6);
|
|
rd_data <= (others => '0');
|
|
lcd_rd <= '1';
|
|
lcd_wr <= '1';
|
|
cs <= '1';
|
|
csoe <= '1';
|
|
rs <= '0';
|
|
rsoe <= '1';
|
|
lcd_doe <= '0';
|
|
doe0 <= '0';
|
|
doe1 <= '0';
|
|
d0 <= '0';
|
|
d1 <= '0';
|
|
idle1 <= '0';
|
|
idle2 <= '0';
|
|
tsctrl <= '0';
|
|
xadc_en <= '0';
|
|
eoc_stat <= '0';
|
|
eos_stat <= '0';
|
|
elsif delay /= "000000" then
|
|
delay <= delay - 1;
|
|
else
|
|
case state is
|
|
when idle =>
|
|
req_wr <= wb_in.we;
|
|
wr_data <= wb_in.dat;
|
|
wr_sel <= wb_in.sel;
|
|
if idle2 = '1' then
|
|
-- delay this one cycle after entering idle
|
|
lcd_doe <= '0';
|
|
doe0 <= '0';
|
|
doe1 <= '0';
|
|
end if;
|
|
idle1 <= '0';
|
|
if wb_in.cyc = '1' and wb_in.stb = '1' and wb_sel = '1' then
|
|
if wb_in.sel = "0000" then
|
|
ack <= '1';
|
|
elsif wb_in.adr(6) = '0' then
|
|
if wb_in.we = '1' or wb_in.adr(2) = '1' then
|
|
ack <= '1';
|
|
end if;
|
|
if wb_in.adr(2) = '0' then
|
|
-- c8050000 or 8, access LCD controller chip
|
|
tsctrl <= '0';
|
|
csoe <= '1';
|
|
cs <= '0'; -- active low
|
|
rsoe <= '1';
|
|
rs <= wb_in.adr(1);
|
|
doe0 <= '0';
|
|
doe1 <= '0';
|
|
state <= prep1;
|
|
elsif wb_in.adr(1) = '0' then
|
|
-- c8050010, touchscreen drive register
|
|
tsctrl <= '1';
|
|
idle2 <= '0';
|
|
rdat := rsoe & rs & doe0 & d0 & doe1 & d1 & csoe & cs;
|
|
rd_data <= rdat & rdat & rdat & rdat;
|
|
if wb_in.we = '1' and wb_in.sel(0) = '1' then
|
|
rsoe <= wb_in.dat(7);
|
|
rs <= wb_in.dat(6);
|
|
doe0 <= wb_in.dat(5);
|
|
d0 <= wb_in.dat(4);
|
|
lcd_dout(0) <= wb_in.dat(4);
|
|
doe1 <= wb_in.dat(3);
|
|
d1 <= wb_in.dat(2);
|
|
lcd_dout(1) <= wb_in.dat(2);
|
|
csoe <= wb_in.dat(1);
|
|
cs <= wb_in.dat(0);
|
|
end if;
|
|
else
|
|
-- c8050018, touchscreen status register
|
|
rdat := 4x"0" & xadc_busy & eoc_stat & eos_stat & tsctrl;
|
|
rd_data <= rdat & rdat & rdat & rdat;
|
|
if wb_in.we = '1' and wb_in.sel(0) = '1' then
|
|
-- for eoc_stat and eos_state, write 0 to clear
|
|
if wb_in.dat(2) = '0' then
|
|
eoc_stat <= '0';
|
|
end if;
|
|
if wb_in.dat(1) = '0' then
|
|
eos_stat <= '0';
|
|
end if;
|
|
end if;
|
|
end if;
|
|
else
|
|
-- c80501xx, access to the XADC DRP port
|
|
xadc_en <= '1';
|
|
xadc_we <= wb_in.we;
|
|
xadc_addr(6 downto 1) <= wb_in.adr(5 downto 0);
|
|
if wb_in.sel(1 downto 0) = "00" then
|
|
xadc_di <= wb_in.dat(31 downto 16);
|
|
xadc_addr(0) <= '1';
|
|
state <= drp_hi;
|
|
else
|
|
xadc_di <= wb_in.dat(15 downto 0);
|
|
xadc_addr(0) <= '0';
|
|
state <= drp_lo;
|
|
end if;
|
|
end if;
|
|
else
|
|
if tsctrl = '0' then
|
|
cs <= '1';
|
|
end if;
|
|
end if;
|
|
when prep1 =>
|
|
lcd_doe <= req_wr;
|
|
doe0 <= req_wr;
|
|
doe1 <= req_wr;
|
|
if req_wr = '1' then
|
|
if wr_sel(1 downto 0) /= "00" then
|
|
if wr_sel(1) = '1' then
|
|
lcd_dout <= wr_data(15 downto 8);
|
|
wr_sel(1) <= '0';
|
|
else
|
|
lcd_dout <= wr_data(7 downto 0);
|
|
wr_sel(0) <= '0';
|
|
end if;
|
|
else
|
|
if wr_sel(3) = '1' then
|
|
lcd_dout <= wr_data(31 downto 24);
|
|
wr_sel(3) <= '0';
|
|
else
|
|
lcd_dout <= wr_data(23 downto 16);
|
|
wr_sel(2) <= '0';
|
|
end if;
|
|
end if;
|
|
end if;
|
|
state <= prep2;
|
|
when prep2 =>
|
|
if req_wr = '1' then
|
|
lcd_wr <= '0'; -- active low
|
|
state <= writing;
|
|
delay <= to_unsigned(1, 6);
|
|
else
|
|
lcd_rd <= '0';
|
|
state <= reading;
|
|
delay <= to_unsigned(35, 6);
|
|
end if;
|
|
when writing =>
|
|
-- last cycle of writing state
|
|
lcd_wr <= '1';
|
|
if wr_sel = "0000" then
|
|
state <= idle;
|
|
idle1 <= '1';
|
|
else
|
|
state <= wr_pause;
|
|
end if;
|
|
when wr_pause =>
|
|
state <= prep1;
|
|
when reading =>
|
|
-- last cycle of reading state
|
|
lcd_rd <= '1';
|
|
rd_data <= lcd_din & lcd_din & lcd_din & lcd_din;
|
|
ack <= '1';
|
|
state <= rd_recovery;
|
|
delay <= to_unsigned(6, 6);
|
|
when rd_recovery =>
|
|
state <= idle;
|
|
when drp_lo =>
|
|
if xadc_rdy = '1' then
|
|
rd_data(15 downto 0) <= xadc_do;
|
|
if wr_sel(3 downto 2) = "00" then
|
|
ack <= '1';
|
|
state <= idle;
|
|
else
|
|
xadc_di <= wr_data(31 downto 16);
|
|
xadc_addr(0) <= '1';
|
|
state <= drp_hi;
|
|
end if;
|
|
end if;
|
|
when drp_hi =>
|
|
if xadc_rdy = '1' then
|
|
rd_data(31 downto 16) <= xadc_do;
|
|
ack <= '1';
|
|
state <= idle;
|
|
end if;
|
|
end case;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
end architecture;
|