[Evaluation of domestic FPGA Gaoyun GW1N-4 series development board]——11. Click on the LCD1602 screen
[Copy link]
This post was last edited by gs001588 on 2022-1-20 20:55
[Evaluation of domestic FPGA Gaoyun GW1N-4 series development board]——11. Click on the LCD1602 screen
I have written a 12864 display application with fonts on FPGA before, but it has been a long time since then, and I cannot find the backup data. I have an LCD1602 LCD screen, so I might as well use it to do a display experiment. LCD1602 is a classic LCD screen, and its application on various learning platforms is indispensable, and FPGA is no exception.
In line with the idea of taking what is available, I referred to the information of netizens and made appropriate modifications. I originally planned to make a video memory module, with an asynchronous RAM interface. The module completed LCD initialization internally, and automatically displayed refresh operations after new video memory data. In this way, it is necessary to write a top-level file and provide a changing data source, which complicates the problem, so it can be used as a subsequent improvement experiment. This post first shows LCD1602.
Reference website ( LCD1602 display driver based on FPGA https://blog.csdn.net/qq_33231534/article/details/108484995 )
The FPGA pin resource configuration used in this experiment is as follows:
The corresponding wiring table between GWIN-4B and LCD1602 screen:
LCD1602 |
Functional Description |
GWIN-4B |
1. VCC |
Power Ground |
JP7.2-5V |
2. GND |
Positive power supply |
J19.1-GND |
3. V0 (connect 5.1K to GND)
|
LCD Bias |
|
4. RS |
Command/Data Selection |
J4.1-32 |
5. RW |
Read/Write Selection |
J4.2-34 |
6. EN |
Enable signal |
J4.3-38 |
7. DATA0 |
Data0 |
J4.4-39 |
8. DATA1
|
Data 1 |
J4.5-40 |
9. DATA2 |
Data 2 |
J4.6-41 |
10. DATA3 |
Data 3 |
J4.7-42 |
11. DATA4 |
Data 4 |
J4.8-43 |
12. DATA5 |
Data 5 |
J4.9-44 |
13. DATA6
|
Data 6 |
J4.10-45 |
14. DATA7 |
Data 7 |
J4.11-46 |
15.A (5V) |
Backlight positive |
JP7.1-5V |
16. K (GND) |
Backlight negative |
J19.16-GND |
A 5.1K direct-insertion resistor is connected between pins 1 and 3 of LCD1602 to provide a reference for the LCD display bias voltage V0 of pin 3. If used on a general development board, a 10K potentiometer will be connected between pins 1 and 3 to adjust the voltage. Why is it 5.1K? I repaired a development board before, and pin 3 on the board was connected to GND, which caused the ordinary LCD1602 to not display. According to the LCD1602 data sheet, this pin V0 is the LCD display bias voltage. When it is grounded, the contrast is the highest. When the contrast is too high, "ghosting" will occur, and the display will be black and difficult to distinguish between normal display and background color; when connected to the positive power supply voltage, the contrast is the weakest, and the display will be white and almost invisible. Connecting a resistor of about 5K can display normally. The resistor does not need to be accurate, 4 to 6K is fine.
It happens that JP7 has two 5V pins, one of which is used to power the LCD logic and the other is used to power the positive pole of the backlight. There are many GND pins, so I randomly selected two, one as the power ground and the other as the negative pole of the backlight.
The remaining 11 data lines are connected to pins 1 to 11 of JP14 respectively.
The logic code is shown below. For specific functions and LCD1602 related register functions, please refer to the relevant content in the "Reference Website" above.
module lcd(
input clk ,
input rst_n ,
output reg lcd_rs ,
output wire lcd_rw ,
output reg lcd_en ,
output reg [7:0] lcd_data
);
reg [17:0] cnt ;
reg [3:0] state_c ;
reg [3:0] state_n ;
reg [4:0] char_cnt ;
reg [7:0] data_display ;
localparam
IDLE = 4'd0 ,
INIT = 4'd1 ,
S0 = 4'd2 ,
S1 = 4'd3 ,
S2 = 4'd4 ,
S3 = 4'd5 ,
ROW1_ADDR = 4'd6 ,
WRITE = 4'd7 ,
ROW2_ADDR = 4'd8 ,
stop = 4'd9 ;
reg [7:0] disp_memory [0:31];
reg [4:0] disp_cnt;
assign lcd_rw = 1'b0;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 17'd0;
end
else begin
if (cnt==17'd100_000 - 1) begin
cnt <= 17'd0;
end
else begin
cnt <= cnt + 1'b1;
end
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
lcd_en <= 0;
end
else if (cnt==17'd50_000 - 1) begin
lcd_en <= 1;
end
else if (cnt==17'd100_000 - 1) begin
lcd_en <= 0;
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
char_cnt <= 0;
end
else if (state_c==WRITE && cnt==17'd50_000 - 1) begin
if (char_cnt==5'd31) begin
char_cnt <= 5'd0;
end
else begin
char_cnt <= char_cnt + 1'b1;
end
end
end
integer i;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
for(i=0;i<32;i=i+1)
begin
case(i)
5'd0: data_display = "W";
5'd1: data_display = "e";
5'd2: data_display = "l";
5'd3: data_display = "c";
5'd4: data_display = "o";
5'd5: data_display = "m";
5'd6: data_display = "e";
5'd7: data_display = " ";
5'd8: data_display = "t";
5'd9: data_display = "o";
5'd10: data_display = " ";
5'd11: data_display = "G";
5'd12: data_display = "O";
5'd13: data_display = "W";
5'd14: data_display = "I";
5'd15: data_display = "N";
5'd16: data_display = "M";
5'd17: data_display = "i";
5'd18: data_display = "n";
5'd19: data_display = "i";
5'd20: data_display = " ";
5'd21: data_display = "K";
5'd22: data_display = "i";
5'd23: data_display = "T";
5'd24: data_display = " ";
5'd25: data_display = "G";
5'd26: data_display = "W";
5'd27: data_display = "I";
5'd28: data_display = "N";
5'd29: data_display = "-";
5'd30: data_display = "4";
5'd31: data_display = "B";
default:data_display = "P";
endcase
disp_memory = data_display;
end
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state_c <= IDLE;
end
else if(cnt==17'd50_000 - 1) begin
state_c <= state_n;
end
end
reg [19:0] cnt_15ms;
reg flag ;
always@(posedge clk or negedge rst_n)begin
if (!rst_n) begin
cnt_15ms <= 0;
end
else if (state_c == IDLE) begin
cnt_15ms <= cnt_15ms + 1'b1;
end
end
always@(posedge clk or negedge rst_n)begin
if (!rst_n) begin
flag <= 0;
end
else if (state_c==IDLE && cnt_15ms==20'd750000) begin
flag <= 1;
end
end
always @(*) begin
case(state_c)
IDLE :
begin
if (flag) begin
state_n = INIT;
end
else begin
state_n = state_c;
end
end
INIT :
begin
state_n = S0;
end
S0 :
begin
state_n = S1;
end
S1 :
begin
state_n = S2;
end
S2 :
begin
state_n = S3;
end
S3 :
begin
state_n = ROW1_ADDR;
end
ROW1_ADDR:
begin
state_n = WRITE;
end
WRITE :
begin
if (char_cnt==5'd15) begin
state_n = ROW2_ADDR;
end
else if (char_cnt==5'd31) begin
state_n = stop;
end
else begin
state_n = state_c;
end
end
ROW2_ADDR:
begin
state_n = WRITE;
end
stop :
begin
state_n = stop;
end
default:state_n = IDLE;
endcase
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
lcd_data <= 8'd0;
end
else begin
case(state_c)
IDLE :begin lcd_data <= 8'h38; lcd_rs <= 0;end
INIT :begin lcd_data <= 8'h38; lcd_rs <= 0;end
S0 :begin lcd_data <= 8'h08; lcd_rs <= 0;end
S1 :begin lcd_data <= 8'h01; lcd_rs <= 0;end
S2 :begin lcd_data <= 8'h06; lcd_rs <= 0;end
S3 :begin lcd_data <= 8'h0c; lcd_rs <= 0;end
ROW1_ADDR :begin lcd_data <= 8'h80; lcd_rs <= 0;end
//WRITE :begin lcd_data <= data_display; lcd_rs <= 1;end
WRITE :begin lcd_data <= disp_memory[char_cnt]; lcd_rs <= 1;end
ROW2_ADDR :begin lcd_data <= 8'hc0; lcd_rs <= 0;end
stop :begin lcd_data <= 8'h38; lcd_rs <= 0;end
default:;
endcase
end
end
endmodule
This experiment uses the reset function, and tick RECONFIG_N in the dual-function pin option as a normal IO option.
The logic code is compiled and downloaded to the development board. The two lines of LCD1602 display "Welcome to GOWIN" and "Mini KiT GWIN-4B" respectively. The effect is shown in the figure below.
After this experiment is completed, the LCD1602 screen will be lit up to display characters.
Due to the epidemic, I cannot go on as usual. The conditions at home are limited, and I lack expansion modules for experiments. I will add more expansion functions later when I have time.
|