Da ich im Internet immer nur die Info gefunden habe ein Text LCD
Controller sei zu "komplex" und man solle doch einen Softcore verwenden
habe ich mir selber einen geschrieben.
Unterstüzt zur Zeit 16x2 im 8-Bit Modus, sollte sich aber leicht
anpassen lassen.
Braucht etwa 80 Slices, wobei 32 auf einen Schattenspeicher entfallen,
d.h. man kann in die Komponente mit vollem Systemtakt schreiben und der
Controller überträgt die Daten dann kontinuierlich an das LCD.
Getestet habe ich das ganze mit meinem Spartan3A Startet Board mit
folgendem Code, es wird einfach bis zum init gewartet und dann
kontinuierlich in die erste Zeile ein '#' Zeichen geschrieben.
1 | library IEEE;
|
2 | use IEEE.STD_LOGIC_1164.ALL;
|
3 | use IEEE.STD_LOGIC_ARITH.ALL;
|
4 | use IEEE.STD_LOGIC_UNSIGNED.ALL;
|
5 |
|
6 | entity LCD16x2TEST is
|
7 | Port ( clk_50M : in STD_LOGIC;
|
8 | LCD_DB : out STD_LOGIC_VECTOR (7 downto 0);
|
9 | LCD_E : out STD_LOGIC;
|
10 | LCD_RW : out STD_LOGIC;
|
11 | LCD_RS : out STD_LOGIC
|
12 | );
|
13 | end LCD16x2TEST;
|
14 |
|
15 | architecture Behavioral of LCD16x2TEST is
|
16 | component CHAR_LCD_CTR is
|
17 | Port ( clk_50M : in STD_LOGIC;
|
18 | LCDData : out STD_LOGIC_VECTOR (7 downto 0);
|
19 | LCD_Enable : out STD_LOGIC;
|
20 | LCD_RW : out STD_LOGIC;
|
21 | LCD_RegisterSelect : out STD_LOGIC;
|
22 | init_done : out std_logic;
|
23 | address : in std_logic_vector(4 downto 0);
|
24 | data : in std_logic_vector(7 downto 0);
|
25 | wr : in std_logic
|
26 | );
|
27 | end component;
|
28 | signal init_done : std_logic;
|
29 | signal address : std_logic_vector(4 downto 0) := (others =>'0');
|
30 | signal data : std_logic_vector(7 downto 0) := x"23";
|
31 | signal wr : std_logic := '0';
|
32 | constant end_Addr : integer := 15;
|
33 | begin
|
34 |
|
35 | TEST: process
|
36 | begin
|
37 | wait until rising_edge(clk_50m);
|
38 | if init_done = '1' then
|
39 | wr <= '1';
|
40 | if address /= end_Addr then
|
41 | address <= address + 1;
|
42 | else
|
43 | address <= (others => '0');
|
44 | end if;
|
45 | end if;
|
46 | end process;
|
47 |
|
48 | LCD16x2: CHAR_LCD_CTR
|
49 | Port map(clk_50M, LCD_DB, LCD_E, LCD_RW, LCD_RS, init_done, address, data, wr);
|
50 | end Behavioral;
|
Die UCF Constraints für das Board:
1 | NET "CLK_50M" LOC = "E12" | IOSTANDARD = LVCMOS33 | PERIOD = 20.000 ;
|
2 | OFFSET = IN 10.000 VALID 20.000 BEFORE "CLK_50M" ;
|
3 | OFFSET = OUT 20.000 AFTER "CLK_50M" ;
|
4 | ##############################################################################
|
5 | # Character Display (LCD)
|
6 | ##############################################################################
|
7 | NET "LCD_DB<0>" LOC = "Y13" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
|
8 | NET "LCD_DB<1>" LOC = "AB18" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
|
9 | NET "LCD_DB<2>" LOC = "AB17" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
|
10 | NET "LCD_DB<3>" LOC = "AB12" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
|
11 | NET "LCD_DB<4>" LOC = "AA12" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
|
12 | NET "LCD_DB<5>" LOC = "Y16" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
|
13 | NET "LCD_DB<6>" LOC = "AB16" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
|
14 | NET "LCD_DB<7>" LOC = "Y15" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
|
15 | NET "LCD_E" LOC = "AB4" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
|
16 | NET "LCD_RS" LOC = "Y14" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
|
17 | NET "LCD_RW" LOC = "W13" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
|
Verbesserungsmöglichkeiten und konstruktive Vorschläge sind gerne
Willkommen.