Line 1... |
Line 1... |
`timescale 1ns / 1ps
|
`timescale 1ns / 1ps
|
|
|
module lcd_controller(
|
module lcd_controller(
|
input rst,
|
input rst,
|
input clk,
|
input clk,
|
|
input rs_in,
|
input [7:0] data_in,
|
input [7:0] data_in,
|
input strobe_in,
|
input strobe_in,
|
input [7:0] period_clk_ns,
|
input [7:0] period_clk_ns,
|
output lcd_e,
|
output lcd_e,
|
output [3:0] lcd_nibble,
|
output [3:0] lcd_nibble,
|
Line 23... |
Line 24... |
localparam lcd_init_wait_100us = 6;
|
localparam lcd_init_wait_100us = 6;
|
localparam lcd_init_write_03_03 = 7;
|
localparam lcd_init_write_03_03 = 7;
|
localparam lcd_init_wait_40us = 8;
|
localparam lcd_init_wait_40us = 8;
|
localparam lcd_init_write_02 = 9;
|
localparam lcd_init_write_02 = 9;
|
localparam lcd_init_wait_50us = 10;
|
localparam lcd_init_wait_50us = 10;
|
localparam lcd_init_strobe = 11;
|
localparam lcd_init_state_done = 11;
|
|
localparam lcd_init_strobe = 12;
|
reg [3:0] lcd_init_states, lcd_init_state_next; // Declare two variables of 4 bits to hold the FSM states
|
reg [3:0] lcd_init_states, lcd_init_state_next; // Declare two variables of 4 bits to hold the FSM states
|
reg [19:0] counter_wait_lcd_init;
|
reg [23:0] counter_wait_lcd_init;
|
reg [7:0] counter_wait_strobe_lcd_init;
|
reg [8:0] counter_wait_strobe_lcd_init, counter_wait_stabilize_lcd_init;
|
reg [19:0] time_wait_lcd_init;
|
reg [23:0] time_wait_lcd_init;
|
reg [3:0] lcd_init_data_out; // FSM output LCD_DATA
|
reg [3:0] lcd_init_data_out; // FSM output LCD_DATA
|
reg lcd_init_e_out; // FSM output LCD_E
|
reg lcd_init_e_out; // FSM output LCD_E
|
reg lcd_init_done;
|
reg lcd_init_done;
|
|
|
// States for FSM that send data to LCD
|
// States for FSM that send data to LCD
|
localparam lcd_data_rst = 1;
|
localparam lcd_data_rst = 1;
|
localparam lcd_data_wait = 2;
|
localparam lcd_data_wait_1us = 2;
|
localparam lcd_data_wr_nibble_high = 3;
|
localparam lcd_data_wr_nibble_high = 3;
|
localparam lcd_data_wr_nibble_low = 4;
|
localparam lcd_data_wr_nibble_low = 4;
|
localparam lcd_data_strobe = 5;
|
localparam lcd_data_strobe = 5;
|
|
localparam lcd_data_wait_40us = 6;
|
|
localparam lcd_data_done = 7;
|
|
reg [19:0] time_wait_lcd_data;
|
|
reg [19:0] counter_wait_lcd_data;
|
|
reg [8:0] counter_wait_strobe_lcd_data, counter_wait_stabilize_lcd_data;
|
reg [3:0] lcd_data_states, lcd_data_state_next; // Declare two variables of 4 bits to hold the FSM states
|
reg [3:0] lcd_data_states, lcd_data_state_next; // Declare two variables of 4 bits to hold the FSM states
|
reg [3:0] lcd_data_data_out; // FSM output LCD_DATA
|
reg [3:0] lcd_data_data_out; // FSM output LCD_DATA
|
reg lcd_data_e_out; // FSM output LCD_E
|
reg lcd_data_e_out; // FSM output LCD_E
|
|
reg done;
|
|
|
|
|
/*
|
/*
|
Initialize LCD...
|
Initialize LCD...
|
*/
|
*/
|
Line 53... |
Line 61... |
if (rst) // Reset synchronous
|
if (rst) // Reset synchronous
|
begin
|
begin
|
lcd_init_states <= lcd_init_rst;
|
lcd_init_states <= lcd_init_rst;
|
counter_wait_lcd_init <= 0;
|
counter_wait_lcd_init <= 0;
|
counter_wait_strobe_lcd_init <= 0;
|
counter_wait_strobe_lcd_init <= 0;
|
|
counter_wait_stabilize_lcd_init <= 0;
|
lcd_init_e_out <= 0;
|
lcd_init_e_out <= 0;
|
lcd_init_done <= 0;
|
lcd_init_done <= 0;
|
|
lcd_init_data_out <= 0;
|
end
|
end
|
else
|
else
|
begin
|
begin
|
case (lcd_init_states)
|
case (lcd_init_states)
|
lcd_init_rst:
|
lcd_init_rst:
|
Line 71... |
Line 81... |
|
|
// Wait for a configured time in (ns) and go to other state in (lcd_init_state_next)
|
// Wait for a configured time in (ns) and go to other state in (lcd_init_state_next)
|
lcd_init_wait:
|
lcd_init_wait:
|
begin
|
begin
|
counter_wait_lcd_init <= counter_wait_lcd_init + period_clk_ns;
|
counter_wait_lcd_init <= counter_wait_lcd_init + period_clk_ns;
|
if (counter_wait_lcd_init > time_wait_lcd_init)
|
if (counter_wait_lcd_init >= time_wait_lcd_init)
|
|
begin
|
lcd_init_states <= lcd_init_state_next;
|
lcd_init_states <= lcd_init_state_next;
|
|
counter_wait_lcd_init <= 0;
|
|
end
|
end
|
end
|
|
|
// Strobe the LCD for at least 240 ns
|
// Strobe the LCD for at least 240 ns
|
lcd_init_strobe:
|
lcd_init_strobe:
|
begin
|
begin
|
lcd_init_e_out = 1;
|
// We need to wait at least 40ns to stabilize the data before strobing the data...
|
|
counter_wait_stabilize_lcd_init <= counter_wait_stabilize_lcd_init + period_clk_ns;
|
|
if (counter_wait_stabilize_lcd_init >= 40)
|
|
begin
|
|
lcd_init_e_out <= 1;
|
|
|
|
// After we got a strobe high hold for more 240 ns
|
counter_wait_strobe_lcd_init <= counter_wait_strobe_lcd_init + period_clk_ns;
|
counter_wait_strobe_lcd_init <= counter_wait_strobe_lcd_init + period_clk_ns;
|
if (counter_wait_strobe_lcd_init > 240)
|
if (counter_wait_strobe_lcd_init >= 240)
|
begin
|
begin
|
lcd_init_states <= lcd_init_state_next;
|
lcd_init_states <= lcd_init_state_next;
|
|
counter_wait_stabilize_lcd_init <= 0;
|
|
counter_wait_strobe_lcd_init <= 0;
|
lcd_init_e_out <= 0;
|
lcd_init_e_out <= 0;
|
end
|
end
|
end
|
end
|
|
end
|
|
|
lcd_init_write_03_01:
|
lcd_init_write_03_01:
|
// Send 0x3 and pulse LCD_E for 240ns
|
// Send 0x3 and pulse LCD_E for 240ns
|
begin
|
begin
|
lcd_init_data_out <= 4'h3;
|
lcd_init_data_out <= 4'h3;
|
Line 127... |
Line 149... |
lcd_init_state_next <= lcd_init_wait_40us;
|
lcd_init_state_next <= lcd_init_wait_40us;
|
end
|
end
|
|
|
lcd_init_wait_40us:
|
lcd_init_wait_40us:
|
begin
|
begin
|
time_wait_lcd_init <= 100000; // Wait for 100us
|
time_wait_lcd_init <= 40000; // Wait for 40us
|
lcd_init_states <= lcd_init_wait;
|
lcd_init_states <= lcd_init_wait;
|
lcd_init_state_next <= lcd_init_write_02;
|
lcd_init_state_next <= lcd_init_write_02;
|
end
|
end
|
|
|
lcd_init_write_02:
|
lcd_init_write_02:
|
// Send 0x3 and pulse LCD_E for 240ns
|
// Send 0x2 and pulse LCD_E for 240ns
|
begin
|
begin
|
lcd_init_data_out <= 4'h2;
|
lcd_init_data_out <= 4'h2;
|
lcd_init_states <= lcd_init_strobe; // Strobe for at least 230 ns
|
lcd_init_states <= lcd_init_strobe; // Strobe for at least 230 ns
|
lcd_init_state_next <= lcd_init_wait_50us;
|
lcd_init_state_next <= lcd_init_wait_50us;
|
end
|
end
|
|
|
lcd_init_wait_50us:
|
lcd_init_wait_50us:
|
begin
|
begin
|
time_wait_lcd_init <= 100000; // Wait for 100us
|
time_wait_lcd_init <= 50000; // Wait for 50us
|
lcd_init_states <= lcd_init_wait;
|
lcd_init_states <= lcd_init_wait;
|
lcd_init_state_next <= lcd_init_wait_50us;
|
lcd_init_state_next <= lcd_init_state_done;
|
|
end
|
|
|
|
lcd_init_state_done:
|
|
begin
|
lcd_init_done <= 1;
|
lcd_init_done <= 1;
|
|
lcd_init_state_next <= lcd_init_state_done;
|
end
|
end
|
endcase;
|
endcase;
|
end;
|
end;
|
end;
|
end;
|
|
|
assign lcd_e = lcd_init_e_out;
|
assign lcd_rw = 0;
|
assign lcd_nibble = lcd_init_data_out;
|
|
|
// Will assign the output of the FSM init or the FSM data depending if initialization is already done
|
|
assign lcd_e = (!lcd_init_done) ? lcd_init_e_out : lcd_data_e_out;
|
|
assign lcd_nibble = (!lcd_init_done) ? lcd_init_data_out : lcd_data_data_out ;
|
|
|
/*
|
/*
|
FSM that deals to send data to the LCD (nibble High + nibble Low)
|
FSM that deals to send data to the LCD (nibble High + nibble Low)
|
*/
|
*/
|
always @ (posedge clk)
|
always @ (posedge clk)
|
begin
|
begin
|
if (~lcd_init_done)
|
if (~lcd_init_done)
|
begin
|
begin
|
|
lcd_data_e_out <= 0;
|
|
lcd_data_data_out <= 0;
|
|
lcd_data_states <= lcd_data_rst;
|
|
done <= 0;
|
|
counter_wait_stabilize_lcd_data <= 0;
|
|
counter_wait_lcd_data <= 0;
|
|
counter_wait_strobe_lcd_data <= 0;
|
|
end
|
|
else
|
|
begin
|
|
case (lcd_data_states)
|
|
lcd_data_rst:
|
|
begin
|
|
done <= 0;
|
|
// Start to send data when strobe_in =1
|
|
if (strobe_in == 1)
|
|
begin
|
|
lcd_data_states <= lcd_data_wr_nibble_high;
|
|
end
|
|
else
|
|
lcd_data_states <= lcd_data_rst;
|
|
end
|
|
|
|
lcd_data_wr_nibble_high:
|
|
begin
|
|
// First send the high nibble
|
|
lcd_data_data_out <= data_in[7:4];
|
|
lcd_data_states <= lcd_data_strobe;
|
|
lcd_data_state_next <= lcd_data_wait_1us;
|
|
end
|
|
|
|
lcd_data_strobe:
|
|
begin
|
|
// We need to wait at least 40ns to stabilize the data before strobing the data...
|
|
counter_wait_stabilize_lcd_data <= counter_wait_stabilize_lcd_data + period_clk_ns;
|
|
if (counter_wait_stabilize_lcd_data >= 40)
|
|
begin
|
|
lcd_data_e_out <= 1;
|
|
|
|
// After we got a strobe high hold for more 240 ns
|
|
counter_wait_strobe_lcd_data <= counter_wait_strobe_lcd_data + period_clk_ns;
|
|
if (counter_wait_strobe_lcd_data >= 240)
|
|
begin
|
|
lcd_data_states <= lcd_data_state_next;
|
|
counter_wait_stabilize_lcd_data <= 0;
|
|
counter_wait_strobe_lcd_data <= 0;
|
|
lcd_data_e_out <= 0;
|
|
end
|
|
end
|
|
end
|
|
|
|
// Wait for 1us before sending the low nibble
|
|
lcd_data_wait_1us:
|
|
begin
|
|
counter_wait_lcd_data <= counter_wait_lcd_data + period_clk_ns;
|
|
if (counter_wait_lcd_data >= 1000)
|
|
begin
|
|
lcd_data_states <= lcd_data_wr_nibble_low;
|
|
counter_wait_lcd_data <= 0;
|
|
end
|
|
end
|
|
|
|
lcd_data_wr_nibble_low:
|
|
begin
|
|
// After send the low nibble
|
|
lcd_data_data_out <= data_in[3:0];
|
|
lcd_data_states <= lcd_data_strobe;
|
|
lcd_data_state_next <= lcd_data_wait_40us;
|
|
end
|
|
|
|
// Wait for 40us before sending the next byte
|
|
lcd_data_wait_40us:
|
|
begin
|
|
counter_wait_lcd_data <= counter_wait_lcd_data + period_clk_ns;
|
|
if (counter_wait_lcd_data >= 40000)
|
|
begin
|
|
lcd_data_states <= lcd_data_done;
|
|
counter_wait_lcd_data <= 0;
|
|
end
|
|
end
|
|
|
|
lcd_data_done:
|
|
begin
|
|
// Signal that we done sending the data
|
|
done <= 1;
|
|
lcd_data_states <= lcd_data_rst;
|
|
end
|
|
|
|
endcase
|
end
|
end
|
end;
|
end;
|
|
|
endmodule
|
endmodule
|
|
|
No newline at end of file
|
No newline at end of file
|