Interfacing FPGA to LCD 16x2
Problem and Solution




              Akhmad Hendriawan
              hendri@eepis-its.edu
You are free:

to Share — to copy, distribute and transmit the work

Under the following conditions:

Attribution — You must attribute the work in the manner specified by the author or
licensor (but not in any way that suggests that they endorse you or your use of the
work).

Noncommercial — You may not use this work for commercial purposes.

No Derivative Works — You may not alter, transform, or build upon this work.
Block Diagram
Pin Description
Write Timing Diagram
LCD Command
LCD initialize Procedure from Datasheet
Implement to FPGA
NET "en" LOC = P62;
NET "dataLCD<0>" LOC = P72;
NET "dataLCD<1>" LOC = P73;
NET "dataLCD<2>" LOC = P83;
NET "dataLCD<3>" LOC = P84;
NET "rs" LOC = p61;
NET "clock" LOC = P43;
NET "reset" LOC = P44;
Recommendate Data sheet
       Init LCD
Behaviour Simulation
Post Route Simulation




It shown that thereis many unknown data that differ from behaviour simulation
Post route Simulation




Unknown Condition
My testbench
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;                                     -- Instantiate the Unit Under Test (UUT)
                                                                      uut: LCDTest PORT MAP (
-- Uncomment the following library declaration if using
                                                                          dataLCD => dataLCD,
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;                                               en => en,
                                                                          rs => rs,
ENTITY LCDTestBench IS                                                    reset => reset,
END LCDTestBench;                                                         clock => clock
                                                                         );
ARCHITECTURE behavior OF LCDTestBench IS


  -- Component Declaration for the Unit Under Test (UUT)              -- Clock process definitions
                                                                      clock_process :process
  COMPONENT LCDTest                                                   begin
  PORT(                                                          clock <= '0';
     dataLCD : OUT std_logic_vector(3 downto 0);
                                                                 wait for clock_period/2;
     en : OUT std_logic;
                                                                 clock <= '1';
     rs : OUT std_logic;
     reset : IN std_logic;                                       wait for clock_period/2;
     clock : IN std_logic                                             end process;
     );
  END COMPONENT;

                                                                      -- Stimulus process
                                                                      stim_proc: process
 --Inputs
 signal reset : std_logic := '0';                                     begin
 signal clock : std_logic := '0';                                      -- hold reset state for 100 ns.
                                                                 --      wait for 100 ns;
 --Outputs
 signal dataLCD : std_logic_vector(3 downto 0);
                                                                 --      wait for clock_period*10;
 signal en : std_logic;
 signal rs : std_logic;
                                                                       -- insert stimulus here
 -- Clock period definitions
 constant clock_period : time := 83.3 ns;                        --      wait;
                                                                      wait for 500ns;
BEGIN
                                                                 reset <= '1';
                                                                      end process;
                                                                 END;
Onother approach(succeed)
●   Using 8 bit Data-line(pin) instead
    of 4 bit
●   ROM based model. Before that I
    used State machine model.
LCD Initializations
8 bit instead of 4 bit
TestBench Simulation
Test with Logic Analyzer




Testing LCD controller with logic analyzer I've got good Result
OK
VHDL
library IEEE;                                                       begin
use IEEE.STD_LOGIC_1164.ALL;                                        PSC : process(clk)
use IEEE.std_logic_unsigned.all;                                    variable prescaller : integer range 0 to 60000 := 0;
                                                                    begin
-- Uncomment the following library declaration if using             if (clk'event and clk = '1') then
-- arithmetic functions with Signed or Unsigned values              if prescaller < 60000 then
--use IEEE.NUMERIC_STD.ALL;                                         prescaller := prescaller + 1;
                                                                    else
-- Uncomment the following library declaration if instantiating     prescaller := 0;
-- any Xilinx primitives in this code.                              pscOut      <= not pscOut;
library UNISIM;                                                     end if;
use UNISIM.VComponents.all;                                         end if;
                                                                    end process PSC;
entity ROM is
Port(dataOut : out STD_LOGIC_VECTOR(7 downto 0);                    BUFG_inst : BUFG
reset : in std_logic;                                               port map(
Rs     : out STD_LOGIC;                                             O => pscClk,             -- Clock buffer output
En     : out STD_LOGIC;                                             I => pscOut              -- Clock buffer input
clk    : in STD_LOGIC);                                             );
end ROM;
                                                                    MYCNT : process(pscClk,reset)
architecture Behavioral of ROM is                                   begin
signal cntOut : integer := 0;                                       if (pscClk'event and pscClk = '1') then
signal pscOut : std_logic                := '0';                    if (reset = '0') then
signal pscClk : std_logic                := '0';                    cntOut <= 0;
elsif (cntOut /= 22) then
cntOut <= cntOut + 1;                        when 11 => --display clear
end if;                                      En<='1'; Rs <= '0'; dataOut <= "00000001";
end if;
                                             when 12 => --display clear
end process MYCNT;
                                             En<='0'; Rs <= '0'; dataOut <= "00000001";
ROM : process(pscClk, cntOut)
begin                                        when 13 => --entry mode
if (pscClk'event and pscClk = '1') then      En<='1'; Rs <= '0'; dataOut <= "00000110";
case cntOut is                               when 14 => --entry mode
when 0 => --delay
                                             En<='0'; Rs <= '0'; dataOut <= "00000110";
En<='1'; Rs <= '0'; dataOut <= "00110000";
                                             when 15 => --display on
when 1 => --function set 1
En<='1'; Rs <= '0'; dataOut <= "00110000";   En<='1'; Rs <= '0'; dataOut <= "00001110";
when 2 => --function set 1                   when 16 => --display on
En<='0'; Rs <= '0'; dataOut <= "00110000";   En<='0'; Rs <= '0'; dataOut <= "00001110";

when 3 => --function set 1
                                             when 17 => -- 'O'
En<='1'; Rs <= '0'; dataOut <= "00110000";
when 4 => --function set 1
                                             En<='1'; Rs <= '1'; dataOut <= "01001111";
En<='0'; Rs <= '0'; dataOut <= "00110000";   when 18 => -- 'O'
                                             En<='0'; Rs <= '1'; dataOut <= "01001111";
when 5 => --function set 1
En<='1'; Rs <= '0'; dataOut <= "00110000";
                                             when 19 => -- 'K'
when 6 => --function set 1
                                             En<='1'; Rs <= '1'; dataOut <= "01001011";
En<='0'; Rs <= '0'; dataOut <= "00110000";
                                             when 20 => -- 'K'
when 7 => --function set 8 bit               En<='0'; Rs <= '1'; dataOut <= "01001011";
En<='1'; Rs <= '0'; dataOut <= "00111001";
when 8 => --function set 8 bit               when others =>
En<='0'; Rs <= '0'; dataOut <= "00111001";
                                             dataOut <= "00000000";
                                             end case;
when 9 => --display off
En<='1'; Rs <= '0'; dataOut <= "00001000";   end if;
when 10 => --display off                     end process ROM;
En<='0'; Rs <= '0'; dataOut <= "00001000";
                                             end Behavioral;
elsif (cntOut /= 22) then
cntOut <= cntOut + 1;                        when 11 => --display clear
end if;                                      En<='1'; Rs <= '0'; dataOut <= "00000001";
end if;
                                             when 12 => --display clear
end process MYCNT;
                                             En<='0'; Rs <= '0'; dataOut <= "00000001";
ROM : process(pscClk, cntOut)
begin                                        when 13 => --entry mode
if (pscClk'event and pscClk = '1') then      En<='1'; Rs <= '0'; dataOut <= "00000110";
case cntOut is                               when 14 => --entry mode
when 0 => --delay
                                             En<='0'; Rs <= '0'; dataOut <= "00000110";
En<='1'; Rs <= '0'; dataOut <= "00110000";
when 1 => --function set 1
                                             when 15 => --display on
En<='1'; Rs <= '0'; dataOut <= "00110000";   En<='1'; Rs <= '0'; dataOut <= "00001110";
when 2 => --function set 1                   when 16 => --display on
En<='0'; Rs <= '0'; dataOut <= "00110000";   En<='0'; Rs <= '0'; dataOut <= "00001110";

when 3 => --function set 1
                                             when 17 => -- 'O'
En<='1'; Rs <= '0'; dataOut <= "00110000";
when 4 => --function set 1                   En<='1'; Rs <= '1'; dataOut <= "01001111";
En<='0'; Rs <= '0'; dataOut <= "00110000";   when 18 => -- 'O'
                                             En<='0'; Rs <= '1'; dataOut <= "01001111";
when 5 => --function set 1
En<='1'; Rs <= '0'; dataOut <= "00110000";
                                             when 19 => -- 'K'
when 6 => --function set 1
                                             En<='1'; Rs <= '1'; dataOut <= "01001011";
En<='0'; Rs <= '0'; dataOut <= "00110000";
                                             when 20 => -- 'K'
when 7 => --function set 8 bit               En<='0'; Rs <= '1'; dataOut <= "01001011";
En<='1'; Rs <= '0'; dataOut <= "00111001";
when 8 => --function set 8 bit
                                             when others =>
En<='0'; Rs <= '0'; dataOut <= "00111001";
                                             dataOut <= "00000000";
when 9 => --display off                      end case;
En<='1'; Rs <= '0'; dataOut <= "00001000";   end if;
when 10 => --display off                     end process ROM;
En<='0'; Rs <= '0'; dataOut <= "00001000";

                                             end Behavioral;

FPGA Tutorial - LCD Interface

  • 1.
    Interfacing FPGA toLCD 16x2 Problem and Solution Akhmad Hendriawan hendri@eepis-its.edu
  • 2.
    You are free: toShare — to copy, distribute and transmit the work Under the following conditions: Attribution — You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work). Noncommercial — You may not use this work for commercial purposes. No Derivative Works — You may not alter, transform, or build upon this work.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
    NET "en" LOC= P62; NET "dataLCD<0>" LOC = P72; NET "dataLCD<1>" LOC = P73; NET "dataLCD<2>" LOC = P83; NET "dataLCD<3>" LOC = P84; NET "rs" LOC = p61; NET "clock" LOC = P43; NET "reset" LOC = P44;
  • 10.
  • 11.
  • 12.
    Post Route Simulation Itshown that thereis many unknown data that differ from behaviour simulation
  • 13.
  • 14.
    My testbench LIBRARY ieee; USEieee.std_logic_1164.ALL; -- Instantiate the Unit Under Test (UUT) uut: LCDTest PORT MAP ( -- Uncomment the following library declaration if using dataLCD => dataLCD, -- arithmetic functions with Signed or Unsigned values --USE ieee.numeric_std.ALL; en => en, rs => rs, ENTITY LCDTestBench IS reset => reset, END LCDTestBench; clock => clock ); ARCHITECTURE behavior OF LCDTestBench IS -- Component Declaration for the Unit Under Test (UUT) -- Clock process definitions clock_process :process COMPONENT LCDTest begin PORT( clock <= '0'; dataLCD : OUT std_logic_vector(3 downto 0); wait for clock_period/2; en : OUT std_logic; clock <= '1'; rs : OUT std_logic; reset : IN std_logic; wait for clock_period/2; clock : IN std_logic end process; ); END COMPONENT; -- Stimulus process stim_proc: process --Inputs signal reset : std_logic := '0'; begin signal clock : std_logic := '0'; -- hold reset state for 100 ns. -- wait for 100 ns; --Outputs signal dataLCD : std_logic_vector(3 downto 0); -- wait for clock_period*10; signal en : std_logic; signal rs : std_logic; -- insert stimulus here -- Clock period definitions constant clock_period : time := 83.3 ns; -- wait; wait for 500ns; BEGIN reset <= '1'; end process; END;
  • 15.
    Onother approach(succeed) ● Using 8 bit Data-line(pin) instead of 4 bit ● ROM based model. Before that I used State machine model.
  • 16.
    LCD Initializations 8 bitinstead of 4 bit
  • 17.
  • 18.
    Test with LogicAnalyzer Testing LCD controller with logic analyzer I've got good Result
  • 19.
  • 20.
    VHDL library IEEE; begin use IEEE.STD_LOGIC_1164.ALL; PSC : process(clk) use IEEE.std_logic_unsigned.all; variable prescaller : integer range 0 to 60000 := 0; begin -- Uncomment the following library declaration if using if (clk'event and clk = '1') then -- arithmetic functions with Signed or Unsigned values if prescaller < 60000 then --use IEEE.NUMERIC_STD.ALL; prescaller := prescaller + 1; else -- Uncomment the following library declaration if instantiating prescaller := 0; -- any Xilinx primitives in this code. pscOut <= not pscOut; library UNISIM; end if; use UNISIM.VComponents.all; end if; end process PSC; entity ROM is Port(dataOut : out STD_LOGIC_VECTOR(7 downto 0); BUFG_inst : BUFG reset : in std_logic; port map( Rs : out STD_LOGIC; O => pscClk, -- Clock buffer output En : out STD_LOGIC; I => pscOut -- Clock buffer input clk : in STD_LOGIC); ); end ROM; MYCNT : process(pscClk,reset) architecture Behavioral of ROM is begin signal cntOut : integer := 0; if (pscClk'event and pscClk = '1') then signal pscOut : std_logic := '0'; if (reset = '0') then signal pscClk : std_logic := '0'; cntOut <= 0;
  • 21.
    elsif (cntOut /=22) then cntOut <= cntOut + 1; when 11 => --display clear end if; En<='1'; Rs <= '0'; dataOut <= "00000001"; end if; when 12 => --display clear end process MYCNT; En<='0'; Rs <= '0'; dataOut <= "00000001"; ROM : process(pscClk, cntOut) begin when 13 => --entry mode if (pscClk'event and pscClk = '1') then En<='1'; Rs <= '0'; dataOut <= "00000110"; case cntOut is when 14 => --entry mode when 0 => --delay En<='0'; Rs <= '0'; dataOut <= "00000110"; En<='1'; Rs <= '0'; dataOut <= "00110000"; when 15 => --display on when 1 => --function set 1 En<='1'; Rs <= '0'; dataOut <= "00110000"; En<='1'; Rs <= '0'; dataOut <= "00001110"; when 2 => --function set 1 when 16 => --display on En<='0'; Rs <= '0'; dataOut <= "00110000"; En<='0'; Rs <= '0'; dataOut <= "00001110"; when 3 => --function set 1 when 17 => -- 'O' En<='1'; Rs <= '0'; dataOut <= "00110000"; when 4 => --function set 1 En<='1'; Rs <= '1'; dataOut <= "01001111"; En<='0'; Rs <= '0'; dataOut <= "00110000"; when 18 => -- 'O' En<='0'; Rs <= '1'; dataOut <= "01001111"; when 5 => --function set 1 En<='1'; Rs <= '0'; dataOut <= "00110000"; when 19 => -- 'K' when 6 => --function set 1 En<='1'; Rs <= '1'; dataOut <= "01001011"; En<='0'; Rs <= '0'; dataOut <= "00110000"; when 20 => -- 'K' when 7 => --function set 8 bit En<='0'; Rs <= '1'; dataOut <= "01001011"; En<='1'; Rs <= '0'; dataOut <= "00111001"; when 8 => --function set 8 bit when others => En<='0'; Rs <= '0'; dataOut <= "00111001"; dataOut <= "00000000"; end case; when 9 => --display off En<='1'; Rs <= '0'; dataOut <= "00001000"; end if; when 10 => --display off end process ROM; En<='0'; Rs <= '0'; dataOut <= "00001000"; end Behavioral;
  • 22.
    elsif (cntOut /=22) then cntOut <= cntOut + 1; when 11 => --display clear end if; En<='1'; Rs <= '0'; dataOut <= "00000001"; end if; when 12 => --display clear end process MYCNT; En<='0'; Rs <= '0'; dataOut <= "00000001"; ROM : process(pscClk, cntOut) begin when 13 => --entry mode if (pscClk'event and pscClk = '1') then En<='1'; Rs <= '0'; dataOut <= "00000110"; case cntOut is when 14 => --entry mode when 0 => --delay En<='0'; Rs <= '0'; dataOut <= "00000110"; En<='1'; Rs <= '0'; dataOut <= "00110000"; when 1 => --function set 1 when 15 => --display on En<='1'; Rs <= '0'; dataOut <= "00110000"; En<='1'; Rs <= '0'; dataOut <= "00001110"; when 2 => --function set 1 when 16 => --display on En<='0'; Rs <= '0'; dataOut <= "00110000"; En<='0'; Rs <= '0'; dataOut <= "00001110"; when 3 => --function set 1 when 17 => -- 'O' En<='1'; Rs <= '0'; dataOut <= "00110000"; when 4 => --function set 1 En<='1'; Rs <= '1'; dataOut <= "01001111"; En<='0'; Rs <= '0'; dataOut <= "00110000"; when 18 => -- 'O' En<='0'; Rs <= '1'; dataOut <= "01001111"; when 5 => --function set 1 En<='1'; Rs <= '0'; dataOut <= "00110000"; when 19 => -- 'K' when 6 => --function set 1 En<='1'; Rs <= '1'; dataOut <= "01001011"; En<='0'; Rs <= '0'; dataOut <= "00110000"; when 20 => -- 'K' when 7 => --function set 8 bit En<='0'; Rs <= '1'; dataOut <= "01001011"; En<='1'; Rs <= '0'; dataOut <= "00111001"; when 8 => --function set 8 bit when others => En<='0'; Rs <= '0'; dataOut <= "00111001"; dataOut <= "00000000"; when 9 => --display off end case; En<='1'; Rs <= '0'; dataOut <= "00001000"; end if; when 10 => --display off end process ROM; En<='0'; Rs <= '0'; dataOut <= "00001000"; end Behavioral;