On the Altera DE2 FPGA development board, there is a Liquid Crystal Display (LCD) module that can be used to display text by sending appropriate commands from FPGA chip to the LCD module. There is a built-in controller HD44780 in the LCD module to drive the display. The interface between FPGA chip and the LCD module is shown in Fig.8.22.
Fig.8.22 The interface between FPGA chip and LCD module
LCD_ON (high-active) turns on the power of LCD module. LCD_BLON controls the LCD back light. LCD_DATA [0:7] is an 8-bit data bus for their data communication. LCD_RW defines the direction of data bus (LCD_RW=1 for read: from LCD to FPGA; LCD_RW=0 for write: from FPGA to LCD). LCD_EN is a read/write enable signal, i.e., a falling edge on LCD_EN is required for a data read/write operation. LCD_RS is a Data/Command select signal, i.e., LCD_DATA [0:7] is data for display when LCD_RS is 1; LCD_DATA is a command (display clear, cursor shift and address information etc.) if LCD_RS is 0. The FPGA pin assignment of the interface is shown in Table.8.1
FPGA L C D
d i s p l a y ( c o n t r o l l e r
H D 4 4 7 8 0 i n c l u d e d ) LCD_ON LCD_BLON LCD_RW LCD_RS LCD_EN LCD_DATA[0:7] Table 8.1 LCD related pin assignments on DE2
8.4.2 Function description of LCD module
1) Registers, DDRAM, and CGROM in LCD module The controller HD44780, built in LCD module, plays an important role in the LCD display task. The controller communicates with FPGA, and controls the LCD display. The block diagram of HD44780 is shown in Fig.8.23. The HD44780 has two 8-bit registers (IR, and DR) to store information sent from FPGA. The operation and selection of two registers are defined by Table 8.2. The IR (instruction register) stores instruction codes, such as display clear, cursor shift, and address information for display data RAM (DDRAM) and character generator RAM (CGRAM). The IR can only be written from FPGA. The DR (data register) temporarily stores data to be written into DDRAM or CGRAM and temporarily stores data read from DDRAM or CGRAM. Here we only consider the situation that data are written into DDRAM or CGRAM. So, in our following discussion, LCD_RW is always set to 0 for writing only, unless otherwise stated. By LCD_RS, the data LCD_DATA [0:7] is interpreted either as instruction codes (when LCD_RS=0) or as display data (when LCD_RS=1).
Fig.8.23 HD44780 block diagram
Table 8.2 Register Selection
Fig.8.24 the relationship between DDRAM addresses and positions on LCD The address counter (AC) receives an initial address through IR based on a command/instruction code, and assigns and updates addresses to both DDRAM and CGRAM. The DDRAM is used to store the display data represented in 8-bit character codes and sent from FPGA. Each address of DDRAM corresponds to a position on the LCD. The relationship between DDRAM addresses and positions on LCD is shown in Fig. 8.24 (2-by-16 character display). Character Generator ROM (CGROM): The CGROM generate 5x8 dot or 5x10 dot character patterns from 8-bit character codes. See Table 8.3. For example, in order to display 2 on the first line position 5, 8h32 should be written into the address (AC) 8h04 of DDRAM.
Table 8.3 CGROM pattern (5x8 dots)
2) Instruction table Table 8.4 includes all available instructions to control LCD. The MPU/FPGA will send a sequence of instructions to LCD with appropriate timing constraints. The instructions are divided into two types: 1) command; 2) data transfer. The command instructions (RS=0) are used to initialize the LCD or set required address. The data transfer instructions are used to send the data (to be displayed on LCD) to LCD or read the data information from RAM in LCD built-in controller (HD44780).
Table 8.4 Instruction table
3) Timing requirements The MPU/FPGA should meet the following timing requirements when it communicates with LCD. For write operation (R/W=0), a negative edge of E (i.e. LCD_EN) is required to send DB (i.e. LCD_DATA [0:7]) to LCD, as shown in Fig.8.25. For read operation, it is the same except that R/W needs to be 1.
Fig. 8.25 Writing operation
8.4.3 Initializing of LCD
FPGA chip needs to send a series of initialization commands to initialize the LCD. These commands include function set, display off, display clear, and entry mode set. The datasheet provides a typical initialization process shown in Fig.8.26. Thus an entire flowchart of LCD tasks is illustrated in Fig.8.27.
Fig. 8.26 Initialization steps
Initialization Text display Fig.8.27 Flowchart of LCD display
8.4.4 An example: digital clock on LCD
We will design a digital clock on Altera DE2 board, shown in Fig.8.28. The time will be displayed on both 7-segment displays HEX0 to HEX7 and LCD module. The digital_clock block delivers BCD of each digit of time (hour, minute, and second) to module fsm_lcd, which is an FSM that communicates with the LCD for display.
Fig.8.28 Diagram of a digital clock on DE2 reset Function set Display off Display clear Display on Mode set Display char 1 Display other chars Display chars in 2 nd line Return home Set DDRAM address for 2 nd
line display
State transition diagram for fsm_lcd
Based on the flow of LCD tasks and timing requirements, a state transition diagram is developed as follows. Each task in Fig.8.27 requires two states since a falling edge on LCD_EN is needed to write commands/data (LCD_DATA) to DDRAM
Notes: 1) Each task is followed by drop_e state. In drop_e sate, LCD_EN drops to zero while other output signals keep the same. 2) LCD_RS=0 for selecting instruction register (IR) (i.e. command), LCD_RS=1 for selecting data register (DR) (i.e. data display) 3) Set_add_line1: before going back to display digit bcd_hrd1, set the DDRAM address for the position of displaying bcd_hrd1. Set_add_line2 {LCD_EN, LCD_RS}=2b10 LCD_DATA_VALUE=8hc0;
always @ (p_state) begin case (p_state) reset1: begin n_state = toggle_e1; {LCD_EN, LCD_RS}=2'b10; LCD_DATA_VALUE = 8'h38; end toggle_e1: begin n_state = reset2; {LCD_EN, LCD_RS}=2'b00; LCD_DATA_VALUE = 8'h38; end
reset2: begin n_state = toggle_e2; {LCD_EN, LCD_RS}=2'b10; LCD_DATA_VALUE = 8'h38; end
toggle_e2: begin n_state = reset3; {LCD_EN, LCD_RS}=2'b00; LCD_DATA_VALUE = 8'h38; end
reset3: begin n_state = toggle_e3; {LCD_EN, LCD_RS}=2'b10; LCD_DATA_VALUE = 8'h38; end
toggle_e3: begin n_state = FUNC_SET; {LCD_EN, LCD_RS}=2'b00; LCD_DATA_VALUE = 8'h38; end
FUNC_SET:
begin n_state = toggle_e4; {LCD_EN, LCD_RS}=2'b10; LCD_DATA_VALUE = 8'h38; end
toggle_e4: begin n_state = display_off; {LCD_EN, LCD_RS}=2'b00; LCD_DATA_VALUE = 8'h38; end display_off: begin n_state = toggle_e5; {LCD_EN, LCD_RS}=2'b10; LCD_DATA_VALUE = 8'h08; end
toggle_e5: begin n_state = display_clear; {LCD_EN, LCD_RS}=2'b00; LCD_DATA_VALUE = 8'h08; end display_clear:
begin n_state = toggle_e6; {LCD_EN, LCD_RS}=2'b10; LCD_DATA_VALUE = 8'h01; end
toggle_e6: begin n_state = display_on; {LCD_EN, LCD_RS}=2'b00; LCD_DATA_VALUE = 8'h01; end
display_on:
begin n_state = toggle_e7; {LCD_EN, LCD_RS}=2'b10; LCD_DATA_VALUE = 8'h0c; end
toggle_e7: begin n_state = mode_set; {LCD_EN, LCD_RS}=2'b00; LCD_DATA_VALUE = 8'h0c; end mode_set:
begin n_state = toggle_e8; {LCD_EN, LCD_RS}=2'b10; LCD_DATA_VALUE = 8'h06; end
toggle_e8: begin n_state = write_char1; {LCD_EN, LCD_RS}=2'b00; LCD_DATA_VALUE = 8'h06; end
write_char1:
begin n_state = toggle_e9; {LCD_EN, LCD_RS}=2'b11; LCD_DATA_VALUE = {3'b011, bcd_hrd1}; end toggle_e9: begin n_state = write_char2; {LCD_EN, LCD_RS}=2'b01; LCD_DATA_VALUE = {3'b011, bcd_hrd1}; end write_char2:
begin n_state = toggle_e10; {LCD_EN, LCD_RS}=2'b11; LCD_DATA_VALUE = {3'b011, bcd_hrd0}; end toggle_e10: begin n_state = write_char3; {LCD_EN, LCD_RS}=2'b01; LCD_DATA_VALUE = {3'b011, bcd_hrd0}; end write_char3: begin n_state = toggle_e11; {LCD_EN, LCD_RS}=2'b11; LCD_DATA_VALUE = 8'h3a; end toggle_e11: begin n_state = write_char4; {LCD_EN, LCD_RS}=2'b01; LCD_DATA_VALUE = 8'h3a; end write_char4:
begin n_state = toggle_e12; {LCD_EN, LCD_RS}=2'b11; LCD_DATA_VALUE = {3'b011, bcd_mind1}; end toggle_e12: begin n_state = write_char5; {LCD_EN, LCD_RS}=2'b01; LCD_DATA_VALUE = {3'b011, bcd_mind1}; end write_char5: begin n_state = toggle_e13; {LCD_EN, LCD_RS}=2'b11; LCD_DATA_VALUE = {3'b011, bcd_mind0}; end toggle_e13: begin n_state = write_char6; {LCD_EN, LCD_RS}=2'b01; LCD_DATA_VALUE = {3'b011, bcd_mind0}; end write_char6: begin n_state = toggle_e14; {LCD_EN, LCD_RS}=2'b11; LCD_DATA_VALUE = 8'h3a; end toggle_e14: begin n_state = write_char7; {LCD_EN, LCD_RS}=2'b01; LCD_DATA_VALUE = 8'h3a; end write_char7: begin n_state = toggle_e15; {LCD_EN, LCD_RS}=2'b11; LCD_DATA_VALUE ={3'b011, bcd_secd1}; end toggle_e15: begin n_state = write_char8; {LCD_EN, LCD_RS}=2'b01; LCD_DATA_VALUE ={3'b011, bcd_secd1}; end write_char8: begin n_state = toggle_e16; {LCD_EN, LCD_RS}=2'b11; LCD_DATA_VALUE ={3'b011, bcd_secd0}; end toggle_e16: begin n_state = w_address; {LCD_EN, LCD_RS}=2'b01; LCD_DATA_VALUE ={3'b011, bcd_secd0}; end
// set DDRAM address for the second line w_address: begin n_state = toggle_e17; {LCD_EN, LCD_RS}=2'b10; LCD_DATA_VALUE =8'hc0; end toggle_e17: begin n_state = write_w; {LCD_EN, LCD_RS}=2'b00; LCD_DATA_VALUE =8'hc0; end write_w: begin n_state = toggle_e18; {LCD_EN, LCD_RS}=2'b11; LCD_DATA_VALUE =8'h57; end toggle_e18: begin n_state = write_e; {LCD_EN, LCD_RS}=2'b00; LCD_DATA_VALUE =8'h57; end write_e: begin n_state = toggle_e20; {LCD_EN, LCD_RS}=2'b11; LCD_DATA_VALUE =8'h65; end toggle_e20: begin n_state = return_home; {LCD_EN, LCD_RS}=2'b00; LCD_DATA_VALUE =8'h65; end return_home: begin n_state = toggle_e21; {LCD_EN, LCD_RS}=2'b10; LCD_DATA_VALUE =8'h80; //8'h80; end toggle_e21: begin n_state = write_char1; {LCD_EN, LCD_RS}=2'b00; LCD_DATA_VALUE =8'h80;//8'h80; end endcase end
always @ (posedge CLK_400Hz, negedge resetn) begin if (resetn == 0) begin p_state <= reset1;
Kindle Fire Owner's Manual: The ultimate Kindle Fire guide to getting started, advanced user tips, and finding unlimited free books, videos and apps on Amazon and beyond