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; |