Sie sind auf Seite 1von 15

Writing Characters to LCD Display on Xilinx Spartan -3A FPGA board

Author: Aditya Joshi aditya.joshi@mathworks.com

Overview: The Spartan 3A starter kit board comes with a 2-line by 16-character liquid crystal display (LCD) [1], which offers a practical way to display information. The FPGA can use both 8-bit and 4-bit data interface to control the LCD. Both ASCII and custom characters can be used for displaying information. In this tutorial, we discuss a way to display the word HOLA on the LCD using the eight bit data interface. For complete details on how the LCD display configuration and commands, please refer to the Spartan 3A User Guide. Design Overflow: 1. Design and simulate the top level model in Simulink and Stateflow. 2. Use the Simulink HDL Coder to produce VHDL code. 3. Synthesize and implement the VHDL code in Xilinx ISE. 4. Deploy the .bit file produced using iMPACT in Xilinx ISE v9.2. Background: All the clock cycles are measured relative to the 50 MHz on board clock (LOC E12). The character codes to be displayed on the screen are stored in the Display Data Ram (DD-RAM). There are special addresses to store these characters: 0x00 to 0x0F (upper line) and 0x40 to 0x4F (lower line). We use the following commands to the DD RAM
1.

Set DD RAM Address: To initialize the address counter before reading/writing.

This command has the general form: LCD_RS LCD_RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 1 A6 A5 A4 A3 A2 A1 A0 A in A6-A0 stands for address-bit. A6-A0 can be either 0 or 1 and refer to one of the valid DD RAM addresses.
2.

Write Data to DD RAM:

The general form of this command is: LCD_RS LCD_RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 1 0 D7 D6 D5 D4 D3 D2 D1 D0 D in D7-D0 stands for the data-bit to be written to the DD RAM address. This could correspond to one of the LCD character sets in the CG ROM. The CG ROM contains certain pre-defined characters that can be displayed on the LCD. Here is the chart for determining the ASII code addresses of the stored characters (Please see the reference for details [1]):

Please note that the character sets are described in terms of Upper Data Nibble and Lower Data Nibble. These are used to print to the LCD screen using the 4-bit data interface, which has a totally different process. Since we are using the 8-bit interface, we can combine both the upper and lower nibbles. For example, the command Write Data to DD RAM for the character I can be sent as: 1001001001 (2 control bits (LCD_RS + LCD_RW) + 8 data bits)

Before writing to the LCD display, a set of commands must be issued to configure the LCD for the data write operation. These are: 1. Waiting: Wait for display to get ready after power-on. Value: 0x00 Execution Time: 15 ms = 750000 cycles

2. Function Set: This is used to set the number of display lines, the character font and the data length (in bits) Value used*: 0x3C Execution Time: 8.4 ms = 420000 cycles * Please note that some of the value used can be changed by setting the DB0 and DB1. Please refer to the user manual for details. 3. Set Display On: Turn the display on, cursor off and cursor position off. Value used: 0x0C Execution Time: 4.2 ms = 210000 cycles 4. Clear Display: Value used: 0x01 Execution Time: 4.2 ms = 210000 cycles 5. Entry Mode Set: This is a powerful command! It can be used to set the direction in which the cursor moves and to specify whether to shift the display or not. Value used: 0x06 Execution Time: 4.2 ms = 210000 cycles Once the LCD is configured for writing, the characters to be displayed can be transferred: 1. Char_h: Value: 0x48 Execution Time: 4.2 ms = 210000 cycles 2. Char_o: Value: 0x4F Execution Time: 4.2 ms = 210000 cycles

3. Char_l: Value: 0x4C Execution Time: 4.2 ms = 210000 cycles 4. Char_a: Value: 0x41 Execution Time: 4.2 ms = 210000 cycles After writing the characters, it is good to wait for additional 4.2 ms (210000 cycles) before exiting the program. It is also important to remember switching the values of the control signals. Here is a description of the three LCD control signals: Signal Name LCD_E FPGA Pin AB4 Description Read/ Write enable Values: 0: Disabled 1: Enabled for Read/ Write Register Select Values: 0: Instruction Register during write operation Busy flash during read operation* 1. Data for Read/ Write Read/ Write Control 0: Write data to LCD 1: Read data from LCD

LCD_RS

Y14

LCD_RW

W13

*Please refer to the user manual [1] for details.

Implementation: The entire write process can be represented in terms of state diagrams:
Waiting
LCD_E=0 LCD_RS=0 LCD_RW=0

T > 15 ms
T < 20 ns LCD_E=1 LCD_RS=0 LCD_RW=0

Initialize1
20 ns<T<8.4 ms LCD_E=0 LCD_RS=0 LCD_RW=0 LCD_E=1 LCD_RS=0 LCD_RW=0

Function_set
T=8.4 ms LCD_Data=0x3C

T > 8.4 m
Function_set
LCD_Data=0x3C T < 20 ns

T < 20 ns
T > 8.4 ms Initialize3
20 ns<T<8.4 ms LCD_E=0 LCD_RS=0 LCD_RW=0 T=8.4 ms LCD_E=1 LCD_RS=0 LCD_RW=0

Function_set
LCD_Data=0x3C

LCD_E=1 LCD_RS=0 LCD_RW=0

T < 20 ns

LCD_E=1 LCD_RS=0 LCD_RW=0

T > 8. LCD_E=1 LCD_RS=0 LCD_RW=0


T > 8.4 ms Initialize4 Function_set
20 ns<T<4.2 ms LCD_E=0 LCD_RS=0 LCD_RW=0 T=4.2 ms LCD_Data=0x3C LCD_E=1 LCD_RS=0 LCD_RW=0

T > 4.2 ms Set_display


T < 20 ns LCD_E=1 LCD_RS=0 LCD_RW=0 20 ns<T<4.2 ms LCD_E=0 LCD_RS=0 LCD_RW=0 LCD_Data=0x0C T=4.2 ms LCD_E=1 LCD_RS=0 LCD_RW=0

T > 4.2 ms

Clear_display
T < 20 ns LCD_E=1 LCD_RS=0 LCD_RW=0 20 ns<T<4.2 ms LCD_E=0 LCD_RS=0 LCD_RW=0

LCD_Data=0x01 T=4.2 ms LCD_E=1 LCD_RS=0 LCD_RW=0

T > 4.2 ms Entry_set


T < 20 ns LCD_E=1 LCD_RS=0 LCD_RW=0 20 ns<T<4.2 ms LCD_E=0 LCD_RS=0 LCD_RW=0 LCD_Data=0x06 T=4.2 ms LCD_E=1 LCD_RS=0 LCD_RW=0

T > 4.2 ms Char_h


T < 20 ns LCD_E=1 LCD_RS=1 LCD_RW=0 20 ns<T<4.2 ms LCD_E=0 LCD_RS=0 LCD_RW=0 LCD_Data=0x48 T=4.2 ms LCD_E=1 LCD_RS=1 LCD_RW=0

T > 4.2 ms
LCD_Data=0x4F T=4.2 ms LCD_E=1 LCD_RS=1 LCD_RW=0

Char_o
T < 20 ns LCD_E=1 LCD_RS=1 LCD_RW=0 20 ns<T<4.2 ms LCD_E=0 LCD_RS=0 LCD_RW=0

T > 4.2 ms Char_l


T < 20 ns LCD_E=1 LCD_RS=1 LCD_RW=0 20 ns<T<4.2 ms LCD_E=0 LCD_RS=0 LCD_RW=0 LCD_Data=0x4C T=4.2 ms LCD_E=1 LCD_RS=1 LCD_RW=0

T > 4.2 ms Char_a


T<4.2 ms LCD_E=0 LCD_RS=0 LCD_RW=0 T=4.2 ms LCD_E=1 LCD_RS=1 LCD_RW=0 LCD_Data=0x41

T > 4.2 ms Done


T<4.2 ms LCD_E=0 LCD_RS=1 LCD_RW=0 LCD_Data=0x00

We use Stateflow in Simulink to model the states and the state transitions. The attached zip file contains the model lcd_hola_sim.mdl which is the most direct implementation of the above flow diagram. When the model is run, the corresponding values of the LCD_E, LCD_RW, LCD_RS and LCD_DATA can be visualized in the scope block. The values of T1, T2, T3 and T4, which correspond to 15 ms, 20 ns, 4.2 ms and 8.4 ms, have been scaled down to reduce simulation time.

Figure 1: Simulation in Simulink

A note on Data types: The default data type in Simulink is double which is 64-bit precision floating-point. Since Spartan 3A will only work with fixed-point data types, all double and single data-types should be converted to equivalent fixed-point types.

To generate the HDL code, please follow these steps: 1. Remove the clock and the scope in lcd_hola_sim.mdl. Replace the scope with output ports. 2. The output LCD_DATA has to be converted to binary values to work on the FPGA. We use an Embedded MATLAB Function for this conversion.

Figure 2: HDL Code Generation in Simulink

The model lcd_hola.mdl is obtained after applying the above modifications. Click on Tools->HDL Coder->Generate HDL to generate the VHDL code. Before the code can be used for synthesis in Xilinx ISE, some additional changes need to be made to the generated VHDL file that corresponds to the binary convertor embedded MATLAB function block uint2bin. This is because this block produces a temporary variable of type real, which must be changed to integer. Here are the steps: 1. Remove the following function (Line # 39):
-- TMW_TO_UNSIGNED FUNCTION tmw_to_unsigned(arg: real; width: integer) RETURN unsigned IS BEGIN RETURN to_unsigned(integer(arg), width); END FUNCTION;

2. Change the following (Line # 55) :


VARIABLE argin_t_0 : real;

to:
VARIABLE argin_t_0 : integer;

3. Change the following lines (Line #72 and 73):


argin_t_0 := real(to_integer(argin_t)) - real(to_integer(c(n - 1))); argin_t := tmw_to_unsigned(argin_t_0, 8);

to:
argin_t_0 := to_integer(argin_t) - to_integer(c(n - 1)); argin_t := to_unsigned(argin_t_0, 8);

The generated code should now be ready to be synthesized on Xilinx ISE. The attached zip file contains the project built using Xilinx ISE v9.2.

Working in Xilinx ISE: This section is for those not familiar with Xilinx ISE. Following are the most straightforward way to synthesize, build and deploy the project to the FPGA board (Please refer to the ISE in depth tutorial for complete details [2]): 1. Open the project: lcd_eight_hola_spartan.ise. Double click on Synthesize-XST

2. Implement Design:

3. Configure the device:

4. Program the board: ISE should prompt this:

Right Click:

LCD display should print HOLA. Please ensure that the Clock enable switch is HIGH as specified in the constraint file (constraints.ucf). References: 1. Spartan 3A Starter Kit Board User Guide, Xilinx. 2. ISE In-depth Tutorial, Xilinx.