| {{% 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 }} |