blob: 8fb339539b44fb76a214f0d2905ffeded09635f0 [file] [log] [blame] [view]
{{% lowrisc-doc-hdr UART with 16550 style interface }}
{{% regfile uart16550.hjson }}
The UART16550 provides an asynchronous serial interface that can
operate at programmable BAUD rates. The main features are:
- 16 byte transmit FIFO
- 16 byte receive FIFO
- Programmable baud rate generator
- Hardware flow control (when enabled)
- 5, 6, 7, or 8 data bits
- optional parity bit (even, odd, mark or space)
- 1 or 2 stop bits when used with 6, 7 or 8 data bits
- 1 or 1.5 stop bits when used with 5 data bits
## Compatibility
The UART16550 is compatible with the de-facto standard 16550 driver
with registers at byte offsets.
## Theory of operation
*TODO block diagram of UART*
The UART can connect to eight external pins:
* TX: transmit data output.
* RX: receive data input.
* RTS_L: request to send flow control output. This pin is active low.
* CTS_L: clear to send flow control input. This pin is active low.
* DTR_L: data terminal ready output. This pin is active low.
* DSR_L: data set ready input. This pin is active low.
* DCD_L: data carrier detect input. This pin is active low.
* RI_L: ring indicate. This pin is active low.
### Baud Rate
The serial line timing is based on a 16x baud rate clock. The
programmable baud rate generator is driven by a 133.33MHz clock and
has a 16 bit divider to generate the 16xbaud rate reference. This
allows generation of the standard baud rates from 300 to 921600 baud
with less than 1% error. The divisor is accessed by setting the DLAB
bit in the line control register which makes the low and high parts of
the divisor value available for read and write through the byte
registers at offset 0 (low byte of divisor)and 1 (high byte). Writing
either of the divisor registers causes the divider counter to be
reloaded.
Required Baud | Divisor | Actual Baud | Error
--------------|---------|-------------|------
B |D = INT(0.5 + 133.33MHz/(16*B)) | A = (133.33MHz/D)/16 | (A-B)/B
300 | 27778 | 300 | 0%
600 | 13889 | 600.04 | 0.01%
1200 | 6944 | 1200.08 | 0.01%
1800 | 4630 | 1799.86 | -0.01%
2400 | 3472 | 2400.15 | 0.01%
4800 | 1736 | 4800.31 | 0.01%
9600 | 868 | 9600.61 | 0.01%
19200 | 434 | 19201.23 | 0.01%
38400 | 217 | 38402.46 | 0.01%
57600 | 145 | 57471.26 | 0.47%
115200 | 72 | 115740.74 | 0.47%
230400 | 36 | 231481.48 | 0.47%
460800 | 18 | 462962.96 | 0.47%
921600 | 9 | 925925.92 | 0.47%
If the baud rate divisor is set to zero the baud rate clock is stopped
and the UART will be disabled, this is the default. The baud rate
clock is automatically stopped to save power when the UART is idle.
### Serial data format
The serial line is high when idle. Characters are sent using a start
bit (low) followed by 5, 6, 7 or 8 data bits sent least significant
first. Optionally there may be a parity bit which is computed to give
either even or odd parity or may be always high or always low. Finally
there is a stop sequence during which the line is high or one or two
(1.5 for 5 bit characters) bit times. The start bit for the next
character may immediately follow the stop sequence, or the line may be
in the idle (high) state for some time. The data format and (for
reference) the baud clock are illustrated for the different number of
data bits with no parity and a single stop bit, and for 8 data bits
with parity. The line could go idle (high) or the next character start
after the stop bit where "next" is indicated. All formatting
parameters are controlled in the !!LCR.
```wavejson
{signal: [
{name:'Baud Clock', wave: 'p...........' },
{name:'Data 8 bit', wave: '10========1=',
data: [ "lsb", "", "", "", "", "", "", "msb", "next" ] },
{name:'Data 7 bit', wave: '10=======1=.',
data: [ "lsb", "", "", "", "", "", "msb", "next" ] },
{name:'Data 6 bit', wave: '10======1=..',
data: [ "lsb", "", "", "", "", "msb", "next" ] },
{name:'Data 5 bit', wave: '10=====1=...',
data: [ "lsb", "", "", "", "msb", "next" ] },
{name:'8 with Parity', wave: '10=========1',
data: [ "lsb", "", "", "", "", "", "", "msb", "par" ] },
],
head:{
text:'Serial Line format (one stop bit)',
tock:-1,
}
}
```
The data formatting ensures that in normal operation the line cannot
be low for more than the number of data bits plus two (low start bit
plus all zero character plus even or low parity bit) before the stop
sequence forces the line high. If the line remains low for longer than
this time the condition is known as a Break. The uart can be set to
generate a (continuous) break on its output line by setting BrkEn in
the !!LCR. Detection of a break is signalled by reception of a
character containing all zeros that is accompanied by the Break Detect
Flag.
### Serial Data Reception
The UART detect the RX line transitioning from high to low as the
start of a potential reception. The line is checked after half a bit
time (8 cycles of the 16xbaud rate clock) and if still low then a
start bit is detected. Every bit-time (16 cycles of the 16x baud rate
clock) the data is sampled. One additional bit is sampled following
the data and parity bits. This should be the stop bit and should
therefore be set. If the line is detected low when the stop bit is
expected then the data is still received but is marked with a framing
error (note that only one bit is checked even if the stop sequence is
set to two bits). If parity is enabled and the bit does not match the
expected value then the received character is marked with a parity
error.
### Serial Data Transmission
The UART will normally format characters (add start, parity and stop
bits) and transmit them whenever characters are available to be sent
and the line is idle. However, setting the AFC bit in the !!MCR
enables automatic flow control. With this setting the transmitter will
only start to send a character if the CTS_L line is asserted
(i.e. low) indicating that the peer device is able to receive data.
### Interface FIFOs
The interface has a FIFO to hold characters waiting to be transmitted
and a FIFO to hold characters that have been received but not yet read
by software. These FIFOs are 16 characters deep. By default the FIFOs
are disabled (effectively one character deep) and should be enabled by
setting the FEN bit in the FIFO Control Register. Note that when the
FEN bit is set any character that is currently in the holding register
will be transmitted before the FIFO is enabled (this was not the case
prior to revision 16 of the UART where it was advised to check the
TEMT bit in the LSR to ensure there are no characters in-flight when
the FIFO is enabled).
Writes to the Data Register when the Transmit Holding Register Empty
(THRE) status bit is set will add characters to the transmit
FIFO. This status bit will be clear when the FIFO is full, and any
writes to the Data Register will be discarded.
Reads from the Data Register will return the next received character
and will remove it from the receive FIFO. Prior to reading the Data
Register a read should be done of the Line Status Register which will
indicate if there is data available and give the error flags that
accompany the character at the head of the FIFO. (The error flags flow
through the FIFO with their corresponding character.)
Once the FIFOs are enabled the TL field in the FCR can be used to
configure the number of characters that must bein the receive FIFO to
trigger two events:
1. The receive data available interrupt is raised (if the FIFO is
disabled this is done when a single character is received).
2. If automatic flow control is enabled the RTS_L output is deasserted
(i.e. set high) on reception of a start bit.
### Modem/Handshake Signals
The UART has two output lines (RTS\_L and DTR\_L) and four input lines
(CTS\_L, DSR\_L, DCD\_L and RI\_L) that can be used for modem
control. However, only the RTS\_L output and CTS\_L input are given
dedicated pins. The other lines are shared with GPIO signals and the
GPIO configuration register must be set correctly to enable their
use. (See section on the GPIO pins.)
The state of the input signals can be read in the Modem Status
Register which also reports if any of the lines have changed since the
previous read of the register. Detection of a change in state can
generate an interrupt. The state of the output lines can be set in the
Modem Control Register.
If automatic flow control is enabled then the hardware will control
the RTS\_L output and use the state of the CTS\_L input. RTS\_L will be
asserted whenever the receive FIFO is full to the threshold level set
in the TL field of the FIFO Control Register and a start bit is
detected. RTS\_L will be deasserted whenever the receive FIFO is below
the threshold. The transmitter will check the CTS\_L signal prior to
sending a character and will wait for CTS\_L to be asserted before
starting the character (once a character has been started it will be
completed before the CTS_L is checked again).
### Interrupts and powerdown
The UART can generate an interrupt to the CPU. The Interrupt Enable
Register configures which UART events cause the interrupt to be raised
and the Interrupt Identification Register allows detection of the
cause of the interrupt. In addition to the normal UART register
controls, the interrupt may be disabled by setting the intd control
bit in the PCI header Command register and the state of the interrupt
may be detected in the is bit of the PCI header Status register. The
interrupt source number that the UART will use can be read as the
default value in the iline field of the PCI header.
The UART may be forced into a low power mode by setting either or both
of the SLP and LPE bits in the Interrupt Enable Register.
### Scratch Register
The UART contains an 8 bit read/write register that is not used by the
hardware. Software may use this register as it sees fit. The value in
the scratch register is unpredictable following a reset.
Testing cross reference to !!DATA (or with punctuation !!DATA). The
strange case will be !!LCR. Which is a different period than in
!!LCR.DLAB or could be used twice in !!LCR.DLAB. How about
!!LCR-!!DATA? Phew!
## Programmer Guide
### Initialization
The baud rate should be set as previously outlined to enable the UART.
### Interrupts
The UART raises a single interrupt to the system based on the four
sources that can be enabled in !!IER:
- TXEE: raised if the transmit buffer is empty
- RDAE: raised if received data is available (if the FIFO is enabled the
TL field in the FCR sets the number of characters in the FIFO before
this is raised)
- RLE: The receiver line status has changed
- MSE: The modem status has changed
### Debug Features
A loopback mode can be enabled. In this the output serial data is
internally looped back to the receiver and the output control lines
(and two addition signals) are looped back to the four handshake
inputs. This allows software testing. In this mode the output pins
will be in their inactive state (i.e. high).
## Implementation Guide
The toplevel of the UART has the following signals that connect to
external pins:
- TX data output connects to external pin
- RX: receive data input connects to external pin
- RTS_L: request to send flow control output. This pin is active
low. Connects to external pin.
- CTS_L: clear to send flow control input. This pin is active
low. Connects to external pin.
- DTR_L: data terminal ready output. This pin is active low.
- DSR_L: data set ready input. This pin is active low.
- DCD_L: data carrier detect input. This pin is active low.
- RI_L: ring indicate. This pin is active low.
The int signal connects to the interrupt controller.
The 133.33MHz peripheral clock is connected to pclk.
The main register interface is connected on the I/O ring.
## Registers
{{% registers x }}