neorv32/docs/datasheet/soc_uart.adoc

196 lines
12 KiB
Plaintext
Raw Permalink Normal View History

2024-02-24 08:25:27 +00:00
<<<
:sectnums:
==== Primary Universal Asynchronous Receiver and Transmitter (UART0)
[cols="<3,<3,<4"]
[frame="topbot",grid="none"]
|=======================
| Hardware source file(s): | neorv32_uart.vhd |
| Software driver file(s): | neorv32_uart.c |
| | neorv32_uart.h |
| Top entity port: | `uart0_txd_o` | serial transmitter output
| | `uart0_rxd_i` | serial receiver input
| | `uart0_rts_o` | flow control: RX ready to receive, low-active
| | `uart0_cts_i` | flow control: RX ready to receive, low-active
| Configuration generics: | `IO_UART0_EN` | implement UART0 when `true`
| | `UART0_RX_FIFO` | RX FIFO depth (power of 2, min 1)
| | `UART0_TX_FIFO` | TX FIFO depth (power of 2, min 1)
| CPU interrupts: | fast IRQ channel 2 | RX interrupt
| | fast IRQ channel 3 | TX interrupt (see <<_processor_interrupts>>)
|=======================
**Overview**
The NEORV32 UART provides a standard serial interface with independent transmitter and receiver channels, each
equipped with a configurable FIFO. The transmission frame is fixed to **8N1**: 8 data bits, no parity bit, 1 stop
bit. The actual transmission rate (Baud rate) is programmable via software. The module features two memory-mapped
registers: `CTRL` and `DATA`. These are used for configuration, status check and data transfer.
.Standard Console
[NOTE]
All default example programs and software libraries of the NEORV32 software framework (including the bootloader
and the runtime environment) use the primary UART (_UART0_) as default user console interface. Furthermore, UART0
is used to implement the "standard consoles" (`STDIN`, `STDOUT` and `STDERR`).
**Theory of Operation**
The module is enabled by setting the `UART_CTRL_EN` bit in the UART0 control register `CTRL`. The Baud rate
is configured via a 10-bit `UART_CTRL_BAUDx` baud divisor (`baud_div`) and a 3-bit `UART_CTRL_PRSCx`
clock prescaler (`clock_prescaler`).
.UART0 Clock Configuration
[cols="<4,^1,^1,^1,^1,^1,^1,^1,^1"]
[options="header",grid="rows"]
|=======================
| **`UART_CTRL_PRSCx`** | `0b000` | `0b001` | `0b010` | `0b011` | `0b100` | `0b101` | `0b110` | `0b111`
| Resulting `clock_prescaler` | 2 | 4 | 8 | 64 | 128 | 1024 | 2048 | 4096
|=======================
_**Baud rate**_ = (_f~main~[Hz]_ / `clock_prescaler`) / (`baud_div` + 1)
The control register's `UART_CTRL_RX_*` and `UART_CTRL_TX_*` flags provide information about the RX and TX FIFO fill level.
Disabling the module via the `UART_CTRL_EN` bit will also clear these FIFOs.
A new TX transmission is started by writing to the `DATA` register. The
transfer is completed when the `UART_CTRL_TX_BUSY` control register flag returns to zero. RX data is available when
the `UART_CTRL_RX_NEMPTY` flag becomes set. The `UART_CTRL_RX_OVER` will be set if the RX FIFO overflows. This flag
is cleared only by disabling the module via `UART_CTRL_EN`.
**UART Interrupts**
The UART module provides independent interrupt channels for RX and TX. These interrupts are triggered by certain RX and TX
FIFO levels. The actual configuration is programmed independently for the RX and TX interrupt channel via the control register's
`UART_CTRL_IRQ_RX_*` and `UART_CTRL_IRQ_TX_*` bits:
. **RX IRQ** The RX interrupt can be triggered by three different RX FIFO level states: If `UART_CTRL_IRQ_RX_NEMPTY` is set the
interrupt fires if the RX FIFO is _not_ empty (e.g. when incoming data is available). If `UART_CTRL_IRQ_RX_HALF` is set the RX IRQ
fires if the RX FIFO is at least half-full. If `UART_CTRL_IRQ_RX_FULL` the interrupt fires if the RX FIFO is full. Note that all
these programmable conditions are logically OR-ed (interrupt fires if any enabled conditions is true).
. **TX IRQ** The TX interrupt can be triggered by two different TX FIFO level states: If `UART_CTRL_IRQ_TX_EMPTY` is set the
interrupt fires if the TX FIFO is empty. If `UART_CTRL_IRQ_TX_NHALF` is set the interrupt fires if the TX FIFO is _not_ at least
half full. Note that all these programmable conditions are logically OR-ed (interrupt fires if any enabled conditions is true).
Once an UART interrupt has fired it remains pending until the actual cause of the interrupt is resolved; for
example if just the `UART_CTRL_IRQ_RX_NEMPTY` bit is set, the RX interrupt will keep firing until the RX FIFO is empty again.
Furthermore, a pending UART interrupt has to be explicitly cleared again by writing zero to the according <<_mip>> CSR bit.
.RX/TX FIFO Size
[TIP]
Software can retrieve the configured sizes of the RX and TX FIFO via the according `UART_DATA_RX_FIFO_SIZE` and
`UART_DATA_TX_FIFO_SIZE` bits from the `DATA` register.
**RTS/CTS Hardware Flow Control**
The NEORV32 UART supports optional hardware flow control using the standard CTS `uart0_cts_i` ("clear to send") and RTS
`uart0_rts_o` ("ready to send" / "ready to receive (RTR)") signals. Both signals are low-active.
Hardware flow control is enabled by setting the `UART_CTRL_HWFC_EN` bit in the modules control register `CTRL`.
When hardware flow control is enabled:
. The UART's transmitter will not start a new transmission until the `uart0_cts_i` signal goes low.
During this time, the UART busy flag `UART_CTRL_TX_BUSY` remains set.
. The UART will set `uart0_rts_o` signal low if the RX FIFO is **less than half full** (to have a wide safety margin).
As long as this signal is low, the connected device can send new data. `uart0_rts_o` is always low if the hardware flow-control
is disabled. Disabling the UART (setting `UART_CTRL_EN` low) while having hardware flow-control enabled, will set `uart0_rts_o`
high to signal that the UARt is not capable of receiving new data.
[NOTE]
Note that RTS and CTS signaling can only be activated together. If the RTS handshake is not required the signal can be left
unconnected. If the CTS handshake is not required it has to be tied to zero.
**Simulation Mode**
The UART provides a _simulation-only_ mode to dump console data as well as raw data directly to a file. When the simulation
mode is enabled (by setting the `UART_CTRL_SIM_MODE` bit) there will be **no** physical transaction on the `uart0_txd_o` signal.
Instead, all data written to the `DATA` register is immediately dumped to a file. Data written to `DATA[7:0]` will be dumped as
ASCII chars to a file named `neorv32.uart0.sim_mode.text.out`. Additionally, the ASCII data is printed to the simulator console.
Both file are created in the simulation's home folder.
**Register Map**
.UART0 register map (`struct NEORV32_UART0`)
[cols="<4,<2,<5,^2,<5"]
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.19+<| `0xfffff500` .19+<| `CTRL` <|`0` `UART_CTRL_EN` ^| r/w <| UART enable
<|`1` `UART_CTRL_SIM_MODE` ^| r/w <| enable **simulation mode**
<|`2` `UART_CTRL_HWFC_EN` ^| r/w <| enable RTS/CTS hardware flow-control
<|`5:3` `UART_CTRL_PRSC2 : UART_CTRL_PRSC0` ^| r/w <| Baud rate clock prescaler select
<|`15:6` `UART_CTRL_BAUD9 : UART_CTRL_BAUD0` ^| r/w <| 12-bit Baud value configuration value
<|`16` `UART_CTRL_RX_NEMPTY` ^| r/- <| RX FIFO not empty
<|`17` `UART_CTRL_RX_HALF` ^| r/- <| RX FIFO at least half-full
<|`18` `UART_CTRL_RX_FULL` ^| r/- <| RX FIFO full
<|`19` `UART_CTRL_TX_EMPTY` ^| r/- <| TX FIFO empty
<|`20` `UART_CTRL_TX_NHALF` ^| r/- <| TX FIFO not at least half-full
<|`21` `UART_CTRL_TX_FULL` ^| r/- <| TX FIFO full
<|`22` `UART_CTRL_IRQ_RX_NEMPTY` ^| r/w <| fire IRQ if RX FIFO not empty
<|`23` `UART_CTRL_IRQ_RX_HALF` ^| r/w <| fire IRQ if RX FIFO at least half-full
<|`24` `UART_CTRL_IRQ_RX_FULL` ^| r/w <| fire IRQ if RX FIFO full
<|`25` `UART_CTRL_IRQ_TX_EMPTY` ^| r/w <| fire IRQ if TX FIFO empty
<|`26` `UART_CTRL_IRQ_TX_NHALF` ^| r/w <| fire IRQ if TX not at least half full
<|`29:27` - ^| r/- <| _reserved_ read as zero
<|`30` `UART_CTRL_RX_OVER` ^| r/- <| RX FIFO overflow; cleared by disabling the module
<|`31` `UART_CTRL_TX_BUSY` ^| r/- <| TX busy or TX FIFO not empty
.4+<| `0xfffff504` .4+<| `DATA` <|`7:0` `UART_DATA_RTX_MSB : UART_DATA_RTX_LSB` ^| r/w <| receive/transmit data
<|`11:8` `UART_DATA_RX_FIFO_SIZE_MSB : UART_DATA_RX_FIFO_SIZE_LSB` ^| r/- <| log2(RX FIFO size)
<|`15:12` `UART_DATA_TX_FIFO_SIZE_MSB : UART_DATA_TX_FIFO_SIZE_LSB` ^| r/- <| log2(RX FIFO size)
<|`31:16` ^| r/- <| _reserved_, read as zero
|=======================
<<<
// ####################################################################################################################
:sectnums:
==== Secondary Universal Asynchronous Receiver and Transmitter (UART1)
[cols="<3,<3,<4"]
[frame="topbot",grid="none"]
|=======================
| Hardware source file(s): | neorv32_uart.vhd |
| Software driver file(s): | neorv32_uart.c |
| | neorv32_uart.h |
| Top entity port: | `uart1_txd_o` | serial transmitter output
| | `uart1_rxd_i` | serial receiver input
| | `uart1_rts_o` | flow control: RX ready to receive, low-active
| | `uart1_cts_i` | flow control: RX ready to receive, low-active
| Configuration generics: | `IO_UART1_EN` | implement UART1 when `true`
| | `UART1_RX_FIFO` | RX FIFO depth (power of 2, min 1)
| | `UART1_TX_FIFO` | TX FIFO depth (power of 2, min 1)
| CPU interrupts: | fast IRQ channel 4 | RX interrupt
| | fast IRQ channel 5 | TX interrupt (see <<_processor_interrupts>>)
|=======================
**Overview**
The secondary UART (UART1) is functionally identical to the primary UART
(<<_primary_universal_asynchronous_receiver_and_transmitter_uart0>>). Obviously, UART1 uses different addresses for the
control register (`CTRL`) and the data register (`DATA`). The register's bits/flags use the same bit positions and naming
as for the primary UART. The RX and TX interrupts of UART1 are mapped to different CPU fast interrupt (FIRQ) channels.
**Simulation Mode**
The secondary UART (UART1) provides the same simulation options as the primary UART (UART0). However, output data is
written to UART1-specific file `neorv32.uart1.sim_mode.text.out`. This data is also printed to the simulator console.
**Register Map**
.UART1 register map (`struct NEORV32_UART1`)
[cols="<2,<1,<1,^1,<2"]
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
| `0xfffff600` | `CTRL` | ... | ... | Same as UART0
| `0xfffff604` | `DATA` | ... | ... | Same as UART0
|=======================