Sie sind auf Seite 1von 30

I/O (input / output) and Peripherals

Registers Ports (digital I / O) Polling Interrupts User input via switches / keypads Analog I / O (analog to digital (A/D) and digital to analog (D/A) converters

Registers
What is a register? A place to store data How? O1 Flip flops

D 0 1

Q(n+1) (Q after a clock edge) 0 1

O2

O3

On

clock I1 I2 I3 In

Ports

What is a port? A port is a connection to a digital computer (microprocessor). This connection provides a method to send or receive data from external devices. Herein, we will use the term port to describe a direct digital connection to a microprocessor as a mechanism to read, write and process external data.

Port Registers

ALL ports need at least 2 registers!

Control provides access for the modification of the ports functionality (e.g. select input or output, modes of operation) Data the register through which data passes on its route to the microprocessor. Status indicates the internal state of the port (often called flags)

Some have a third

An Example the Intel 8255 PPI

This chip provides three bi-directional 8-bit ports It is still in use today on PC I/O cards It is designed to provide digital I/O for microprocessors which have no built-in ports, (or those which require more ports for a specific application) Note: you are not responsible for knowledge of 8255 functionality this is an example only

Memory-Mapped Ports

With memory-mapped ports, the I/O registers behave like memory locations, responding to the same control signals as RAM and ROM chips Address lines control which register we are accessing, read and write lines control whether we are reading or writing the register

Memory Mapped I/O


CPU

System Bus: A0 A15, D0 D7, R, W

A0 A13 A14 A15 D0 D7

A0 A13 D0 D7

A0 A1 D0 D7 R, W

16K x 8
ROM
Chip Select

16K x 8
RAM
Chip Select

Status Reg
Command Reg Data Regs

2:4 Decoder
Not Used

Chip Select I/O lines

I/O Mapped Ports

On some processors, by adding extra control lines and extra instructions, an independent address space for I/O ports is provided (x86 / Pentium family included) ADVANTAGE: Slow I/O devices do not slow down the speed of memory accesses!

Programming Ports

As a programmer, what do you need to do to access a port?

Read the datasheet and figure out what is a command register, a status register, and a data register Write the command register to set the mode of operation (often includes the direction of the port) Read or write the data Determine when we can read or write the data again!

Example: Reading an 8051 Port

The 8051 has no command register for the ports, however, we need to set the direction. No initialization is necessary to use the port as an output. To use it as an input, we must (counter-intuitively) write a one to the port bit! Example: echo the switches on the leds in the simulator P2 = 0xff; // initialize port 2 as input P1 = P2;

Reading Input Data

When reading data, we have a problem. The data that is produced is often not synchronized with when we read it (asynchronous input). Either the data could be produced faster than we can consume it, or it could be produced slowly, so that we have to wait for it. If it is produced too slowly, we can opt to wait for it (Blocking) or we can keep going and check back later (Non-blocking) If it is produced too quickly, we can buffer it.

Polled I/O

When should we read asynchronous input data? IDEA: Continuously read the port in a tight loop sometimes called spin polling while(1) { P1 = P2; // read switches and output it to // leds }

Polling Issues

Biggest problem is that the processor wastes a LOT of time polling! It is possible to poll the port less often, at the risk of missing data. This is sometimes called timed polling. It is necessary to determine whether to block (keep polling until we have new data) on the read or not

Blocking Example
while(1) { // other code oldSwitchData = SwitchData; while(!NewData) { if(P1 != oldSwitchData) { SwitchData = P1; NewData = TRUE; } } // we only get here with new data! // more code }

Non-Blocking Example
while(1) { // other code // enter with previous switch data SwitchData = P1; // we get here with either new data or the old data // more code }

Buffering

For the Non-Blocking case, we can construct a buffer so that we dont miss any important data We will cover this in a bit more detail when we talk about sharing data between tasks when multitasking. The basic idea is that while one task gathers data as fast as possible (non-blocking) it sticks the data into a buffer. When the other task (the consumer of this data) needs this data, it can look into the buffer to find what it is looking for. Therefore, the consumer task can take data at a slower rate than it is gathered.

Summary

Polling (reading I/O in a continuous loop) can be either blocking or non-blocking If the polling loop blocks, it will not exit until the blocking condition is met. If the polling loop does not block, it is actually not a loop at all it just keeps going whether or not new data exists (although it may be part of a bigger application loop) Buffering allows for a slower consumption of data than it is produced.

Interrupt Driven I/O


When should we read the data? IDEA: Read the data when an external device tells us that there is new data to read by way of an INTERRUPT This allows us to synchronize the production and consumption of the data.

How Do Interrupts Work?

The basic idea is that an external input (a pin on a microprocessor) is asserted (set to a specific logic state) by the interrupting device. This signal tells the microprocessor to:

Complete the instruction it is currently executing Push the Program Counter (the address of the line of code currently executing) onto the stack Disable interrupts of equal (or lower) priority Load the Program Counter with the address of the Interrupt Vector Start executing code located at the address of the interrupt vector

8051 Interrupt Vectors

As mentioned in Lecture 1, the 8051 allows for 7 interrupt sources, shown in the table below, along with the interrupt vector address: How many bytes are allocated for each vector?

Interrupt
System Reset External 0 Timer 0 External 1 Timer 1 Serial Port Timer 2

Flag
RST IE0 TF0 IE1 TF1 RI or TI TF2 or EXF2

Vector Address
0000H 0003H 000BH 0013H 001BH 0023H 002BH

Interrupt Control Registers

In general, we will have some processor registers which allow the user to enable/disable specific interrupts. Often there is a global interrupt enable as well. On the 8051, we have the IE register. In addition, we have two bits in a register called TCON (Timer control) which controls the interrupt edge (high to low or low to high) and the interrupt type (level or edge) TCON.0 controls the edge (the bit symbol is IT0).

Bit

Symbol

Description 1=enable 2 = disable


Global Enable/Disable Undefined Enable Timer 2 Interrupt Enable Serial Port Interrupt

IE.7 IE.6 IE.5 IE.4

EA ET2 ES

IE.3
IE.2 IE.1 IE.0

ET1
EX1 ET0 EX0

Enable Timer 1 Interrupt


Enable External 1 Interrupt Enable Timer 0 Interrupt Enable External 0 Interrupt

8051 Interrupt Example-Read the A/D


ORG 0 SJMP main ORG 3 SJMP ext0ISR ORG 30H main: SETB IT0 SETB EX0 CLR P0.7 SETB ea CLR P3.6 SETB P3.6 loop: SJMP loop ; set external 0 interrupt as edge-activated ; enable external 0 interrupt ; enable DAC WR line ; set the global interrupt enable bit ; clear ADC WR line ; then set it - this results in the required positive edge ; to start a conversion ; jump back to the same line (ie: do nothing) ; end of main program ; external 0 ISR - responds to the ADC conversion complete interrupt ext0ISR: CLR P3.7 MOV P1, P2 SETB P3.7 CLR P3.6 SETB P3.6 RETI ; clear the ADC RD line - this enables the data lines ; take the data from the ADC on P2 and send it to the DAC data lines on P1 ; disable the ADC data lines by setting RD ; clear ADC WR line ; then set it - this results in the required positive edge to start a conversion ; return from interrupt ; reset vector ; jump to the main program ; external 0 interrupt vector ; jump to the external 0 ISR ; main program starts here

8051 Interrupts In C (Keil compiler)


#pragma code #pragma NOAREGS #include <REG52.H> // special function register declarations // for the intended 8051 derivative

void Initialize(); void StartConversion(); void main() { Initialize(); StartConversion(); // wait for the end of conversion while(1) ; }

Interrupts in C (subroutines)
void Initialize() { IT0 = 1; EX0 = 1; P0 &= B8(01111111); EA = 1; } // set external 0 interrupt as edge-activated // enable external 0 interrupt // enable DAC WR line // set the global interrupt bit

void StartConversion() { // start the next conversion P3 &= B8(10111111); // clear ADC WR line P3 |= B8(01000000); // then set it - this results in the required positive edge to start a conversion }

static void NewAtoDSample() interrupt 0 using 1 { P3 &= B8(01111111); P1 = P2; P3 |= B8(10000000); // clear the ADC RD line - this enables the data lines // take the data from the ADC on P2 and send it to the DAC data lines on P1 // disable the ADC data lines by setting RD

// start the next conversion StartConversion(); }

The I/O Subsystem

Each I/O device driver supplies a driverspecific set of I/O application programming interfaces (APIs) to the applications This will provide a uniform set of functions for I/O The number of functions, their names and functionality is dependent on the implementation, but an example will follow.

Example I/O API with a driver

The I/O subsystem-defined API set is mapped to a function set that is specific to the device driver that supports the I/O
UNIFORM_IO_DRV tty10drv;

typedef struct { int (*Create) ( ); int (*Open) ( ); int (*Read) ( ); int (*Write) ( ); int (*Close) ( ); int (*Ioctl) ( ); int (*Destroy) ( ); } UNIFORM_IO_DRV

TTY10drv.Create = tty_Create; TTY10drv.Open = tty_Open; TTY10drv.Read = tty_Read; TTY10drv.Write = tty_Write; TTY10drv.Close = ttv_Close; TTY10drv.Ioctl = tty_Ioctl; TTY10drv.Destroy = tty_Destroy;

I/O API Functions


Function Create Destroy Open Close Functionality Creates a virtual instance of an I/O device Deletes a virtual instance of an I/O device Prepares an I/O device for use Communicates to the device that its services are no longer required, which typically initiates device-specific cleanup operations. Reads data from an I/O device Writes data into an I/O device Issues control commands to the I/O device (I/O control)

Read Write Ioctl

I/O Driver Table

Any driver can be installed into or removed from this driver table by using the utility functions that the I/O subsystem provides Each row in the table represents a unique I/O driver that supports the defined API set. The first column of the table is a generic name used to associate the uniform I/O driver with a particular type of device. A uniform I/O driver is provided for a serial line terminal device, tty. The table element at the second row and column contains a pointer to the internal driver function, tty_Create().

Associating Devices with Device Drivers

Each entry in the device table holds generic information, as well as instance-specific information. The generic part of the device entry can include the unique name of the device instance and a reference to the device driver. A device instance name is constructed using the generic device name and the instance number. The device named tty0 implies that this I/O device is a serial terminal device and is the first instance created in the system. The driver-dependent part of the device entry is a block of memory allocated by the driver for each instance to hold instance-specific data. The driver initializes and maintains it. The content of this information is dependent on the driver implementation. The driver is the only entity that accesses and interprets this data. A reference to the newly created device entry is returned to the caller of the create function. Subsequent calls to the open and destroy functions use this reference.

Next week

Lab 1!!! Now is the time to start trying to write the 3 programs!

Das könnte Ihnen auch gefallen