`timescale 1ns / 1ps
|
`timescale 1ns / 1ps
|
/*
|
/*
|
* File : lcd_ctrl.v
|
* File : lcd_ctrl.v
|
* Project : University of Utah, XUM Project MIPS32 core
|
* Project : University of Utah, XUM Project MIPS32 core
|
* Creator(s) : Grant Ayers (ayers@cs.utah.edu)
|
* Creator(s) : Grant Ayers (ayers@cs.utah.edu)
|
*
|
*
|
* Modification History:
|
* Modification History:
|
* Rev Date Initials Description of Change
|
* Rev Date Initials Description of Change
|
* 1.0 16-Jun-2011 GEA Initial design.
|
* 1.0 16-Jun-2011 GEA Initial design.
|
*
|
*
|
* Standards/Formatting:
|
* Standards/Formatting:
|
* Verilog 2001, 4 soft tab, wide column.
|
* Verilog 2001, 4 soft tab, wide column.
|
*
|
*
|
* Description:
|
* Description:
|
* A controller for the common 16x2-character LCD screen based on the
|
* A controller for the common 16x2-character LCD screen based on the
|
* Sitronix ST7066U, Samsung S6A0069X / KS0066U, Hitachi HD44780, SMOS SED1278,
|
* Sitronix ST7066U, Samsung S6A0069X / KS0066U, Hitachi HD44780, SMOS SED1278,
|
* or other compatible device. This controller uses a 4-bit data bus, is write-only,
|
* or other compatible device. This controller uses a 4-bit data bus, is write-only,
|
* and requires a total of 7 output pins to the LCD. The timing must be adjusted for
|
* and requires a total of 7 output pins to the LCD. The timing must be adjusted for
|
* different input clock frequencies where noted. The primary version is based on a
|
* different input clock frequencies where noted. The primary version is based on a
|
* 100 MHz clock.
|
* 100 MHz clock.
|
*/
|
*/
|
module lcd_ctrl(
|
module lcd_ctrl(
|
input clock,
|
input clock,
|
input reset,
|
input reset,
|
input [8:0] command,
|
input [8:0] command,
|
input write,
|
input write,
|
output reg ack,
|
output reg ack,
|
//---------------------------------
|
//---------------------------------
|
output reg [3:0] LCD_D, // 4-bit LCD data bus
|
output reg [3:0] LCD_D, // 4-bit LCD data bus
|
output reg LCD_E, // Enable
|
output reg LCD_E, // Enable
|
output LCD_RS, // Register Select (0->Register; 1->Data)
|
output LCD_RS, // Register Select (0->Register; 1->Data)
|
output LCD_RW // Read/Write (0->Write; 1->Read)
|
output LCD_RW // Read/Write (0->Write; 1->Read)
|
);
|
);
|
|
|
localparam [4:0] INIT_1=1, INIT_2=2, INIT_3=3, INIT_4=4, INIT_5=5, INIT_6=6, INIT_7=7, INIT_8=8,
|
localparam [4:0] INIT_1=1, INIT_2=2, INIT_3=3, INIT_4=4, INIT_5=5, INIT_6=6, INIT_7=7, INIT_8=8,
|
CMD_WAIT=9, NOP=10, U_SETUP=11, U_ENAB=12, U_HOLD=13, UL_WAIT=14, L_SETUP=15,
|
CMD_WAIT=9, NOP=10, U_SETUP=11, U_ENAB=12, U_HOLD=13, UL_WAIT=14, L_SETUP=15,
|
L_ENAB=16, L_HOLD=17;
|
L_ENAB=16, L_HOLD=17;
|
|
|
reg [18:0] count;
|
reg [18:0] count;
|
reg [18:0] compare;
|
reg [18:0] compare;
|
reg [4:0] state;
|
reg [4:0] state;
|
wire bell;
|
wire bell;
|
wire long_instr;
|
wire long_instr;
|
|
|
assign LCD_RW = 0; // There is no reason to read from the LCD screen.
|
assign LCD_RW = 0; // There is no reason to read from the LCD screen.
|
assign LCD_RS = command[8];
|
assign LCD_RS = command[8];
|
assign bell = (count == compare);
|
assign bell = (count == compare);
|
assign long_instr = ((command == 9'b0_0000_0001) || (command[8:1] == 8'b0_0000_001));
|
assign long_instr = ((command == 9'b0_0000_0001) || (command[8:1] == 8'b0_0000_001));
|
|
|
|
|
/* The count register increments until it equals 'compare' */
|
/* The count register increments until it equals 'compare' */
|
always @(posedge clock) begin
|
always @(posedge clock) begin
|
count <= (reset | bell) ? 19'b0 : count + 1;
|
count <= (reset | bell) ? 19'b0 : count + 1;
|
end
|
end
|
|
|
/* Time delays for various states */
|
/* Time delays for various states */
|
always @(*) begin
|
always @(*) begin
|
case (state)
|
case (state)
|
INIT_1 : compare <= 19'd410000; // 15ms (4.1ms OK due to power-up delay)
|
INIT_1 : compare <= 19'd410000; // 15ms (4.1ms OK due to power-up delay)
|
INIT_2 : compare <= 19'd24; // 240 ns
|
INIT_2 : compare <= 19'd24; // 240 ns
|
INIT_3 : compare <= 19'd410000; // 4.1 ms
|
INIT_3 : compare <= 19'd410000; // 4.1 ms
|
INIT_4 : compare <= 19'd24; // 240 ns
|
INIT_4 : compare <= 19'd24; // 240 ns
|
INIT_5 : compare <= 19'd10000; // 100 us or longer
|
INIT_5 : compare <= 19'd10000; // 100 us or longer
|
INIT_6 : compare <= 19'd24; // 240 ns
|
INIT_6 : compare <= 19'd24; // 240 ns
|
INIT_7 : compare <= 19'd4000; // 40 us or longer
|
INIT_7 : compare <= 19'd4000; // 40 us or longer
|
INIT_8 : compare <= 19'd24; // 240 ns
|
INIT_8 : compare <= 19'd24; // 240 ns
|
CMD_WAIT : compare <= (long_instr) ? 19'd164000 : 19'd4000; // 40 us or 1.64 ms
|
CMD_WAIT : compare <= (long_instr) ? 19'd164000 : 19'd4000; // 40 us or 1.64 ms
|
NOP : compare <= 19'hxxxxx;
|
NOP : compare <= 19'hxxxxx;
|
U_SETUP : compare <= 19'd4; // 40 ns
|
U_SETUP : compare <= 19'd4; // 40 ns
|
U_ENAB : compare <= 19'd23; // 230 ns
|
U_ENAB : compare <= 19'd23; // 230 ns
|
U_HOLD : compare <= 19'd1; // 10 ns
|
U_HOLD : compare <= 19'd1; // 10 ns
|
UL_WAIT : compare <= 19'd100; // 1 us
|
UL_WAIT : compare <= 19'd100; // 1 us
|
L_SETUP : compare <= 19'd4; // 40 ns
|
L_SETUP : compare <= 19'd4; // 40 ns
|
L_ENAB : compare <= 19'd23; // 230 ns
|
L_ENAB : compare <= 19'd23; // 230 ns
|
L_HOLD : compare <= 19'd1; // 10 ns
|
L_HOLD : compare <= 19'd1; // 10 ns
|
default : compare <= 19'hxxxxx;
|
default : compare <= 19'hxxxxx;
|
endcase
|
endcase
|
end
|
end
|
|
|
/* The main state machine */
|
/* The main state machine */
|
always @(posedge clock) begin
|
always @(posedge clock) begin
|
if (reset) begin
|
if (reset) begin
|
state <= INIT_1;
|
state <= INIT_1;
|
end
|
end
|
else begin
|
else begin
|
case (state)
|
case (state)
|
INIT_1 : state <= (bell) ? INIT_2 : INIT_1;
|
INIT_1 : state <= (bell) ? INIT_2 : INIT_1;
|
INIT_2 : state <= (bell) ? INIT_3 : INIT_2;
|
INIT_2 : state <= (bell) ? INIT_3 : INIT_2;
|
INIT_3 : state <= (bell) ? INIT_4 : INIT_3;
|
INIT_3 : state <= (bell) ? INIT_4 : INIT_3;
|
INIT_4 : state <= (bell) ? INIT_5 : INIT_4;
|
INIT_4 : state <= (bell) ? INIT_5 : INIT_4;
|
INIT_5 : state <= (bell) ? INIT_6 : INIT_5;
|
INIT_5 : state <= (bell) ? INIT_6 : INIT_5;
|
INIT_6 : state <= (bell) ? INIT_7 : INIT_6;
|
INIT_6 : state <= (bell) ? INIT_7 : INIT_6;
|
INIT_7 : state <= (bell) ? INIT_8 : INIT_7;
|
INIT_7 : state <= (bell) ? INIT_8 : INIT_7;
|
INIT_8 : state <= (bell) ? CMD_WAIT : INIT_8;
|
INIT_8 : state <= (bell) ? CMD_WAIT : INIT_8;
|
CMD_WAIT : state <= (bell) ? NOP : CMD_WAIT;
|
CMD_WAIT : state <= (bell) ? NOP : CMD_WAIT;
|
NOP : state <= (write & ~ack) ? U_SETUP : NOP;
|
NOP : state <= (write & ~ack) ? U_SETUP : NOP;
|
U_SETUP : state <= (bell) ? U_ENAB : U_SETUP;
|
U_SETUP : state <= (bell) ? U_ENAB : U_SETUP;
|
U_ENAB : state <= (bell) ? U_HOLD : U_ENAB;
|
U_ENAB : state <= (bell) ? U_HOLD : U_ENAB;
|
U_HOLD : state <= (bell) ? UL_WAIT : U_HOLD;
|
U_HOLD : state <= (bell) ? UL_WAIT : U_HOLD;
|
UL_WAIT : state <= (bell) ? L_SETUP : UL_WAIT;
|
UL_WAIT : state <= (bell) ? L_SETUP : UL_WAIT;
|
L_SETUP : state <= (bell) ? L_ENAB : L_SETUP;
|
L_SETUP : state <= (bell) ? L_ENAB : L_SETUP;
|
L_ENAB : state <= (bell) ? L_HOLD : L_ENAB;
|
L_ENAB : state <= (bell) ? L_HOLD : L_ENAB;
|
L_HOLD : state <= (bell) ? CMD_WAIT : L_HOLD;
|
L_HOLD : state <= (bell) ? CMD_WAIT : L_HOLD;
|
default : state <= 5'bxxxxx;
|
default : state <= 5'bxxxxx;
|
endcase
|
endcase
|
end
|
end
|
end
|
end
|
|
|
/* Combinatorial enable and data assignments */
|
/* Combinatorial enable and data assignments */
|
always @(*) begin
|
always @(*) begin
|
case (state)
|
case (state)
|
INIT_1 : begin LCD_E <= 0; LCD_D <= 4'b0000; end
|
INIT_1 : begin LCD_E <= 0; LCD_D <= 4'b0000; end
|
INIT_2 : begin LCD_E <= 0; LCD_D <= 4'b0011; end
|
INIT_2 : begin LCD_E <= 0; LCD_D <= 4'b0011; end
|
INIT_3 : begin LCD_E <= 0; LCD_D <= 4'b0000; end
|
INIT_3 : begin LCD_E <= 0; LCD_D <= 4'b0000; end
|
INIT_4 : begin LCD_E <= 1; LCD_D <= 4'b0011; end
|
INIT_4 : begin LCD_E <= 1; LCD_D <= 4'b0011; end
|
INIT_5 : begin LCD_E <= 0; LCD_D <= 4'b0000; end
|
INIT_5 : begin LCD_E <= 0; LCD_D <= 4'b0000; end
|
INIT_6 : begin LCD_E <= 1; LCD_D <= 4'b0011; end
|
INIT_6 : begin LCD_E <= 1; LCD_D <= 4'b0011; end
|
INIT_7 : begin LCD_E <= 0; LCD_D <= 4'b0000; end
|
INIT_7 : begin LCD_E <= 0; LCD_D <= 4'b0000; end
|
INIT_8 : begin LCD_E <= 1; LCD_D <= 4'b0010; end
|
INIT_8 : begin LCD_E <= 1; LCD_D <= 4'b0010; end
|
CMD_WAIT : begin LCD_E <= 0; LCD_D <= 4'b0000; end
|
CMD_WAIT : begin LCD_E <= 0; LCD_D <= 4'b0000; end
|
NOP : begin LCD_E <= 0; LCD_D <= 4'b0000; end
|
NOP : begin LCD_E <= 0; LCD_D <= 4'b0000; end
|
U_SETUP : begin LCD_E <= 0; LCD_D <= command[7:4]; end
|
U_SETUP : begin LCD_E <= 0; LCD_D <= command[7:4]; end
|
U_ENAB : begin LCD_E <= 1; LCD_D <= command[7:4]; end
|
U_ENAB : begin LCD_E <= 1; LCD_D <= command[7:4]; end
|
U_HOLD : begin LCD_E <= 0; LCD_D <= command[7:4]; end
|
U_HOLD : begin LCD_E <= 0; LCD_D <= command[7:4]; end
|
UL_WAIT : begin LCD_E <= 0; LCD_D <= 4'b0000; end
|
UL_WAIT : begin LCD_E <= 0; LCD_D <= 4'b0000; end
|
L_SETUP : begin LCD_E <= 0; LCD_D <= command[3:0]; end
|
L_SETUP : begin LCD_E <= 0; LCD_D <= command[3:0]; end
|
L_ENAB : begin LCD_E <= 1; LCD_D <= command[3:0]; end
|
L_ENAB : begin LCD_E <= 1; LCD_D <= command[3:0]; end
|
L_HOLD : begin LCD_E <= 0; LCD_D <= command[3:0]; end
|
L_HOLD : begin LCD_E <= 0; LCD_D <= command[3:0]; end
|
default : begin LCD_E <= 0; LCD_D <= 4'b0000; end
|
default : begin LCD_E <= 0; LCD_D <= 4'b0000; end
|
endcase
|
endcase
|
end
|
end
|
|
|
/* Full 4-way Handshake */
|
/* Full 4-way Handshake */
|
always @(posedge clock) begin
|
always @(posedge clock) begin
|
ack <= (reset | ~write) ? 0 : (((state == L_HOLD) && (bell == 1'b1)) ? 1 : ack);
|
ack <= (reset | ~write) ? 0 : (((state == L_HOLD) && (bell == 1'b1)) ? 1 : ack);
|
end
|
end
|
|
|
endmodule
|
endmodule
|
|
|
No newline at end of file
|
No newline at end of file
|
|
|
No newline at end of file
|
No newline at end of file
|