|
|||||||||||||||||||||||||||||||||||||||
This site uses Google Analytics to track visits.
Privacy Statement |
LCDsVHDL Driver for a HD44780 driven Liquid Crystal Display.
• VHDL Driver Module
• File: LCDDriver.vhdl
-- LCD Driver Module for driving HD44780 Controller -- A. Greensted, June 2007 -- Generic tickNum must be set such that: -- tickNum = 10us / Period clk -- This provides an internal tick every 10us -- Clk: 100 MHz, tickNum: 1000 -- Clk: 32 MHz, tickNum: 320 -- Clk: 10 MHz, tickNum: 100 library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity LCDDriver is generic ( tickNum : positive := 320); port ( clk : in std_logic; reset : in std_logic; dIn : in std_logic_vector(7 downto 0); charNum : in std_logic_vector(5 downto 0); wEn : in std_logic; -- LCD Interface lcdData : out std_logic_vector(7 downto 0); lcdRS : out std_logic; lcdRW : out std_logic; lcdE : out std_logic); end LCDDriver; architecture Structural of LCDDriver is -- LCD interface constants constant LCD_READ : std_logic := '1'; constant LCD_WRITE : std_logic := '0'; constant DATA_CODE : std_logic := '1'; constant INSN_CODE : std_logic := '0'; -- Tick Generation subtype TICK_COUNTER_TYPE is integer range 0 to tickNum; signal tick : std_logic; constant WARMUP_DELAY : integer := 2000; -- 2000: 20ms constant INIT_DELAY : integer := 500; -- 500: 5ms constant CHAR_DELAY : integer := 10; -- 10: 100us subtype DELAY_TYPE is integer range 0 to WARMUP_DELAY; signal timer : DELAY_TYPE; type INIT_ROM_TYPE is array (0 to 6) of std_logic_vector(7 downto 0); constant initROM : INIT_ROM_TYPE := ( b"0011_0000", -- Init b"0011_0000", -- Init b"0011_0000", -- Init b"0011_1000", -- Function Set: 8 bit, 2 lines, 5x7 characters b"0000_1100", -- Display On/Off Control: Display on, Cursor off, Blink off b"0000_0001", -- Clear Display: Move cursor to home b"0000_0110"); -- Entry Mode Set: Auto increment cursor, don't shift display type CHAR_RAM_TYPE is array(0 to 39) of std_logic_vector(7 downto 0); signal charRAM : CHAR_RAM_TYPE := ( 0=>x"41", 1=>x"6E", 2=>x"64", 3=>x"79", 4=>x"FE", 5=>x"47", 20=>x"31", 21=>x"34", 22=>x"2F", 23=>x"30", 24=>x"36", 25=>x"2F", 26=>x"30", 27=>x"37", others=>x"A0"); signal setLine : std_logic; signal lineNum : integer range 0 to 1; signal initialising : std_logic; signal initROMPointer : integer range 0 to INIT_ROM_TYPE'high; signal charRAMPointer : integer range 0 to CHAR_RAM_TYPE'high; type STATE_TYPE is (WARMUP, STAGE1, STAGE2, STAGE3, DELAY); signal state : STATE_TYPE; begin lcdRW <= LCD_WRITE; TickGen : process(clk) variable tickCounter : TICK_COUNTER_TYPE; begin if (clk'event and clk='1') then if (tickCounter = 0) then tickCounter := TICK_COUNTER_TYPE'high-1; tick <= '1'; else tickCounter := tickCounter - 1; tick <= '0'; end if; end if; end process; CharRAMWrite : process(clk) variable add : integer range 0 to 39; begin if (clk'event and clk='1') then if (wEn='1') then add := to_integer(unsigned(charNum)); charRAM(add) <= dIn; end if; end if; end process; Controller : process (clk) begin if (clk'event and clk='1') then if (reset='1') then timer <= WARMUP_DELAY; initROMPointer <= 0; charRAMPointer <= 0; lcdRS <= INSN_CODE; lcdE <= '0'; lcdData <= (others => '0'); initialising <= '1'; setLine <= '0'; lineNum <= 0; state <= WARMUP; elsif (tick='1') then case state is -- Perform initial long warmup delay when WARMUP => if (timer=0) then state <= STAGE1; else timer <= timer - 1; end if; -- Set the LCD data -- Set the LCD RS -- Initialise the timer with the required delay when STAGE1 => if (initialising='1') then timer <= INIT_DELAY; lcdRS <= INSN_CODE; lcdData <= initROM(initROMPointer); elsif (setLine='1') then timer <= CHAR_DELAY; lcdRS <= INSN_CODE; case lineNum is when 0 => lcdData <= b"1000_0000"; -- x00 when 1 => lcdData <= b"1100_0000"; -- x40 end case; else timer <= CHAR_DELAY; lcdRS <= DATA_CODE; lcdData <= charRAM(charRAMPointer); end if; state <= STAGE2; -- Set lcdE (latching RS and RW) when STAGE2 => if (initialising='1') then if (initROMPointer=INIT_ROM_TYPE'high) then initialising <= '0'; else initROMPointer <= initROMPointer + 1; end if; elsif (setLine='1') then setLine <= '0'; else if (charRAMPointer=19) then setLine <= '1'; lineNum <= 1; elsif (charRAMPointer=39) then setLine <= '1'; lineNum <= 0; end if; if (charRAMPointer=CHAR_RAM_TYPE'high) then charRAMPointer <= 0; else charRAMPointer <= charRAMPointer + 1; end if; end if; lcdE <= '1'; state <= STAGE3; -- Clear lcdE (latching data) when STAGE3 => lcdE <= '0'; state <= DELAY; -- Provide delay to allow instruciton to execute when DELAY => if (timer=0) then state <= STAGE1; else timer <= timer - 1; end if; end case; end if; end if; end process; end Structural;
• Modelsim TestBench
• File: LCDDriver_TB.vhdl
library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.ALL; use ieee.std_logic_unsigned.ALL; entity LCDDriver_TB is end LCDDriver_TB; architecture TestBench of LCDDriver_TB is component LCDDriver generic ( tickNum : positive := 320); port ( clk : in std_logic; reset : in std_logic; dIn : in std_logic_vector(7 downto 0); charNum : in std_logic_vector(5 downto 0); wEn : in std_logic; lcdData : out std_logic_vector(7 downto 0); lcdRS : out std_logic; lcdRW : out std_logic; lcdE : out std_logic); end component; signal clk : std_logic; signal reset : std_logic; signal dIn : std_logic_vector(7 downto 0); signal charNum : std_logic_vector(5 downto 0); signal wEn : std_logic; signal lcdData : std_logic_vector(7 downto 0); signal lcdRS : std_logic; signal lcdRW : std_logic; signal lcdE : std_logic; begin MainClk : process begin clk <= '1'; wait for 15.625 ns; -- 32 MHz clk <= '0'; wait for 15.625 ns; end process; Driver : LCDDriver generic map(tickNum => 320) port map( clk => clk, reset => reset, dIn => dIn, charNum => charNum, wEn => wEn, lcdData => lcdData, lcdRS => lcdRS, lcdRW => lcdRW, lcdE => lcdE); TB : process begin reset <= '1'; dIn <= (others => '0'); charNum <= (others => '0'); wEn <= '0'; wait until (clk'event and clk='1'); wait until (clk'event and clk='1'); reset <= '0'; wait; end process; end TestBench; • File: LCDDriver_TB.do
vlib work vcom -93 -pedanticerrors -lint +acc=v LCDDriver.vhdl vcom -93 LCDDriver_TB.vhdl vsim -t 1ps -lib work LCDDriver_TB configure wave -gridperiod 5000 configure wave -griddelta 10 configure wave -signalnamewidth 1 view wave -undock add wave -height 20 -color orange clk add wave -height 20 -color gold reset add wave -divider "Tick" add wave -height 20 -color yellow Driver/tick add wave -height 20 -color yellow -unsigned Driver/TickGen/tickCounter add wave -divider "Init ROM" add wave -height 20 -color coral Driver/initROMPointer add wave -divider "Char RAM" add wave -height 20 -color coral Driver/charRAMPointer add wave -divider "Delay Timer" add wave -height 20 -color coral Driver/timer add wave -divider "State Machine" add wave -height 20 -color steelBlue Driver/state add wave -height 20 -color steelBlue Driver/initialising add wave -height 20 -color pink Driver/setLine add wave -height 20 -color salmon -unsigned Driver/lineNum add wave -divider "LCD Interface" add wave -height 20 -color cornflowerBlue lcdRW add wave -height 20 -color cornflowerBlue lcdRS add wave -height 20 -color cornflowerBlue lcdE add wave -height 20 -color cornflowerBlue -hex lcdData run 100 ms
• LCD Information
|
||||||||||||||||||||||||||||||||||||||