The final lab project will be designing an interface between
a magnetic card stripe reader and an LCD (liquid crystal display). You will work with a partner for the final
project which is separated into two parts.
In this first part, you will design a simple LCD controller using three
22V10 PALs and behavioral Verilog. In the second part (next week) you will
add the interface to magnetic card stripe reader. You will complete the first part by the end
of next week’s lab, and complete the entire project by
You are now familiar with two very powerful tools: ActiveHDL
and behavioral Verilog, and you will employ them both extensively in order to
complete this assignment. You are also familiar with the design process where
you fully design and simulate a circuit before you try to construct it.
This lab assignment is definitely more challenging than the previous ones, and
you may not be able to finish within the first lab session. However, this time
you will have an extra week to complete the assignment.
In these last two labs, you’ll be using the FPGA on your board to generate a variable-rate clock signal (to ensure proper initialization of the LCD and reading of the magnetic stripes) and to debug your circuit. To do this, you need to configure the FPGA to run in a special mode for these final two labs.
To configure the FPGA for use with the final labs:
If you need any assistance with
configuring the FPGA for these last two labs, please ask!
Your goal is to design a circuit which can write an
arbitrary ASCII character code entered on your prototyping switches to an LCD
display. (In the next lab, characters will be come from the magnetic card
stripe reader.) Three PALs will be required to implement this interface: a data
buffer, an LCD command "table" and a main control
As you can see in the figure below, both commands and data
are sent to the display. The commands
are used to initialize the display and tell it what to do, and the data is the
character to be displayed. The control
Only the main controller is sequential. The data buffer and command table are very simple and are implemented with merely combinational logic.
The LCD which you will be using has many advanced functions (see the datasheet for a complete explanation), but you will only be concerned with the following two:
The pin layout of the LCD follows:
Pin |
Name |
Function |
1 |
GND |
0 V |
2 |
Vdd |
5 V |
3 |
Vo |
1 V |
4 |
RS |
High: Data input Low: Instruction input |
5 |
R/W |
High: Read from LCD Low: Write to LCD |
6 |
E |
Enable the LCD |
7 |
DB0 |
Data bus |
8 |
DB1 |
|
9 |
DB2 |
|
10 |
DB3 |
|
11 |
DB4 |
|
12 |
DB5 |
|
13 |
DB6 |
|
14 |
DB7 |
Pins 1-3 are power supply connections and will be explained
later. Pins 4-14 are signals that you must supply. R/W specifies whether
you are reading or writing the display: Since you will only be writing to the
display, the R/W signal will always be 0. RS is used to determine whether you
are sending a command or ASCII data to the display. E (enable) is used to
provide a strobe that causes the operation to be executed. The enable, E,
for the LCD is a signal that you must generate: the LCD commits a new character
or command on the negative edge of E (something to think about: how do you give
E a negative edge?). Note that the
timing diagrams in the datasheet indicate that RS and E cannot change at the
same time. The data pins contain either an ASCII character code or a
command code depending upon the value of RS. You will need to multiplex this
data bus between an instruction source and a data source using tri-state
drivers in the
The following is a table with the codes for the 5 commands that you need to execute for this assignment. The first four should be executed in sequence once after reset has been pushed. The last command is used to write a character to the display. You can look at the documentation if you would like to try out other commands.
Operation |
RS |
DB[7:0] |
Clear Display |
0 |
0000 0001 |
Function Set |
0 |
0011 0011 |
Display On |
0 |
0000 1100 |
Entry Mode Set |
0 |
0000 0110 |
Write Character |
1 |
DDDD DDDD |
Your "main controller"
Finally, you will need to set the contrast for the LCD screen. For this, we have to apply a specific voltage at the Vo pin. We can do so with the voltage divider circuit shown in the figure below. It will generate a voltage Vo of approximately 1/(1+4) of Vdd or 20% of 5V (1V). In your kit should be a 3.9K ohm resistor and a 1K ohm resistor (If there aren't any in your kit, they are also on the conference table). You can determine the resistance value of a resistor by the color coded bands on the resistor (see explanation of how the color coded system works).
The following Verilog implements an 8-bit tri-state driver which will serve your purposes for this assignment. You are encouraged to use an intuitive pin assignment. The provided file tri_driver.ctl will do just fine. Note how "turning off" the output of a pin is expressed in Verilog: rather than assigning 0 or 1 to the output, we assign a z, which stands for "not driven". This distinction between no voltage and some voltage is key to understanding this concept. Make sure you understand what each of the three possible states of the output means before moving on with the lab (your output is either (a) off, no voltage, (b) on and a voltage representing a 0, and (c) on and a voltage representing a 1).
module
tri_driver (en, from, to);
input en;
input [7:0] from;
output [7:0] to;
assign to = (en) ? from : 8'bzzzzzzzz;
endmodule
The following is a do-nothing stub which you will need to
complete for the command table. Again, a sane pin assignment is highly
recommended (use lcd_cmd.ctl). Remember that,
since you will wire the outputs of the 8-bit tri-state driver together with the
outputs of this
module
lcd_cmd (RS, cmdIndex, lcdCMD);
input
RS;
// Used to tristate the LCD CMD
input [1:0] cmdIndex; // Index of the command
output [7:0] lcdCMD; // LCD command
/* YOUR CODE HERE */
endmodule
Here is another module which you will need to complete. Note: Before you start writing this module, draw a complete, correct state diagram for its finite state machine. You will be asked to turn in the state diagram, and it definitely pays to carefully think about the exact timing of your finite state machine in this traditional manner before beginning to write the code for it. We strongly advise you to draw a detailed timing diagram so that you understand how to generate the different signals. Pay particular attention to the timing of the RS and EN signals and use the LCD test fixture to make sure you've got it right. Read the tips section below for some ideas that may help in implementing the LCD controller.
You will need to write your own pin assignment file for this chip.
module
lcd_control (clk, reset, write, EN, RS, CMD);
input clk, reset;
input write; // Write a character to the
LCD
output EN, RS; // Enable, RS signals of LCD
output [1:0] CMD; // Index for current LCD command
/* reg [??:??] state; */
/* YOUR DECLARATIONS
always @(posedge clk) begin
/* YOUR SYNCHRONOUS CODE GOES HERE */
end
endmodule
You must verify your final circuit design before actually programming your PALs and wiring it. As mentioned above, we use a variable-rate clock signal in these labs, which can be simulated with the fpga_clock_sim.v module and will provide you with the clock and reset signals to use. Use the LCD test fixture lcd_tf.v to simulate the behavior of the LCD entirely within ActiveHDL. Now that you are beginning to understand behavioral Verilog, you might want to read and understand the behavior of the test fixture if that of the LCD itself is not clear to you. Note that this test fixture is not like some of those that you've worked with in the past. It does not exhaustively test your design for all possible (or any) inputs. It merely simulates an LCD and writes characters to the ActiveHDL console when properly used, so you will be responsible for anticipating, handling, and verifying all of the interesting "boundary conditions" for your design.
Note: Since the
clock signal provided by fpga_clock_sim.v matches that of the real FPGA, you
need to run the simulation for at least 9.4 ms in order for you to see if the
LCD correctly initializes.
After successful simulation of your design, program your
PALs, and wire up the full circuit. Be prepared to reprogram a chip for a
bug fix, and wire accordingly. In other words, try to wire as neatly as
possible, and try to do so such that your chips may be extracted from the
circuit without significant rewiring. Consider ways in which you might be
able to use fewer wires for the LCD's data bus. Also remember that
careful construction of your
Full credit completion of this assignment will include all of the following by the given due date: