Hello,
I'm posting my working Verilog state machine for driving the Character LCD. Sorry there are not many comments. This module requires a 5MHz clock for correct LCD timing. The module initializes the LCD according to the some constants that you can modify as you wish.
Asserting the write input will start an LCD write cycle, which writes the a character on the text bus to the current cursor position. Change the cursor position by asserting the write and addr inputs together, with the new cursor position on the text bus.
Thomas
module LCD_driver_char (input clk, input wire addr, input wire text, input wire write, output busy, output reg LCD_RS = 0, output reg LCD_RW = 0, output reg LCD_E = 0, inout LCD_data);
assign LCD_data = LCD_RW ? 8'bzzzzzzzz : data_reg;
assign busy = ~|state || ~state || state;
reg state;
reg countclk;
reg data_reg;
reg text_hold;
reg addr_hold;
initial begin
state <= 0;
countclk <= 0;
data_reg <= 0;
text_hold <= 0;
addr_hold <= 0;
end
always @ (posedge clk) begin
if (write) begin
state <= 1'b1;
text_hold <= text;
addr_hold <= addr;
end
if (state == 2'b00) begin
if (countclk == 200000) state <= 6'b010000;
else countclk <= countclk + 1'b1;
end else if (state == 2'b01) begin
if (~state) begin
state <= 2'b10;
countclk <= 20'h00000;
LCD_RW <= 0;
LCD_RS <= 0;
if (state == 2'b00) begin
data_reg <= 8'b00111000; // Function Set
state <= 2'b01;
end else if (state == 2'b01) begin
data_reg <= 8'b00001110; // Display Config
state <= 2'b10;
end else if (state == 2'b10) begin
data_reg <= 8'b00000001; // Display Clear
state <= 2'b11;
end else if (state == 2'b11) begin
data_reg <= 8'b00000110; // Memory Mode
state <= 2'b10;
end
end else if (~write) begin
if (state) begin
state <= 2'b10;
state <= 1'b0;
countclk <= 20'h00000;
LCD_RW <= 0;
LCD_RS <= ~addr_hold;
data_reg <= addr_hold ? (text_hold ? 8'b11000000 : 8'b10000000) + text_hold : text_hold;
end
end
end else if (state == 2'b10) begin
if (~state) begin
if (countclk == 4) begin
LCD_E <= 1;
countclk <= countclk + 1'b1;
end else if (countclk == 16) begin
LCD_E <= 0;
countclk <= countclk + 1'b1;
end else if (countclk == 50) begin
state <= 1;
countclk <= 0;
LCD_RW <= 1;
LCD_RS <= 0;
end else begin
countclk <= countclk + 1'b1;
end
end else begin
if (countclk == 4) begin
LCD_E <= 1;
countclk <= countclk + 1'b1;
end else if (countclk == 16) begin
LCD_E <= 0;
if (LCD_data == 0) begin
state <= 2'b11;
state <= 0;
end
countclk <= countclk + 1'b1;
end else if (countclk == 50) begin
countclk <= 0;
end else begin
countclk <= countclk + 1'b1;
end
end
end else if (state == 2'b11) begin
if (countclk == 50) state <= 2'b01;
else countclk <= countclk + 1'b1;
end
end
endmodule