Beruflich Dokumente
Kultur Dokumente
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
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
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)
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
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
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
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!
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;
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.
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.
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
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
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
EA ET2 ES
IE.3
IE.2 IE.1 IE.0
ET1
EX1 ET0 EX0
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
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.
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;
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().
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!