Title: The UART project
1The UART project
- Applying what weve learned about Linux
device-drivers to the PCs serial-port controller
2Projects purpose
- Allow you to gain experience encountering the
kinds of issues that commonly arise in crafting
software to operate real hardware - Learning the hardware devices capabilities
- Deciding which driver-methods to implement
- Accommodating your platforms interfaces
- Exploiting the OS kernels support-functions
- Devising a strategy for testing and debugging
3Universal Asynchronous Receiver-Transmitter
(UART)
See our CS635 course website at
lthttp//cs.usfca.edu/cruse/cs635f07gt for links
to the UART manufacturers documentation and to
an in-depth online programming tutorial
4Tx and Rx
- The UART has a transmission-engine, and also a
reception-engine, which are able to operate
simultaneously (i.e., full-duplex) - Software controls the UARTs operations by
accessing several registers, using the x86
processors in and out instructions - Linux provides some convenient macros that
hide the x86 machine-code details
5PC-to-PC communications
student workstation
student workstation
KVM cable
KVM cable
rackmount PC system
rackmount PC system
null-modem serial cable
ethernet cables
6Using echo and cat
- Your device-driver module (named uart.c) is
intended to allow unprivileged programs that are
running on a pair of adjacent PCs to communicate
via a null-modem cable
Receiving
Transmitting
echo Hello gt /dev/uart _
cat /dev/uart Hello _
7Kudlick Classroom
08
09
10
15
16
17
18
19
20
28
29
30
04
05
06
07
11
12
13
14
24
25
26
27
01
02
03
21
22
23
lectern
Indicates a null-modem PC-to-PC serial cable
connection
8Linux char-driver components
Device-driver LKM layout
modules payload is a collection of
callback-functions having prescribed
prototypes
function
function
function
AND a package of
function-pointers
fops
. . .
init
the usual pair of module-administration
functions
registers the fops
exit
unregisters the fops
9Requires a device-file node
- Our System Administrator has created the
device-file needed for your driver-module root
mknod /dev/uart c 84 0 root chmod aw
/dev/uart - Your driver-module needs to register your
package of driver-methods (i.e., functions) in
its initialization routine (and unregister them
later in its cleanup routine)
10write() and read()
- Obviously your driver-modules payload will
have to include methods (functions) which
perform the write() and read() operations
that applications will invoke - You may decide your driver needs also to
implement certain additional methods - A little history is helpful for understanding
some of the UART devices terminology
11DCE and DTE
- Original purpose of the UART was for PCs to
communicate via the telephone network - Telephones were for voice communication (analog
signals) whereas computers need so exchange
discrete data (digital signals) - Special communication equipment was needed for
doing the signal conversions (i.e. a
modulator/demodulator, or modem)
12PC with a modem
computer terminal
modem
serial cable
Data Communications Equipment (DCE)
Data Terminal Equipment (DTE)
phone wire
13Serial data-transmission
The Transmitter Holding Register (8-bits)
Software outputs a byte of data to the
THR The bits are immediately copied into an
internal shift-register The bits are
shifted out, one-at-a-time, in sync with a
clock-pulse
0
1
1
0
0
0
0
1
0
1
1
0
0
0
0
1
1-0-1-1-0-0-0-0-1-0
data-bits
The transmitters internal shift register
clock
start bit
stop bit
clock-pulses trigger bit-shifts
14Serial data reception
input voltage
clock
clock-pulses trigger voltage-sampling and
bit-shifts at regular intervals
The receivers internal shift register
0
1
1
0
0
0
0
1
1-0-1-1-0-0-0-0-1-0
data-bits
start bit
stop bit
Software can input the received byte from the
RBR
0
1
1
0
0
0
0
1
The Receiver Buffer Register (8-bits)
15Normal 9-wire serial cable
1
1
Carrier Detect
6
6
Data Set Ready
Rx data
Request To Send
Tx data
Clear To Send
Data Terminal Ready
Ring Indicator
9
9
Signal Ground
5
5
16Signal functions
- CD Carrier Detect The modem asserts this signal
to indicate that it successfully made its
connection to a remote device - RI Ring Indicator The modem asserts this signal
to indicate that the phone is ringing at the
other end of its connection - DSR Data Set Ready Modem to PC
- DTR Data Terminal Ready PC to Modem
17Signal functions (continued)
- RTS Request To Send PC is ready for the modem to
relay some received data - CLS Clear To Send Modem is ready for the PC to
begin transmitting some data
189-wire null-modem cable
CD
CD
RxD
RxD
TxD
TxD
GND
GND
DSR
DSR
DTR
DTR
RTS
RTS
CTS
CTS
RI
RI
Data Terminal Equipment
Data Terminal Equipment
no modems
19The 16550 UART registers
Divisor Latch Register
Base0
16-bits (R/W)
Transmit Data Register
Base0
8-bits (Write-only)
Received Data Register
Base0
8-bits (Read-only)
Interrupt Enable Register
Base1
8-bits (Read/Write)
Interrupt Identification Register
Base2
8-bits (Read-only)
FIFO Control Register
Base2
8-bits (Write-only)
Line Control Register
Base3
8-bits (Read/Write)
Modem Control Register
Base4
8-bits (Read/Write)
Line Status Register
Base5
8-bits (Read-only)
Modem Status Register
Base6
8-bits (Read-only)
Scratch Pad Register
Base7
8-bits (Read/Write)
20Rate of data-transfer
- The standard UART clock-frequency for PCs equals
1,843,200 cycles-per-second - Each data-bit consumes 16 clock-cycles
- So the fastest serial bit-rate in PCs would be
1843200/16 115200 bits-per-second - With one start bit and one stop bit, ten bits
are required for each byte of data - Rate is too fast for teletype terminals
21Divisor Latch
- The Divisor Latch may be used to slow down the
UARTs rate of data-transfer - Clock-frequency gets divided by the value
programmed in the Divisor Latch register - Older terminals often were operated at a baud
rate of 300 bits-per-second (which translates
into 30 characters-per-second) - So Divisor-Latch was set to 0x0180
22How timing works
Transmitter clock (bit-rate times 16)
DATA OUT
start-bit data-bit 0
data-bit 1
24 clock-cycles
16 clock-cycles
16 clock-cycles
sample
sample
Receiver clock (bit-rate times 16)
receiver detects this high-to-low transition,
so it waits 24 clock-cycles, then
samples the data-lines voltage every 16
clock-cycles afterward
23Programming interface
The PC uses eight consecutive I/O-ports to access
the UARTs registers
0x03F8 0x03F9 0x03FA 0x03FB
0x03FC 0s03FD 0x03FE 0x03FF
RxD/TxD
IER
IIR/FCR
LCR
MCR
LSR
MSR
SCR
modem status register
line status register
interrupt enable register
modem control register
line control register
scratchpad register
receive buffer register and transmitter holding
register (also Divisor Latch register)
interrupt identification register
and FIFO control register
24Modem Control Register
7 6 5 4
3 2 1 0
0
0
0
LOOP BACK
OUT2
OUT1
RTS
DTR
Legend DTR Data Terminal Ready (1yes,
0no) RTS Request To Send (1yes, 0no)
OUT1 not used (except in loopback mode)
OUT2 enables the UART to issue interrupts
LOOPBACK-mode (1enabled, 0disabled)
25Modem Status Register
7 6 5 4
3 2 1 0
DCD
RI
DSR
CTS
delta DCD
delta RI
delta DSR
delta CTS
set if the corresponding bit has changed since
the last time this register was read
Legend ---- loopback-mode ---- CTS
Clear To Send (1yes, 0no) bit 0 in Modem
Control DSR Data Set Ready (1yes, 0no)
bit 1 in Modem Control RI Ring
Indicator (1yes,0no) bit 2 in Modem Control
DCD Data Carrier Detected (1yes,0no) bit 3
in Modem Control
26Line Status Register
7 6 5 4
3 2 1 0
Error in Rx FIFO
Transmitter idle
THR empty
Break interrupt
Framing error
Parity error
Overrun error
Received Data Ready
These status-bits indicate errors in the received
data
This status-bit indicates that the data-transmissi
on has been completed
This status-bit indicates that the
Transmitter Holding Register is ready to accept
a new data byte
This status-bit indicates that a new byte of data
has arrived (or, in FIFO-mode, that the
receiver-FIFO has reached its threshold)
27Line Control Register
7 6 5 4
3 2 1 0
Divisor Latch access
set break
stick parity
even parity select
parity enable
number of stop bits
word length selection
00 5 bits 01 6 bits 10 7 bits 11 8 bits
0 1 stop bit 1 2 stop bits
0 normal 1 break
0 no parity bits 1 one parity bit
0 not accessible 1 assessible
1 even parity 0 odd parity
28Interrupt Enable Register
7 6 5 4
3 2 1 0
0
0
0
0
Modem Status change
Rx Line Status change
THR is empty
Received data is available
If enabled (by setting the bit to 1), the UART
will generate an interrupt (bit 3) whenever
modem status changes (bit 2) whenever a
receive-error is detected (bit 1) whenever the
transmit-buffer is empty (bit 0) whenever the
receive-buffer is nonempty Also, in FIFO mode,
a timeout interrupt will be generated if
neither FIFO has been serviced for at least
four character-clock times
29FIFO Control Register
7 6 5 4
3 2 1 0
RCVR FIFO trigger-level
reserved
reserved
DMA Mode select
XMIT FIFO reset
RCVR FIFO reset
FIFO enable
00 1 byte 01 4 bytes 10 8 bytes 11 14
bytes
NOTE DMA is unsupported for the UART on our
systems
Writing 1 empties the FIFO, writing 0 has no
effect
Writing 0 will disable the UARTs FIFO-mode,
writing 1 will enable FIFO-mode
30Interrupt Identification Register
7 6 5 4
3 2 1 0
0
0
highest priority UART interrupt still
pending
00 FIFO-mode has not been enabled 11
FIFO-mode is currently enabled
highest 011 receiver line-status
010 received data ready 100 character
timeout 001 Tx Holding Reg empty
000 modem-status change lowest
1 No UART interrupts are pending 0 At least
one UART interrupt is pending
31Responding to interrupts
- You need to clear a reported interrupt by
taking some action -- depending on which
condition was the cause of the interrupt - Line-Status read the Line Status Register
- Rx Data Ready read Receiver Data Register
- Timeout read from Receiver Data Register
- THRE read Interrupt Identification Register or
write to Transmitter Data Register (or both) - Modem-Status read Modem Status Register
32Usage flexibility
- A UART can be programmed to operate in polled
mode or in interrupt-driven mode - While Polled Mode is simple to program (as we
shall show on the following slides), it does not
make efficient use of the CPU in situations that
require multitasking (as the CPU is kept busy
doing polling of the UARTs status instead of
useful work
33How to transmit a byte
Read the Line Status Register
Transmit Holding Register is Empty?
NO
YES
Write byte to the Transmitter Data Register
DONE
34How to receive a byte
Read the Line Status Register
Received Data is Ready?
NO
YES
Read byte from the Receiver Data Register
DONE
35How to implement in C/C
// declare the programs variables and
constants char inch, outch A //
--------------------- Transmitting a byte
------------------- // wait until the
Transmitter Holding Register is empty, // then
output the byte to the Transmit Data Register
do while ( (inb( LINE_STATUS) 0x20) 0
) outb( outch, TRANSMIT_DATA_REGISTER ) //
---------------------- Receiving a byte
------------------------ // wait until the
Received Data Ready bit becomes true, // then
input a byte from the Received Data Register do
while ( (inb( LINE_STATUS ) 0x01 ) 0
) inch inb( RECEIVED_DATA_REGISTER )
36How to initialize loopback mode
Set the Divisor Latch Access Bit in the Line
Control Register
Write a nonzero value to the Divisor Latch
Register
Clear the Divisor Latch Access Bit and specify
the desired data-format in the Line Control
Register
Set the Loopback bit in the Modem Control Register
DONE
37How to adjust the cpus IOPL
- Linux provides a system-call to privileged
programs which need to access I/O ports - The ltsys/io.hgt header-file prototypes it, and the
iopl() library-function invokes it - The kernel will modify the CPUs current I/O
Permission Level in cpus EFLAGS (if the
programs owner has root privileges) - So you first execute our iopl3 command
38In-class experiments
- For learning purposes, we can write user-programs
that are able to execute in and out
instructions, and so control the UART - But to avoid the CPUs normal segfaults we will
have to acquire I/O privileges - The iopl3 command (created by our CS System
Administrator Alex Fedosov) will establish the
permissions which we need
39Experiment 1
- Download and run our testuart.cpp demo
- It uses the UARTs loopback test mode to
receive each character that it transmits
UART loopback mode
TxData
TxShiftReg
RxData
RxShiftReg
Output loops back to become input
The external signal-lines are bypased
40Experiment 2
- Download and run our uartecho.cpp app (it does
nothing untill you do the next step) - Modify the testuart.cpp demo-program by
commenting out the instruction that places the
UART into loopback mode - Execute those two programs on a pair of PCs that
are connected by a null-modem
41Experiment 3
- Add a pair of counters to testuart.cpp
- Declare two integer variables (initialized to 0)
- int txwait 0, rxwait 0
- Increment these in the body of your do-loops
- do txwait while ( / Transmitter is busy
/ ) - do rxwait while ( / Receiver not ready
/ ) - Display their totals at the demos conclusion
- printf( txwaitd rxwaitd \n, txwait,
rxwait )
42Experiment 4
- Modify the testuart.cpp demo-program to
experiment with using a different baud rate and a
different data-format - For example, use 300 baud and 7-N-2
- output 0x0180 to the Divisor Latch register
- output 0x06 to the Line Control register
- Then, to better observe the effect, add the
statement fflush( stdout ) in the program loop
immediately after printf( c, data)
43Is your cable working?
- We created a diagnostic program (called
trycable.cpp) that you can use to check whether
two PCs are properly connected with a working
null-modem cable - You run uartecho.cpp on one of the PCs and then
execute testcable.cpp on the adjacent PC you
will see a message on both screens if your cable
is working OK