diff --git a/lcd_driver.vhd b/lcd_driver.vhd
index 9c364fc..8f15248 100644
--- a/lcd_driver.vhd
+++ b/lcd_driver.vhd
@@ -1,14 +1,27 @@
----------------------------------------------------------------------------------
--- Company:
--- Engineer:
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+----------------------------------------------------------------------------------
+-- Company: Berner Fachhochschule
+-- Engineer: Aaron Schmocker
--
--- Create Date: 19:29:54 05/09/2016
+-- Create Date: 19:29:54 05/09/2016
-- Design Name:
-- Module Name: lcddriver - Behavioral
-- Project Name: yasg
--- Target Devices:
+-- Target Devices: Spartan-3am Board
-- Tool versions:
--- Description:
+-- Description: This file is part of the yasg project
--
-- Dependencies:
--
@@ -17,8 +30,9 @@
-- Additional Comments:
--
----------------------------------------------------------------------------------
-library IEEE;
-use IEEE.STD_LOGIC_1164.ALL;
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
@@ -30,7 +44,13 @@ use IEEE.STD_LOGIC_1164.ALL;
--use UNISIM.VComponents.all;
entity lcd_driver is
- Port ( clk : in STD_LOGIC; -- Systemclock (~50MHz)
+ generic ( clk_freq : natural := 50000000; -- frequency of clk (50MHz) in hz
+ wait_40000us : natural := 40000; -- wait 40ms
+ wait_37us : natural := 37; -- wait 37us
+ wait_1520us : natural := 1520); -- wait 1.52ms
+
+ Port ( clk : in STD_LOGIC; -- Systemclock (50MHz)
+ reset : in STD_LOGIC; -- Initialize display controller
data : in STD_LOGIC_VECTOR (7 downto 0); -- either one ascii char (8bit) or new cursor position (0-31)
new_character : in STD_LOGIC; -- a new character is available on the data bus
new_pos : in STD_LOGIC; -- a new cursor position is available on the data bus
@@ -43,8 +63,198 @@ end lcd_driver;
architecture Behavioral of lcd_driver is
+ -- type definitions
+ type display_state is (
+ INIT, -- initialization, wait for 40ms to pass
+ SEND_FS, -- send the function set
+ SEND_SD, -- send the display ON/OFF control
+ SEND_CD, -- send a clear
+ SEND_ES, -- send entry mode set
+ SEND_SA, -- send the starting address
+ PAUSE, -- wait for 1.52ms
+ COUNT, -- wait and toggle lcd_en
+ DONE); -- initialization done
+
+ -- signals
+ signal init_done : STD_LOGIC := '0'; -- 1 when initialization done, else 0
+
+ signal cur_state : display_state := INIT; -- cur_state register
+ signal next_state : display_state := INIT; -- next_state register
+ signal ret_state : display_state := INIT; -- ret_state register
+ signal next_ret_state : display_state := INIT; -- next_ret_state register
+
+ signal cur_counter : unsigned(15 downto 0) := (others => '0'); -- 10bit counter signal
+ signal next_counter : unsigned(15 downto 0) := (others => '0');
+ signal ret_counter : unsigned(15 downto 0) := (others => '0'); -- 10bit counter signal
+ signal next_ret_counter : unsigned(15 downto 0) := (others => '0');
+
+ signal next_lcd_db : STD_LOGIC_VECTOR(7 downto 0) := (others => '0'); -- next lcd databus
+ signal next_lcd_en : STD_LOGIC := '0'; -- next lcd enable
+ signal next_lcd_rw : STD_LOGIC := '0'; -- next lcd read/write
+ signal next_lcd_rs : STD_LOGIC := '0'; -- next lcd register select
+
+ signal cur_lcd_db : STD_LOGIC_VECTOR(7 downto 0) := (others => '0'); -- next lcd databus
+ signal cur_lcd_en : STD_LOGIC := '0'; -- next lcd enable
+ signal cur_lcd_rw : STD_LOGIC := '0'; -- next lcd read/write
+ signal cur_lcd_rs : STD_LOGIC := '0'; -- next lcd register select
+
+ -- constants
+ constant INIT_COUNT : natural := clk_freq / (1000000 / wait_40000us); -- number of clock cycles for 40us
+ constant PAUSE_COUNT : natural := clk_freq / (1000000 / wait_37us); -- number of clock cycles for 37us
+ constant CLEAR_DISPLAY_COUNT : natural := clk_freq / (1000000 / wait_1520us); -- number of clock cycles for 1.52ms
+
begin
+ -- purpose : state register
+ -- type : sequential
+ -- inputs : clk, reset, next_state
+ -- outputs : cur_state
+ REGS: process (clk, reset) is
+ begin
+ if(reset = '1') then -- asynchronous reset
+ cur_state <= INIT;
+ ret_state <= INIT;
+ cur_counter <= (others => '0');
+ ret_counter <= (others => '0');
+ cur_lcd_db <= (others => '0');
+ cur_lcd_en <= '0';
+ cur_lcd_rw <= '0';
+ cur_lcd_rs <= '0';
+ elsif rising_edge(clk) then -- synchronous on clk
+ cur_state <= next_state;
+ ret_state <= next_ret_state;
+ cur_counter <= next_counter;
+ ret_counter <= next_ret_counter;
+ cur_lcd_db <= next_lcd_db;
+ cur_lcd_en <= next_lcd_en;
+ cur_lcd_rw <= next_lcd_rw;
+ cur_lcd_rs <= next_lcd_rs;
+ end if;
+ end process REGS;
+
+ -- purpose : Finite state machine next state logic
+ -- type : sequential
+ -- inputs : clk, cur_state
+ -- outputs : none
+ NSL: process(clk, cur_state, cur_counter, cur_lcd_db, cur_lcd_en, cur_lcd_rw, cur_lcd_rs, ret_state, ret_counter) is
+ begin
+
+ next_state <= cur_state; -- state stays the same
+ next_counter <= cur_counter + 1; -- increment counter
+ next_lcd_db <= cur_lcd_db;
+ next_lcd_en <= cur_lcd_en;
+ next_lcd_rw <= cur_lcd_rw;
+ next_lcd_rs <= cur_lcd_rs;
+ next_ret_state <= ret_state;
+ next_ret_counter <= ret_counter;
+
+ case cur_state is -- switch on current state
+ when INIT =>
+
+ next_lcd_db <= "00000000";
+ next_lcd_en <= '0';
+ next_lcd_rw <= '0';
+ next_lcd_rs <= '1';
+
+ next_counter <= (others => '0');
+ next_ret_state <= SEND_FS;
+ next_ret_counter <= to_unsigned(INIT_COUNT,16);
+ next_state <= COUNT;
+
+ when SEND_FS =>
+
+ next_lcd_db <= "00110000";
+ next_lcd_en <= '0';
+ next_lcd_rw <= '0';
+ next_lcd_rs <= '0';
+
+ next_counter <= (others => '0');
+ next_ret_state <= SEND_SD;
+ next_ret_counter <= to_unsigned(PAUSE_COUNT,16);
+ next_state <= COUNT;
+
+ when SEND_SD =>
+
+ next_lcd_db <= "00001111";
+ next_lcd_en <= '0';
+ next_lcd_rw <= '0';
+ next_lcd_rs <= '0';
+
+ next_counter <= (others => '0');
+ next_ret_state <= SEND_CD;
+ next_ret_counter <= to_unsigned(PAUSE_COUNT,16);
+ next_state <= COUNT;
+
+ when SEND_CD =>
+
+ next_lcd_db <= "00000001";
+ next_lcd_en <= '0';
+ next_lcd_rw <= '0';
+ next_lcd_rs <= '0';
+
+ next_counter <= (others => '0');
+ next_ret_state <= PAUSE;
+ next_ret_counter <= to_unsigned(PAUSE_COUNT,16);
+ next_state <= COUNT;
+
+ when PAUSE =>
+
+ next_lcd_db <= "00000000";
+ next_lcd_en <= '0';
+ next_lcd_rw <= '0';
+ next_lcd_rs <= '1';
+
+ next_counter <= (others => '0');
+ next_ret_state <= SEND_ES;
+ next_ret_counter <= to_unsigned(CLEAR_DISPLAY_COUNT,16);
+ next_state <= COUNT;
+
+ when SEND_ES =>
+
+ next_lcd_db <= "00000110";
+ next_lcd_en <= '0';
+ next_lcd_rw <= '0';
+ next_lcd_rs <= '0';
+
+ next_counter <= (others => '0');
+ next_ret_state <= SEND_SA;
+ next_ret_counter <= to_unsigned(PAUSE_COUNT,16);
+ next_state <= COUNT;
+
+ when SEND_SA =>
+
+ next_lcd_db <= "10000000";
+ next_lcd_en <= '0';
+ next_lcd_rw <= '0';
+ next_lcd_rs <= '0';
+
+ next_counter <= (others => '0');
+ next_ret_state <= DONE;
+ next_ret_counter <= to_unsigned(PAUSE_COUNT,16);
+ next_state <= COUNT;
+
+ when COUNT =>
+ if(cur_counter >= ret_counter) then
+ next_state <= ret_state;
+ end if;
+
+ when DONE =>
+
+ next_lcd_db <= "10000000";
+ next_lcd_en <= '0';
+ next_lcd_rw <= '0';
+ next_lcd_rs <= '0';
+ init_done <= '1';
+
+ when others => null; -- do nothing, if we are in a different state
+ end case;
+ end process NSL;
+
+ -- Output logic
+ lcd_db <= cur_lcd_db;
+ lcd_en <= cur_lcd_en;
+ lcd_rw <= cur_lcd_rw;
+ lcd_rs <= cur_lcd_rs;
end Behavioral;
diff --git a/lcd_driver_tb.vhd b/lcd_driver_tb.vhd
new file mode 100644
index 0000000..db6d29e
--- /dev/null
+++ b/lcd_driver_tb.vhd
@@ -0,0 +1,120 @@
+--------------------------------------------------------------------------------
+-- Company:
+-- Engineer:
+--
+-- Create Date: 21:11:41 05/16/2016
+-- Design Name:
+-- Module Name: /home/aaron/Dokumente/STUDIUM/SEM6/EloSys/EloSysDigital/Projekt/vhdl-yasg/lcd_driver_tb.vhd
+-- Project Name: yasg
+-- Target Device:
+-- Tool versions:
+-- Description:
+--
+-- VHDL Test Bench Created by ISE for module: lcd_driver
+--
+-- Dependencies:
+--
+-- Revision:
+-- Revision 0.01 - File Created
+-- Additional Comments:
+--
+-- Notes:
+-- This testbench has been automatically generated using types std_logic and
+-- std_logic_vector for the ports of the unit under test. Xilinx recommends
+-- that these types always be used for the top-level I/O of a design in order
+-- to guarantee that the testbench will bind correctly to the post-implementation
+-- simulation model.
+--------------------------------------------------------------------------------
+LIBRARY ieee;
+USE ieee.std_logic_1164.ALL;
+
+-- Uncomment the following library declaration if using
+-- arithmetic functions with Signed or Unsigned values
+--USE ieee.numeric_std.ALL;
+
+ENTITY lcd_driver_tb IS
+END lcd_driver_tb;
+
+ARCHITECTURE behavior OF lcd_driver_tb IS
+
+ -- Component Declaration for the Unit Under Test (UUT)
+
+ COMPONENT lcd_driver
+ PORT(
+ clk : IN std_logic;
+ reset : IN std_logic;
+ data : IN std_logic_vector(7 downto 0);
+ new_character : IN std_logic;
+ new_pos : IN std_logic;
+ auto_incr_cursor : IN std_logic;
+ lcd_db : OUT std_logic_vector(7 downto 0);
+ lcd_en : OUT std_logic;
+ lcd_rw : OUT std_logic;
+ lcd_rs : OUT std_logic
+ );
+ END COMPONENT;
+
+
+ --Inputs
+ signal clk : std_logic := '0';
+ signal reset : std_logic := '0';
+ signal data : std_logic_vector(7 downto 0) := (others => '0');
+ signal new_character : std_logic := '0';
+ signal new_pos : std_logic := '0';
+ signal auto_incr_cursor : std_logic := '0';
+
+ --Outputs
+ signal lcd_db : std_logic_vector(7 downto 0);
+ signal lcd_en : std_logic;
+ signal lcd_rw : std_logic;
+ signal lcd_rs : std_logic;
+
+ -- Clock period definitions
+ constant clk_period : time := 20 ns; -- 50MHz
+
+BEGIN
+
+ -- Instantiate the Unit Under Test (UUT)
+ uut: lcd_driver PORT MAP (
+ clk => clk,
+ reset => reset,
+ data => data,
+ new_character => new_character,
+ new_pos => new_pos,
+ auto_incr_cursor => auto_incr_cursor,
+ lcd_db => lcd_db,
+ lcd_en => lcd_en,
+ lcd_rw => lcd_rw,
+ lcd_rs => lcd_rs
+ );
+
+ -- Clock process definitions
+ clk_process :process
+ begin
+ clk <= '0';
+ wait for clk_period/2;
+ clk <= '1';
+ wait for clk_period/2;
+ end process;
+
+
+ -- Stimulus process
+ stim_proc: process
+ begin
+
+ reset <= '1';
+
+ -- hold reset state for 100 ns.
+ wait for 100 ns;
+
+ reset <= '0';
+
+ wait for clk_period*10;
+
+
+ -- insert stimulus here
+
+ wait;
+ end process;
+
+END;
diff --git a/yasg.gise b/yasg.gise
index cfaaefd..6e87a5b 100644
--- a/yasg.gise
+++ b/yasg.gise
@@ -21,8 +21,135 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/yasg.xise b/yasg.xise
index 514e35c..46469d9 100644
--- a/yasg.xise
+++ b/yasg.xise
@@ -16,8 +16,14 @@
+
+
+
+
-
+
+
+
@@ -31,6 +37,8 @@
+
+
@@ -39,6 +47,7 @@
+