OpenCores
URL https://opencores.org/ocsvn/16x2_lcd_controller/16x2_lcd_controller/trunk

Subversion Repositories 16x2_lcd_controller

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 6 to Rev 7
    Reverse comparison

Rev 6 → Rev 7

/16x2_lcd_controller/trunk/lcd16x2_ctrl.vhd
0,0 → 1,325
-------------------------------------------------------------------------------
-- Title : 16x2 LCD controller
-- Project :
-------------------------------------------------------------------------------
-- File : lcd16x2_ctrl.vhd
-- Author : <stachelsau@T420>
-- Company :
-- Created : 2012-07-28
-- Last update: 2012-07-29
-- Platform :
-- Standard : VHDL'93/02
-------------------------------------------------------------------------------
-- Description: The controller initializes the display when rst goes to '0'.
-- After that it writes the contend of the input signals
-- line1_buffer and line2_buffer continously to the display.
-------------------------------------------------------------------------------
-- Copyright (c) 2012
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2012-07-28 1.0 stachelsau Created
-------------------------------------------------------------------------------
 
library ieee;
use ieee.std_logic_1164.all;
 
entity lcd16x2_ctrl is
generic (
CLK_PERIOD_NS : positive := 20); -- 50MHz
 
port (
clk : in std_logic;
rst : in std_logic;
lcd_e : out std_logic;
lcd_rs : out std_logic;
lcd_rw : out std_logic;
lcd_db : out std_logic_vector(7 downto 4);
line1_buffer : in std_logic_vector(127 downto 0); -- 16x8bit
line2_buffer : in std_logic_vector(127 downto 0));
 
end entity lcd16x2_ctrl;
 
architecture rtl of lcd16x2_ctrl is
 
constant DELAY_15_MS : positive := 15 * 10**6 / CLK_PERIOD_NS + 1;
constant DELAY_1640_US : positive := 1640 * 10**3 / CLK_PERIOD_NS + 1;
constant DELAY_4100_US : positive := 4100 * 10**3 / CLK_PERIOD_NS + 1;
constant DELAY_100_US : positive := 100 * 10**3 / CLK_PERIOD_NS + 1;
constant DELAY_40_US : positive := 40 * 10**3 / CLK_PERIOD_NS + 1;
 
constant DELAY_NIBBLE : positive := 10**3 / CLK_PERIOD_NS + 1;
constant DELAY_LCD_E : positive := 230 / CLK_PERIOD_NS + 1;
constant DELAY_SETUP_HOLD : positive := 40 / CLK_PERIOD_NS + 1;
 
constant MAX_DELAY : positive := DELAY_15_MS;
 
-- this record describes one write operation
type op_t is record
rs : std_logic;
data : std_logic_vector(7 downto 0);
delay_h : integer range 0 to MAX_DELAY;
delay_l : integer range 0 to MAX_DELAY;
end record op_t;
constant default : op_t := (rs => '1', data => X"00", delay_h => DELAY_NIBBLE, delay_l => DELAY_40_US);
constant op_select_line1 : op_t := (rs => '0', data => X"80", delay_h => DELAY_NIBBLE, delay_l => DELAY_40_US);
constant op_select_line2 : op_t := (rs => '0', data => X"C0", delay_h => DELAY_NIBBLE, delay_l => DELAY_40_US);
 
-- init + config operations:
-- write 3 x 0x3 followed by 0x2
-- function set command
-- entry mode set command
-- display on/off command
-- clear display
type config_ops_t is array(0 to 5) of op_t;
constant config_ops : config_ops_t
:= (5 => (rs => '0', data => X"33", delay_h => DELAY_4100_US, delay_l => DELAY_100_US),
4 => (rs => '0', data => X"32", delay_h => DELAY_40_US, delay_l => DELAY_40_US),
3 => (rs => '0', data => X"28", delay_h => DELAY_NIBBLE, delay_l => DELAY_40_US),
2 => (rs => '0', data => X"06", delay_h => DELAY_NIBBLE, delay_l => DELAY_40_US),
1 => (rs => '0', data => X"0C", delay_h => DELAY_NIBBLE, delay_l => DELAY_40_US),
0 => (rs => '0', data => X"01", delay_h => DELAY_NIBBLE, delay_l => DELAY_1640_US));
 
signal this_op : op_t;
 
type op_state_t is (IDLE,
WAIT_SETUP_H,
ENABLE_H,
WAIT_HOLD_H,
WAIT_DELAY_H,
WAIT_SETUP_L,
ENABLE_L,
WAIT_HOLD_L,
WAIT_DELAY_L,
DONE);
 
signal op_state : op_state_t := DONE;
signal next_op_state : op_state_t;
signal cnt : natural range 0 to MAX_DELAY;
signal next_cnt : natural range 0 to MAX_DELAY;
 
type state_t is (RESET,
CONFIG,
SELECT_LINE1,
WRITE_LINE1,
SELECT_LINE2,
WRITE_LINE2);
 
signal state : state_t := RESET;
signal next_state : state_t;
signal ptr : natural range 0 to 15 := 0;
signal next_ptr : natural range 0 to 15;
 
begin
 
proc_state : process(state, op_state, ptr, line1_buffer, line2_buffer) is
begin
case state is
when RESET =>
this_op <= default;
next_state <= CONFIG;
next_ptr <= config_ops_t'high;
when CONFIG =>
this_op <= config_ops(ptr);
next_ptr <= ptr;
next_state <= CONFIG;
if op_state = DONE then
next_ptr <= ptr - 1;
if ptr = 0 then
next_state <= SELECT_LINE1;
end if;
end if;
 
when SELECT_LINE1 =>
this_op <= op_select_line1;
next_ptr <= 15;
if op_state = DONE then
next_state <= WRITE_LINE1;
else
next_state <= SELECT_LINE1;
end if;
 
when WRITE_LINE1 =>
this_op <= default;
this_op.data <= line1_buffer(ptr*8 + 7 downto ptr*8);
next_ptr <= ptr;
next_state <= WRITE_LINE1;
if op_state = DONE then
next_ptr <= ptr - 1;
if ptr = 0 then
next_state <= SELECT_LINE2;
end if;
end if;
 
when SELECT_LINE2 =>
this_op <= op_select_line2;
next_ptr <= 15;
if op_state = DONE then
next_state <= WRITE_LINE2;
else
next_state <= SELECT_LINE2;
end if;
 
when WRITE_LINE2 =>
this_op <= default;
this_op.data <= line2_buffer(ptr*8 + 7 downto ptr*8);
next_ptr <= ptr;
next_state <= WRITE_LINE2;
if op_state = DONE then
next_ptr <= ptr - 1;
if ptr = 0 then
next_state <= SELECT_LINE1;
end if;
end if;
end case;
end process proc_state;
 
reg_state : process(clk)
begin
if rising_edge(clk) then
if rst = '1' then
state <= RESET;
ptr <= 0;
else
state <= next_state;
ptr <= next_ptr;
end if;
end if;
end process reg_state;
 
-- we never read from the lcd
lcd_rw <= '0';
 
proc_op_state : process(op_state, cnt, this_op) is
begin
case op_state is
when IDLE =>
lcd_db <= (others => '0');
lcd_rs <= '0';
lcd_e <= '0';
next_op_state <= WAIT_SETUP_H;
next_cnt <= DELAY_SETUP_HOLD;
when WAIT_SETUP_H =>
lcd_db <= this_op.data(7 downto 4);
lcd_rs <= this_op.rs;
lcd_e <= '0';
if cnt = 0 then
next_op_state <= ENABLE_H;
next_cnt <= DELAY_LCD_E;
else
next_op_state <= WAIT_SETUP_H;
next_cnt <= cnt - 1;
end if;
 
when ENABLE_H =>
lcd_db <= this_op.data(7 downto 4);
lcd_rs <= this_op.rs;
lcd_e <= '1';
if cnt = 0 then
next_op_state <= WAIT_HOLD_H;
next_cnt <= DELAY_SETUP_HOLD;
else
next_op_state <= ENABLE_H;
next_cnt <= cnt - 1;
end if;
 
when WAIT_HOLD_H =>
lcd_db <= this_op.data(7 downto 4);
lcd_rs <= this_op.rs;
lcd_e <= '0';
if cnt = 0 then
next_op_state <= WAIT_DELAY_H;
next_cnt <= this_op.delay_h;
else
next_op_state <= WAIT_HOLD_H;
next_cnt <= cnt - 1;
end if;
 
when WAIT_DELAY_H =>
lcd_db <= (others => '0');
lcd_rs <= '0';
lcd_e <= '0';
if cnt = 0 then
next_op_state <= WAIT_SETUP_L;
next_cnt <= DELAY_SETUP_HOLD;
else
next_op_state <= WAIT_DELAY_H;
next_cnt <= cnt - 1;
end if;
 
when WAIT_SETUP_L =>
lcd_db <= this_op.data(3 downto 0);
lcd_rs <= this_op.rs;
lcd_e <= '0';
if cnt = 0 then
next_op_state <= ENABLE_L;
next_cnt <= DELAY_LCD_E;
else
next_op_state <= WAIT_SETUP_L;
next_cnt <= cnt - 1;
end if;
 
when ENABLE_L =>
lcd_db <= this_op.data(3 downto 0);
lcd_rs <= this_op.rs;
lcd_e <= '1';
if cnt = 0 then
next_op_state <= WAIT_HOLD_L;
next_cnt <= DELAY_SETUP_HOLD;
else
next_op_state <= ENABLE_L;
next_cnt <= cnt - 1;
end if;
 
when WAIT_HOLD_L =>
lcd_db <= this_op.data(3 downto 0);
lcd_rs <= this_op.rs;
lcd_e <= '0';
if cnt = 0 then
next_op_state <= WAIT_DELAY_L;
next_cnt <= this_op.delay_l;
else
next_op_state <= WAIT_HOLD_L;
next_cnt <= cnt - 1;
end if;
 
when WAIT_DELAY_L =>
lcd_db <= (others => '0');
lcd_rs <= '0';
lcd_e <= '0';
if cnt = 0 then
next_op_state <= DONE;
next_cnt <= 0;
else
next_op_state <= WAIT_DELAY_L;
next_cnt <= cnt - 1;
end if;
 
when DONE =>
lcd_db <= (others => '0');
lcd_rs <= '0';
lcd_e <= '0';
next_op_state <= IDLE;
next_cnt <= 0;
end case;
end process proc_op_state;
 
reg_op_state : process (clk) is
begin
if rising_edge(clk) then
if state = RESET then
op_state <= IDLE;
else
op_state <= next_op_state;
cnt <= next_cnt;
end if;
end if;
end process reg_op_state;
 
end architecture rtl;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.