F
Fei Liu
Guest
(originally posted on c.a.fpga but it seems that may not be the right
newsgroup, reposted here in c.l.verilog)
Hello gentle readers,
I started playing with FPGA and verilog about a month ago. As a fun
starting project, my goal is to allow interaction between host linux pc
and fpga lcd display. The connection is made through serial RS323
interface. Here is my lcd controller module that accomplished my goal. I
am looking for your advice and suggestions and in what ways I can
improve this module. I am hoping to learn from this process.
module lcd_controller (clk, data_ready, rx_data, lcd_rs, lcd_rw, lcd_e,
lcd_4, lcd_5, lcd_6, lcd_7);
parameter k = 18;
// in register_input mode, the input doesn't have to stay valid
// while the character is been transmitted
parameter register_input = 1;
parameter clr = 8'h0A;
input clk;
input data_ready;
input [7:0] rx_data;
output lcd_rs;
output lcd_rw;
output lcd_e;
output lcd_7;
output lcd_6;
output lcd_5;
output lcd_4;
reg lcd_e, lcd_rs, lcd_rw, lcd_7, lcd_6, lcd_5, lcd_4;
reg [k+8:0] count=0;
reg [6:0] lcd_code = 0;
reg [2:0] state=3'b000;
reg [2:0] next_state=3'b000;
wire lcd_ready = (state==1);
// store rx_data locally
reg [7:0] lcd_dataReg;
always @(posedge clk)
if(data_ready & lcd_ready)
lcd_dataReg <= rx_data;
wire [7:0] lcd_dataD = register_input ? lcd_dataReg : rx_data;
// continuous assignment by default of wire type, clr key clears display
wire clear = (rx_data == clr)? 1:0;
//assign {lcd_e,lcd_rs,lcd_rw,lcd_7,lcd_6,lcd_5,lcd_4} = lcd_code;
// sequential logic
always @ (posedge clk)
state <= next_state;
always @ (posedge clk)
begin
if(state != 3'b001)
begin
count <= count + 1;
if(count[4] && state == 3'b010)
count <= 0;
if(count[4] && state == 3'b100)
count <= 0;
if(count[5] && state == 3'b011)
count <= 0;
if(count[10] && state == 3'b101)
count <= 0;
end
else
count <= 0;
{lcd_e,lcd_rs,lcd_rw,lcd_7,lcd_6,lcd_5,lcd_4} <= lcd_code;
if(state == 0 || state == 6) lcd_e <= ^count[k+1:k];
end // sequential logic
// combinatorial logic
always @ (state or count or data_ready or clear) begin
case(state)
3'b000:
begin
if(count[k+5:k+2] == 12)
next_state <= 3'b1; // idle_data/1
else
next_state <= 0;
end
3'b001:
begin
if(data_ready) begin
if(clear)
next_state <= 3'b110; // clear/6
else
next_state <= 3'b10; // disp_hn/2
end
else
next_state <= 3'b1; // idle_data/1
end
3'b010:
begin
if(count[4])
next_state <= 3'b11; // idle_high/3
else
next_state <= 3'b10; // disp_hn/3
end
3'b011:
begin
if(count[5])
next_state <= 3'b100; // disp_ln/4
else
next_state <= 3'b11; // idle_high/3
end
3'b100:
begin
if(count[4])
next_state <= 3'b101; // wait/5
else
next_state <= 3'b100; // disp_ln/4
end
3'b101:
begin
if(count[10])
next_state <= 3'b1; // idle_data/1
else
next_state <= 3'b101; // wait/5
end
3'b110:
begin
if(count[k+3:k+2] == 2)
next_state <= 3'h1; // idle_data/1
else
next_state <= 3'h6; // clear/6
end
endcase
end // combinatorial logic
// output logic
always @(state or count or lcd_dataD) begin
lcd_code <= 7'h00;
case(state)
3'b000:
begin
case (count[k+5:k+2])
0: lcd_code <= 7'h43; // power-on initialization
1: lcd_code <= 7'h43;
2: lcd_code <= 7'h43;
3: lcd_code <= 7'h42;
4: lcd_code <= 7'h42; // function set
5: lcd_code <= 7'h48;
6: lcd_code <= 7'h40; // entry mode set
7: lcd_code <= 7'h46;
8: lcd_code <= 7'h40; // display on/off control
9: lcd_code <= 7'h4C;
10: lcd_code <= 7'h40; // display clear
11: lcd_code <= 7'h41;
endcase
end
3'b001:
lcd_code <= 7'h00;
3'b010:
lcd_code <= {3'b110, lcd_dataD[7:4]};
3'b011:
lcd_code <= 7'b0110000;
3'b100:
lcd_code <= {3'b110, lcd_dataD[3:0]};
3'b101:
lcd_code <= 7'b0110000;
3'b110:
begin
case(count[k+3:k+2])
0: lcd_code <= 7'h40; // display clear
1: lcd_code <= 7'h41;
endcase
end
endcase
end // output logic
endmodule
newsgroup, reposted here in c.l.verilog)
Hello gentle readers,
I started playing with FPGA and verilog about a month ago. As a fun
starting project, my goal is to allow interaction between host linux pc
and fpga lcd display. The connection is made through serial RS323
interface. Here is my lcd controller module that accomplished my goal. I
am looking for your advice and suggestions and in what ways I can
improve this module. I am hoping to learn from this process.
module lcd_controller (clk, data_ready, rx_data, lcd_rs, lcd_rw, lcd_e,
lcd_4, lcd_5, lcd_6, lcd_7);
parameter k = 18;
// in register_input mode, the input doesn't have to stay valid
// while the character is been transmitted
parameter register_input = 1;
parameter clr = 8'h0A;
input clk;
input data_ready;
input [7:0] rx_data;
output lcd_rs;
output lcd_rw;
output lcd_e;
output lcd_7;
output lcd_6;
output lcd_5;
output lcd_4;
reg lcd_e, lcd_rs, lcd_rw, lcd_7, lcd_6, lcd_5, lcd_4;
reg [k+8:0] count=0;
reg [6:0] lcd_code = 0;
reg [2:0] state=3'b000;
reg [2:0] next_state=3'b000;
wire lcd_ready = (state==1);
// store rx_data locally
reg [7:0] lcd_dataReg;
always @(posedge clk)
if(data_ready & lcd_ready)
lcd_dataReg <= rx_data;
wire [7:0] lcd_dataD = register_input ? lcd_dataReg : rx_data;
// continuous assignment by default of wire type, clr key clears display
wire clear = (rx_data == clr)? 1:0;
//assign {lcd_e,lcd_rs,lcd_rw,lcd_7,lcd_6,lcd_5,lcd_4} = lcd_code;
// sequential logic
always @ (posedge clk)
state <= next_state;
always @ (posedge clk)
begin
if(state != 3'b001)
begin
count <= count + 1;
if(count[4] && state == 3'b010)
count <= 0;
if(count[4] && state == 3'b100)
count <= 0;
if(count[5] && state == 3'b011)
count <= 0;
if(count[10] && state == 3'b101)
count <= 0;
end
else
count <= 0;
{lcd_e,lcd_rs,lcd_rw,lcd_7,lcd_6,lcd_5,lcd_4} <= lcd_code;
if(state == 0 || state == 6) lcd_e <= ^count[k+1:k];
end // sequential logic
// combinatorial logic
always @ (state or count or data_ready or clear) begin
case(state)
3'b000:
begin
if(count[k+5:k+2] == 12)
next_state <= 3'b1; // idle_data/1
else
next_state <= 0;
end
3'b001:
begin
if(data_ready) begin
if(clear)
next_state <= 3'b110; // clear/6
else
next_state <= 3'b10; // disp_hn/2
end
else
next_state <= 3'b1; // idle_data/1
end
3'b010:
begin
if(count[4])
next_state <= 3'b11; // idle_high/3
else
next_state <= 3'b10; // disp_hn/3
end
3'b011:
begin
if(count[5])
next_state <= 3'b100; // disp_ln/4
else
next_state <= 3'b11; // idle_high/3
end
3'b100:
begin
if(count[4])
next_state <= 3'b101; // wait/5
else
next_state <= 3'b100; // disp_ln/4
end
3'b101:
begin
if(count[10])
next_state <= 3'b1; // idle_data/1
else
next_state <= 3'b101; // wait/5
end
3'b110:
begin
if(count[k+3:k+2] == 2)
next_state <= 3'h1; // idle_data/1
else
next_state <= 3'h6; // clear/6
end
endcase
end // combinatorial logic
// output logic
always @(state or count or lcd_dataD) begin
lcd_code <= 7'h00;
case(state)
3'b000:
begin
case (count[k+5:k+2])
0: lcd_code <= 7'h43; // power-on initialization
1: lcd_code <= 7'h43;
2: lcd_code <= 7'h43;
3: lcd_code <= 7'h42;
4: lcd_code <= 7'h42; // function set
5: lcd_code <= 7'h48;
6: lcd_code <= 7'h40; // entry mode set
7: lcd_code <= 7'h46;
8: lcd_code <= 7'h40; // display on/off control
9: lcd_code <= 7'h4C;
10: lcd_code <= 7'h40; // display clear
11: lcd_code <= 7'h41;
endcase
end
3'b001:
lcd_code <= 7'h00;
3'b010:
lcd_code <= {3'b110, lcd_dataD[7:4]};
3'b011:
lcd_code <= 7'b0110000;
3'b100:
lcd_code <= {3'b110, lcd_dataD[3:0]};
3'b101:
lcd_code <= 7'b0110000;
3'b110:
begin
case(count[k+3:k+2])
0: lcd_code <= 7'h40; // display clear
1: lcd_code <= 7'h41;
endcase
end
endcase
end // output logic
endmodule