Serial Port / UART of Modern Desktop Board & its Linux programming
Dr A Sahu
Dept of Comp Sc & Engg.
IIT Guwahati
Outline
IO Port Addressing
0170-0177 : 0000:00:14.1
0170-0177 : pata_atiixp
01f0-01f7 : 0000:00:14.1
01f0-01f7 : pata_atiixp
0200-020f : pnp 00:09
0220-0233 : pnp 00:09
0240-0253 : pnp 00:09
0260-0273 : pnp 00:09
0280-0293 : pnp 00:09
02f8-02ff : serial
0000-001f : dma1
0020-0021 : pic1
0040-0043 : timer0
0050-0053 : timer1
0060-0060 : keyboard
0064-0064 : keyboard
0070-0071 : rtc0
0080-008f : dma page reg
00a0-00a1 : pic2
00c0-00df : dma2
00f0-00ff : fpu
0376-0376 : 0000:00:14.1
0376-0376 : pata_atiixp
0378-037a : parport0
0388-0389 : pnp 00:09
03c0-03df : vga+
03f6-03f6 : 0000:00:14.1
03f6-03f6 : pata_atiixp
03f8-03ff : serial
040b-040b : pnp 00:09
04d0-04d1 : pnp 00:09
IOPL
Type of Serial Communication
Type of Serial Communication
Sender
Sender
Receiver
Receiver
Data
Data
Data
Data
Data
Data
Data
Data
a
Transmission Gaps
Asynchronous transmission
Synchronous transmission
CLK
Framing in Asynchronous
Type of Serial Communication
Asynchronous transmission
8 bit Data
Start Bit
Start Bits
1 0 0 0 1 1 1 0
LSB MSB
Time
1 start
bit
1 or 2 Stop
bit
Source data
Using ‘echo’ and ‘cat’
$ echo Hello > /dev/uart
$ _
$ cat /dev/uart
Hello _
Receiving…
Transmitting…
Tx and Rx
Linux char-driver components
init
exit
fops
function
function
function
. . .
Device-driver LKM layout
registers the ‘fops’
unregisters the ‘fops’
module’s ‘payload’
is a collection of
callback-functions
having prescribed
prototypes
AND
a ‘package’ of
function-pointers
the usual pair of
module-administration
functions
Requires a device-file node
Serial data-transmission
0
1
1
0
0
0
0
1
The Transmitter Holding Register (8-bits)
0
1
1
0
0
0
0
1
The transmitter’s internal ‘shift’ register
clock
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
1-0-1-1-0-0-0-0-1-0
start
bit
stop
bit
data-bits
clock-pulses
trigger bit-shifts
‘write()’ and ‘read()’
Serial data reception
clock
input voltage
clock-pulses trigger
voltage-sampling
and bit-shifts
at regular intervals
0
1
1
0
0
0
0
1
The receiver’s internal ‘shift’ register
1-0-1-1-0-0-0-0-1-0
start
bit
stop
bit
data-bits
0
1
1
0
0
0
0
1
The Receiver Buffer Register (8-bits)
Software can input
the received byte
from the RBR
8251 Block Diagram
Data Bus
Buffer
Transmit
Buffer
Receive
Buffer
Transmit
Control
Receive
Control
R/W
Control
Logic
Modem Control
Internal
Line
D7-D0
RESET
CLK
C/Db
RDb
WRb
CSb
DSRb
DTRb
CTSb
RTSb
TXD
TXRDY
TXE
TXC
RXD
RXRDY
RXC
SYBDET/BD
Transmitter and Receiver
Data
Buffer
Register
D0
D7
Internal
Data
Bus
Transmitter
Buffer
Register
Receiver
Buffer
Register
Out put
Register
Input
Register
Transmitter
Control Logic
Receiver
Control Logic
TxD
TxCb
TxRDY
TxE
RxD
RxCb
RxRDY
Command Register
(Command Word Format)
EH
IR
RTS
ER
SBRK
RxE
DTR
TxE
TxE: transmit enable (0/1 Enable Disable)
DTR: data terminal ready (1=ENABLE DTR)
RxE: receiver enable (1/0=EN/DISABLE)
SBPRK: send break character 1= force TxD low
ER: error reset (Reset Flags: Parity ,Over run, Framing Error of Status Word)
RTS: request to send (1= Enable Request to send)
IR: internal reset (Reset 8251 to mode)
EH: enter hunt mode (1=search for Sync Character)
8251: Status Regsiter
DSR
SYN
DET
FE
OE
PE
Tx
EMPTY
RxRDY
TxRDY
TxRDY transmit ready (DB Buffer is empty)
RxRDY receiver ready
TxEMPTY transmitter empty
PE parity error (1=when PE detected)
OE overrun error
FE framing error (Aynsc only, Valid stop bit not detected)
SYNDET sync. character detected
DSR data set ready (DSR set at 0 level)
PC Standard UART (16550) Registers
Transmit Data Register
Received Data Register
Interrupt Enable Register
Interrupt Identification Register
FIFO Control Register
Line Control Register
Modem Control Register
Line Status Register
Modem Status Register
Scratch Pad Register
Divisor Latch Register
16-bits (R/W)
8-bits (Write-only)
8-bits (Read-only)
8-bits (Read/Write)
8-bits (Read-only)
8-bits (Write-only)
8-bits (Read/Write)
8-bits (Read/Write)
8-bits (Read-only)
8-bits (Read-only)
8-bits (Read/Write)
Base+0
Base+0
Base+1
Base+2
Base+2
Base+3
Base+4
Base+5
Base+6
Base+7
Base+0
Rate of data-transfer
Divisor Latch
How timing works
Transmitter clock (bit-rate times 16)
DATA
OUT
start-bit data-bit 0 data-bit 1 …
receiver detects this high-to-low transition,
so it waits 24 clock-cycles,
then samples the data-line’s voltage
every 16 clock-cycles afterward
24 clock-cycles
16 clock-cycles
16 clock-cycles
Receiver clock (bit-rate times 16)
sample
sample
Programming interface
RxD/TxD
IER
IIR/FCR
LCR
MCR
LSR
MSR
SCR
The PC uses eight consecutive I/O-ports to access
the UART’s registers
0x03F8 0x03F9 0x03FA 0x03FB 0x03FC 0s03FD 0x03FE 0x03FF
scratchpad
register
modem
status
register
line
status
register
modem
control
register
line
control
register
interrupt
enable
register
interrupt identification register and FIFO control register
receive buffer register and
transmitter holding register
(also Divisor Latch register)
Modem Control Register
0
0
0
LOOP
BACK
OUT2
OUT1
RTS
DTR
7 6 5 4 3 2 1 0
Legend:
DTR = Data Terminal Ready (1=yes, 0=no)
RTS = Request To Send (1=yes, 0=no)
OUT1 = not used (except in loopback mode)
OUT2 = enables the UART to issue interrupts
LOOPBACK-mode (1=enabled, 0=disabled)
Modem Status Register
DCD
RI
DSR
CTS
delta
DCD
delta
RI
delta
DSR
delta
CTS
7 6 5 4 3 2 1 0
set if the corresponding bit has changed since the last time this register was read
Legend: [---- loopback-mode ----]
CTS = Clear To Send (1=yes, 0=no) [bit 0 in Modem Control]
DSR = Data Set Ready (1=yes, 0=no) [bit 1 in Modem Control]
RI = Ring Indicator (1=yes,0=no) [bit 2 in Modem Control]
DCD = Data Carrier Detected (1=yes,0=no) [bit 3 in Modem Control]
Line Status Register
Error in
Rx FIFO
TXmitter
idle
THR
empty
Break
interrupt
Framing
error
Parity
error
Overrun
error
Received
Data
Ready
7 6 5 4 3 2 1 0
These status-bits indicate errors in the received data
This status-bit indicates that a new byte of data has arrived
(or, in FIFO-mode, that the receiver-FIFO has reached its threshold)
This status-bit
indicates that the
data-transmission
has been completed
This status-bit indicates that
the Transmitter Holding Register
is ready to accept a new data byte
Line Control Register
Divisor
Latch
access
set
break
stick
parity
even
parity
select
parity
enable
number
of stop
bits
word length
selection
7 6 5 4 3 2 1 0
00 = 5 bits
01 = 6 bits
10 = 7 bits
11 = 8 bits
0 = 1 stop bit
1 = 2 stop bits
0 = no parity bits
1 = one parity bit
1 = even parity
0 = ‘odd’ parity
0 = not accessible
1 = assessible
0 = normal
1 = ‘break’
Interrupt Enable Register
0
0
0
0
Modem
Status
change
Rx Line
Status
change
THR
is
empty
Received
data is
available
7 6 5 4 3 2 1 0
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
FIFO Control Register
RCVR FIFO
trigger-level
reserved
reserved
DMA
Mode
select
XMIT
FIFO
reset
RCVR
FIFO
reset
FIFO
enable
7 6 5 4 3 2 1 0
Writing 0 will disable the UART’s FIFO-mode, writing 1 will enable FIFO-mode
Writing 1 empties the FIFO, writing 0 has no effect
00 = 1 byte
01 = 4 bytes
10 = 8 bytes
11 = 14 bytes
Mode: If supported DMA
Interrupt Identification Register
0
0
7 6 5 4 3 2 1 0
00 = FIFO-mode has not been enabled
11 = FIFO-mode is currently enabled
1 = No UART interrupts are pending
0 = At least one UART interrupt is pending
‘highest priority’ UART Interrupt still pending
highest
011 = receiver line-status
010 = received data ready
100 = character timeout
001 = Tx Holding Reg empty
000 = modem-status change
lowest
Responding to interrupts
Usage flexibility
How to transmit a byte
Read the Line Status Register
Write byte to the Transmitter Data Register
Transmit Holding Register
is Empty?
NO
YES
DONE
How to receive a byte
Read the Line Status Register
Read byte from the Receiver Data Register
Received Data
is Ready?
NO
YES
DONE
How to implement in C/C++
// declare the program’s 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 );
How 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
How to adjust the cpu’s IOPL
Loop-Back Experiment
TxData
RxData
TxShiftReg
RxShiftReg
UART ‘loopback’ mode
The external signal-lines are bypased
Output loops back to become input
Loop Back Program: uarttest.cpp
#define UART_PORT 0x03F8 // base port-address for the UART
#define DIVISOR_LATCH (UART_PORT + 0)
#define TX_DATA_REG (UART_PORT + 0)
#define RX_DATA_REG (UART_PORT + 0)
#define LINE_CONTROL (UART_PORT + 3)
#define MODEM_CONTROL (UART_PORT + 4)
#define LINE_STATUS (UART_PORT + 5)
char msg[] = "\n\tThis is a test of the UART's loopback mode\n";
int main( int argc, char **argv ) {
// set the CPU's I/O Permission-Level to allow port-access
if ( iopl( 3 ) ) { perror( "iopl" ); exit(1); }
Loop Back Program
// establish the UART's operational parameters
outb( 0x80, LINE_CONTROL ); // set DLAB=1
outw( 0x0001, DIVISOR_LATCH ); // set 11520 baud
outb( 0x03, LINE_CONTROL ); // set data-format: 8-N-1
outb( 0x10, MODEM_CONTROL ); // turn on 'loopback' mode
// write each message-character, read it back, and display it
for (int i = 0; i < sizeof( msg ); i++) {
do { } while ( (inb( LINE_STATUS )&0x20) == 0x00 );
outb( msg[i], TX_DATA_REG );
do { } while ( (inb( LINE_STATUS )&0x01) == 0x00 );
int data = inb( RX_DATA_REG );
printf( "%c", data );
}
outb( 0x00, MODEM_CONTROL );// turn off 'loopback' mode
printf( "\n" );
}
Thanks