PS/2 and JTAG UART Interfaces

Transcription

PS/2 and JTAG UART Interfaces
PS/2 and JTAG UART Interfaces
Updated: February 2014
1.
Introduction
This document presents an overview of the tools and two IP cores from Altera. In this
lesson, we will discuss two interfaces:
 PS2
 JTAG UART
2.
Design of an Embedded System on an FPGA Device: A Review
Let us quickly review the design procedure to interface with a new hardware device.
We designed and implemented a hardware controller to interface with a device at the
physical hardware level in lab 1 (PS/2 keyboard controller). At system and application
level, we integrated the hardware controller into an embedded system (nios_system) and
developed a software application to interface with the device in lab 2. Labs 1 and 2 have
illustrated the concept of developing an interfacing core that communicates with I/O
devices. The same concept can be applied to most peripherals and can be summarized
as:
i. Developing a hardware controller in hardware description language. This step
requires knowledge of
o Input and output signals
o Timing requirement
ii.
o Communication protocol, etc.
Developing a wrapper interface so that the hardware controller can be integrated
into a Nios system in Qsys. This step can be done by
o Using a PIO core (as in lab 2) or
o Using a custom core for the controller (built-in or developed).
iii.
Developing a software application (or drivers) to utilize the device. Application
can be written in
o Assembly programming language, or
o C programming language.
The first step (step i) is a time consuming task. Fortunately, Altera provides a set of IP
cores that are ready to be integrated into a Nios system. So, instead of developing an
1
I/O interfacing core from scratch for every device, we will use the provided IP cores (if
available). This lesson mainly focuses steps ii and iii above. Specifically, we will learn
how to utilize two pre-built IP cores from Altera in our applications.
3.
DE2-70 Media Computer
Before we develop any application in C, we need to develop the hardware system. This
task is done using Qsys tool as you have seen in the tutorial and lab 2. To save time
from creating, generating, port mapping, and compiling a system every time we have a
new project, we will use a provided system from Altera University Program (AUP).
This system is known as the DE2-70 Media Computer which includes most of the
standard I/O devices that can be used to perform different experiments in this class.
3.1.
System Overview
The block diagram of the DE2-70 Media Computer is shown in Fig. 1. The main components include the Altera Nios-II processor, SRAM, SDRAM and on-chip
memory for program and data storage, an audio-in/out port, a video-out port with
both pixel and character buffers, a PS/2 serial port, a 16×2 character display, parallel
ports connected to switches and lights, a timer module, and an RS 232 serial port.
Fig. 1. Block diagram of the DE2-70 Media Computer [1].
2
A screenshot of the DE2-70 Media Computer in Qsys is shown in Fig. 2.
Fig. 2. Screen shot of the DE2-70 Media Computer in Qsys.
Question: Will your C program from assignment 2 (the tutorial) work with this system?
No. You will need to modify the base addresses.
Note that this system has been verified to work correctly. You will not need to generate,
port map, or compile the system.
3.4
PS2 Core
Let’s first look at the PS2 core in the DE2_70 Media Computer since we have completed
2 labs dealing with a PS2 keyboard. The PS2 Core handles the timing of the PS2 Serial
Data Transmission Protocol. A driver function or an application can communicate with
3
the device by reading from and writing to its data and control registers. The core comes
with a 256-word First-In-First-Out (FIFO) buffer for storing data received from a PS2
device. A block diagram illustrating connections in an embedded system is shown in
the figure below. Note that the processor does not access to the FIFO buffer or the
controller directly.
Altera FPGA
PS2 Core
Registers
FIFO
Data
NIOS-II
Processor
PS2 connector
Controller
Control
Fig. 3. Interfacing a Nios-II processor with a PS2 Core.
Data and Control Registers
Device drivers or user applications communicate with the PS2 Core through two 32-bit
registers as shown in Table 1.
Table 1. PS2 core register map [2].
(1) Reserved. Read values are undefined. Write zero.
The fields in the data register are explained in Table 2. The PS2 Data register is both
readable and writable. When bit 15, RVALID, is 1, reading from this register provides
the data at the head of the FIFO in the Data field, and the number of entries in the FIFO
(including this read) in the RAVAIL field. When RVALID is 1, reading from the PS2
4
Data register decrements this field by 1. Writing to the PS/2 Data register can be used to
send a command in the Data field to the PS2 device.
Table 2. Data register of the PS/2 core [2].
The fields in the control register are explained in Table 3. The PS2 control register can
be used to enable interrupts from the PS2 port by setting the RE field to the value 1.
When RE field is set, the PS2 port generates an interrupt when RAVAIL > 0. While the
interrupt is pending the field RI will be set to 1, and it can be cleared by emptying the
PS2 port FIFO. It means that will need to read all data in the FIFO buffer before exiting
the interrupt service routine (clear the interrupt). The CE field in the PS/2 control
register is used to indicate that an error has occurred when sending a command to a PS2
device. In this class, we will mainly deal with receiving data from a PS2 device.
Table 3. Control register of the PS/2 core [2].
Question: What register should a user program communicate with when polling
method is used?
Data register
5
Example: Complete the C program below to read valid data from a PS2 device and
display the data on the red LEDs of the DE2 Media Computer. Use polling method.
#define LEDR_BASE_ADR
#define PS2_KB_BASE_ADR
0x10000000
0x10000100
//Main function
int main(void)
{
volatile int *LEDR_ptr
volatile int *PS2_KB_ptr
int ps2;
= (int *) LEDR_BASE_ADR; // LEDR ip core
= (int *) PS2_KB_BASE_ADR; // PS2_KB ip core
// temporary storage
while(1) // loop forever
{
ps2 = *(PS2_KB_ptr);
if ( ((ps2 & 0xFFFF0000) >> 16) > 0x0) // check RAVAIL field
*(LEDR_ptr) = (ps2 & 0x000000FF); // output data to red leds
}
return 0;
}
Question: Why do we need to use the ps2 variable in the previous example? In other
words can we replace the while loop with
while(1) // loop forever
{
if ( ((*PS2_KB_ptr & 0xFFFF0000) >> 16) > 0x0)
*(LEDR_ptr) = (*PS2_KB_ptr & 0x000000FF);
}
*PS2_KB_ptr indicates a read operation
 two read operations are performed by the if statement
 one byte is lost every time the if statement is executed.
PS2 Core Interrupt


PS2 core setup in Qsys:
o This control register is automatically generated when a PS2 core is added
to the system.
PS2 core setup in C program:
o Bit 0 (RE bit) in the control register is set to 1.

Nios-II processor setup in C program:
o Set the interrupt enable bit for the PS2 core IRQ level in register 3 (ienable
register) of the Nios-II processor to 1.
6


o Set the global interrupt enable bit in register 0 (status register) of the NiosII processor to 1.
Setup the interrupt service routine (ISR) in C program:
o Include the “exception.h” file
o In the interrupt_handler function, check register 4 (ipending register) and
call the appropriate ISR function.
o Develop an ISR function to deal with an interrupt event and to clear the
interrupt.
Setup the Altera Monitor Program:
o Reserve space for the exception and reset functions at the top of the
memory space.
Example: Complete the C program below to read valid data from a PS2 device and
display the data on the red LEDs of the DE2 Media Computer. Use interrupt method.
#include "exception.h"
#define LEDR_BASE_ADR 0x10000000
#define PS2_KB_BASE_ADR 0x10000100
//Main function
int main(void)
{
int *PS2_KB_ptr
= (int *) PS2_KB_BASE_ADR ;
// PS2_KB ip core
// PS2 Core Setup for interrupt
*(PS2_KB_ptr + 1) = 0x01; // set RE = 1 to enable interrupt
// Enable individual components and global interrupt bit (Nios side)
__builtin_wrctl(3, 0x80); //Enable IRQ7 level
__builtin_wrctl(0, 1);
//Write 1 into status register
while(1) // loop forever
{} // do nothing, wait for interrupt
return 0;
}
// interrupt handler function --> handle all interrupt events
void interrupt_handler(void)
{
int ipending;
ipending = __builtin_rdctl(4);
//Read the ipending register
if ((ipending & 0x80) > 0)
ps2_kb_isr();
//If irq7 is high, run ps2_kb_isr()
return;
}
7
// ps2 keyboard interrupt service routine
void ps2_kb_isr(void)
{
int *PS2_KB_ptr
= (int *) PS2_KB_BASE_ADR ;
int *LEDR_ptr
= (int *) LEDR_BASE_ADR;
*LEDR_ptr = (*PS2_KB_ptr & 0x000000FF);
// PS2_KB ip core
// output data to red leds
return;
}
Question: Why don’t we need to use the ps2 variable in the interrupt example?
Because we don’t have to check for valid data in the data register  only
one read operation is needed.
3.4
JTAG UART Core
A simple and commonly used scheme for transferring data between a processor and an
I/O device is known as the Universal Asynchronous Receiver Transmitter (UART). A UART
interface (circuit) is placed between the processor and the I/O device. It handles data one 8bit character (ASCII code) at a time.
We will use a JTAG UART core (named JTAG_UART in the DE2 Media Computer) to
establish a connection between a Nios II processor and the host computer connected to
the DE2_70 board. Fig. 2 shows a block diagram of the JTAG UART circuit. On one side
the JTAG UART connects to the Avalon switch fabric, which interconnects the Nios II
processor, the memory chips, and the I/O interfaces. On the other side it connects to the
host computer via the JTAG port using an USB-Blaster cable. The JTAG UART core
contains two registers: Data and Control, which are accessed by the processor as
memory locations. The core also contains two 64-character FIFOs that serve as storage
buffers, one for queuing up the data to be transmitted to the host and the other for
queuing up the data received from the host.
A block diagram illustrating connections in an embedded system is shown in the figure
below. Note that the processor does not access to the FIFO buffer or the controller
directly.
8
Nios-II
processor
Fig. 4. Block diagram for JTAG UART circuit [3].
Data and Control Registers
Device drivers or user applications communicate with the JTAG UART core through
two 32-bit registers as shown in the table below.
Table 4. JTAG UART core register map
Reserved space: Read values are undefined. Write zero.
The fields in the data register are explained in Table 5. When bit 15, RVALID, is 1,
reading from this register provides the character (ASCII code) at the head of the FIFO in
the Data field, and the number of entries in the FIFO (after this read) in the RAVAIL
9
field. When RVALID is 1, reading from the PS2 data register decrements this field by 1.
Writing to the data register stores the ASCII value in the write FIFO. If the write FIFO is
full, the character is lost.
Table 5. JTAG UART data register bits [3].
The fields in the control register are explained in Table 6. The JTAG UART control
register can be used to enable read or write interrupts from the JTAG UART port by
setting the RE (for Read interrupt) or WE (for Write interrupt) field to the value 1.
Table 6. JTAG UART control register bits [3].
When RE field is set, the JTAG UART port generates an interrupt whenever the read
FIFO is nearly full. The nearly full threshold value is specified at system generation time
in Qsys and cannot be changed by the C program. The read threshold value (rtv) is set to 8
in the DE2-70 Media Computer as shown in Fig. 5. The read interrupt condition is set
whenever the read FIFO has rtv or fewer empty spaces remaining. The read interrupt
condition is also set if there is at least one character in the read FIFO and no more
characters are expected. While the interrupt is pending the field RI will be set to 1, and
it can be cleared by reading characters from the data register.
10
The JTAG UART port also can assert a write interrupt whenever the write FIFO is
nearly empty. The write threshold value (wtv) is specified at system generation time in
Qsys and cannot be changed by the C program. The wtv is set to 8 in the DE2-70 Media
Computer as shown in Fig. 5. The write interrupt condition is set whenever there are
wtv or fewer characters in the write FIFO. If it has no characters remaining to send, the
application program should disable the write interrupt. While the interrupt is pending
the field WI will be set to 1, and it is cleared by writing characters to the data register to
fill the write FIFO beyond the wtv.
Fig. 5. Write threshold value (wtv) and read threshold value (rtv) setup.
We will mostly deal with the polling method for the JTAG UART port in the DE2-70
Media Computer.
Using JTAG UART Core in Altera Monitor Program
The JTAG_UART core can be used to display text messages (i.e. for troubleshooting) in
the terminal window of the Altera Monitor Program. The terminal window can also be
used to and to read in ASCII characters from the host computer via the JTAG_UART
core. To establish this type of communication, you will need to set the Terminal
device as JTAG_UART under the System Settings tab as shown in Fig. 6. The
output from the JTAG UART core will be displayed in the terminal window. While the C
11
program is running, you will need to click inside the terminal window to read input
characters from the JTAG UART core. An example is shown in Fig. 7.
Fig. 6. JTAG UART setup in Altera Monitor Program.
Fig. 7. An example using JTAG UART core in the Altera Monitor Program.
12
Example: Complete the put_jtag function in the C program below to display the
character c in the terminal using the JTAG UART core. Your function should check for
WSPACE field. Print/Output c only if WSPACE > 0 (available spaces in the write FIFO).
See example program below.
Example: Complete the while loop in the C program below to read in a character c in the
terminal using the JTAG UART core. Use polling technique to check for valid input.
See example program below.
//Base Addresses from DE2-70 Media Computer
#define JTAG_UART_BASE_ADR 0x10001000
/* function prototypes */
void put_jtag(volatile int *, char);
//Main function
int main(void)
{
volatile int * JTAG_UART_ptr = (int *) JTAG_UART_BASE_ADR; //base address
int i, data;
char text_string[] = "\n EC463 JTAG UART example: \n> \0";
/* print a text string */
for (i = 0; text_string[i] != 0; i++)
put_jtag (JTAG_UART_ptr, text_string[i]);
while(1)//main loop
{
data = *(JTAG_UART_ptr); // read the JTAG_UART data register
if (data & 0x00008000)
// check RVALID bit
{
data = data & 0x000000FF;
// extract data byte
put_jtag (JTAG_UART_ptr, (char)data ); // output data byte
}
}
return 0;
}
//Subroutine to send a character to the JTAG UART
void put_jtag( volatile int * JTAG_UART_ptr, char c )
{
if (*(JTAG_UART_ptr + 1) & 0xFFFF0000) // if WSPACE > 0,
*(JTAG_UART_ptr) = c;
// then print the character, else ignore
}
13
4.
Exercise
Use an interrupt method to interface with a PS2 keyboard via the PS2 core of the DE2-70
Media Computer. Convert the make code of the numeric (0 – 9), ‘-‘, ‘+’, and enter keys to
ASCII codes and display them in the Altera Monitor Program terminal. Other scan
codes should be converted ASCII value of ‘E’.
5.
References:
[1].
Altera, “Media Computer System for the Altera DE-70 Board,” for Quartus II
v.13.0, May 2013.
Altera, “PS/2 Core for Altera DE-Series Boards,” for Quartus II v.13.0, May 2012.
Altera, “Chapter 6: JTAG UART Core,” in the Embedded Peripheral IP User Guide,
June 2011.
[2].
[3].
14