is41985
Newbie level 2
Hi,
for the past few days I've been playing around with a Spartan 3-AN Starter Kit Board. I'm interested in learning as much as I can, but now I'm stuck, and need a fresh pair of eyes to look over my code, and correct me where I made a mistake...
I'm trying to initialize and write something to the 2x16 LCD display that comes on the board (S6A0069), and have been following the instructions found in the board's datasheet (can't post a link to the datasheet because edaboard won't let me yet, but: chapter 5, page 43).
Below is my code. When the FPGA is configured, there is nothing on the screen, but when I simulate the design using Multisim, all changes happen in timely manner. LED's are used for debugging purposes only. This is the second design I've created, the first was done using a state machine, with the same result. I'm guessing that this might be a hardware thing (rising/falling time)? The display is working properly, tested it with the design that comes preconfigured from Xilinx.
This might not be the best way of coding, but I'm pretty new at this, so all suggestions are welcome
for the past few days I've been playing around with a Spartan 3-AN Starter Kit Board. I'm interested in learning as much as I can, but now I'm stuck, and need a fresh pair of eyes to look over my code, and correct me where I made a mistake...
I'm trying to initialize and write something to the 2x16 LCD display that comes on the board (S6A0069), and have been following the instructions found in the board's datasheet (can't post a link to the datasheet because edaboard won't let me yet, but: chapter 5, page 43).
Below is my code. When the FPGA is configured, there is nothing on the screen, but when I simulate the design using Multisim, all changes happen in timely manner. LED's are used for debugging purposes only. This is the second design I've created, the first was done using a state machine, with the same result. I'm guessing that this might be a hardware thing (rising/falling time)? The display is working properly, tested it with the design that comes preconfigured from Xilinx.
This might not be the best way of coding, but I'm pretty new at this, so all suggestions are welcome
Code:
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 13:27:19 09/03/2010
-- Design Name:
-- Module Name: lcdDriver
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity lcdDriver is
Port ( clk : in STD_LOGIC;
reset: in STD_LOGIC;
led : out STD_LOGIC_VECTOR (7 downto 0);
lcdDB : inout STD_LOGIC_VECTOR (7 downto 0);
lcdE : out STD_LOGIC;
lcdRS : out STD_LOGIC;
lcdRW : out STD_LOGIC);
end lcdDriver;
architecture RTL of lcdDriver is
signal clkPeriods: STD_LOGIC_VECTOR (31 downto 0) := X"00000000";
signal usClock: STD_LOGIC := '0';
signal delayCount: STD_LOGIC_VECTOR(31 downto 0) := X"0000_0000";
signal delayOK: STD_LOGIC := '0';
signal ledStateDisplay: STD_LOGIC_VECTOR(5 downto 0) := "000000";
type lcdCommandType is array(integer range <>) of STD_LOGIC_VECTOR(10 downto 0);
type delayListType is array(integer range <>) of STD_LOGIC_VECTOR(31 downto 0);
constant delayListInit: delayListType := ( 0 => X"000B_71B0", -- Wait for 15ms or longer (750000 clock cycles 50MHz = X"000B_71B0")
1 => X"0000_000C", -- Write for 12 clock cycles (X"0000_000C")
2 => X"0003_20C8", -- Wait for 4.1ms or longer (205000 clock cycles = X"0003_20C8")
3 => X"0000_000C", -- Write for 12 clock cycles (X"0000_000C")
4 => X"0000_1388", -- Wait for 100us or longer (5000 clock cycles = X"0000_1388")
5 => X"0000_000C", -- Write for 12 clock cycles (X"0000_000C")
6 => X"0000_07D0", -- Wait for 40us or longer (2000 clock cycles = X"0000_07D0")
7 => X"0000_000C", -- Write for 12 clock cycles (X"0000_000C")
8 => X"0000_07D0", -- Wait for 40us or longer (2000 clock cycles = X"0000_07D0")
9 => X"0000_07D0", -- Function Set delay (40us)
10 => X"0000_07D0", -- Entry Mode delay (40us)
11 => X"0000_07D0", -- Display On/Off delay (40us);
12 => X"0000_C350", -- Clear Display delay (82us - 1.64ms, 1ms chosen)
13 => X"0001_4050", -- Allow at least 1.64ms after issuing Clear Display command (82000 clock cycles = X"0001_4050")
14 => X"0000_1388", -- Return home for 40us - 1.6ms (80us = 5000 clock cycles = X"0000_1388")
15 => X"0000_07D0", -- Set DD RAM delay (40us)
16 => X"0000_07D0", -- Write Data to DD RAM delay (40us)
17 => X"0000_07D0", -- Write Data to DD RAM delay (40us)
18 => X"0000_07D0", -- Write Data to DD RAM delay (40us)
19 => X"0000_07D0", -- Write Data to DD RAM delay (40us)
20 => X"0000_07D0", -- Write Data to DD RAM delay (40us)
21 => X"0000_07D0", -- Write Data to DD RAM delay (40us)
22 => X"0000_07D0", -- Write Data to DD RAM delay (40us)
23 => X"0000_07D0", -- Write Data to DD RAM delay (40us)
24 => X"0000_07D0", -- Write Data to DD RAM delay (40us)
25 => X"0000_07D0", -- Write Data to DD RAM delay (40us)
26 => X"0000_07D0", -- Write Data to DD RAM delay (40us)
27 => X"0000_07D0", -- Write Data to DD RAM delay (40us)
28 => X"0000_07D0" -- NOP delay (something I just put there, used for the last command)
);
constant lcdCommandListInit: lcdCommandType := ( 0 => "000"&X"00", -- Wait 15ms or longer
1 => "100"&X"30", -- Write LCD_DB<7:4> = 0x3, and pulse LCD_E High for 12 clock cycles
2 => "000"&X"00", -- Wait 4.1ms or longer
3 => "100"&X"30", -- Write LCD_DB<7:4> = 0x3, and pulse LCD_E High for 12 clock cycles
4 => "000"&X"00", -- Wait 100us or longer
5 => "100"&X"30", -- Write LCD_DB<7:4> = 0x3, and pulse LCD_E High for 12 clock cycles
6 => "000"&X"00", -- Wait 40us or longer
7 => "100"&X"20", -- Write LCD_DB<7:4> = 0x3, and pulse LCD_E High for 12 clock cycles
8 => "000"&X"00", -- Wait 40us or longer
9 => "100"&X"28", -- Function Set
10 => "100"&X"06", -- Entry Mode Set
11 => "100"&X"0F", -- Display On/Off
12 => "100"&X"01", -- Clear Display
13 => "000"&X"00", -- Nothing
14 => "100"&X"02", -- Return Home (cursor)
15 => "100"&X"80", -- Set DD RAM Address, address is equal to 0
16 => "110"&X"48", -- Write Data to DD RAM (letter H)
17 => "110"&X"65", -- Write Data to DD RAM (letter e)
18 => "110"&X"6C", -- Write Data to DD RAM (letter l)
19 => "110"&X"6C", -- Write Data to DD RAM (letter l)
20 => "110"&X"6F", -- Write Data to DD RAM (letter o)
21 => "110"&X"20", -- Write Data to DD RAM (letter ' ')
22 => "110"&X"77", -- Write Data to DD RAM (letter w)
23 => "110"&X"6F", -- Write Data to DD RAM (letter o)
24 => "110"&X"72", -- Write Data to DD RAM (letter r)
25 => "110"&X"6C", -- Write Data to DD RAM (letter l)
26 => "110"&X"64", -- Write Data to DD RAM (letter d)
27 => "110"&X"21", -- Write Data to DD RAM (letter !)
28 => "000"&X"00" -- NOP operation (something I just put there, used for the last command)
);
signal commandPointer: integer range 0 to (delayListInit'HIGH + 1) := 0;
begin
led(5 downto 0) <= ledStateDisplay;
led(7) <= '1';
led(6) <= '0';
-- delay counter
process(clk)
begin
if (rising_edge(clk)) then
if (reset = '1') then
delayCount <= X"0000_0000";
else
if (delayOK = '1') then
delayCount <= X"0000_0000";
else
delayCount <= delayCount + X"0000_0001";
end if;
end if;
end if;
end process;
-- the delayOK variable should only be equal to '1' if current delayCount is equal to the desired delay
delayOK <= '1' when (delayCount >= (delayListInit(commandPointer)-1))
else '0';
-- go through all commands (incrementing the command pointer when a delay related to that command has elapsed)
process(clk, delayOK)
begin
if (rising_edge(clk)) then
if (reset = '1') then
commandPointer <= 0;
else
if (delayOK = '1') then
-- commandPointer <= nextCommand;
if (commandPointer < delayListInit'HIGH) then
commandPointer <= commandPointer + 1;
end if;
end if;
end if;
end if;
end process;
-- execute current command
lcdRS <= lcdCommandListInit(commandPointer)(9);
lcdRW <= lcdCommandListInit(commandPointer)(8);
lcdDB <= lcdCommandListInit(commandPointer)(7 downto 0);
lcdE <= lcdCommandListInit(commandPointer)(10);
ledStateDisplay <= conv_std_logic_vector(commandPointer, 6);
end RTL;