UART

The UART (Universal Asynchronous Receiver-Transmitter) IP Core is a configurable serial communication interface designed to handle data transmission and reception. The core includes an internal clock divider and supports flexible frame configurations, allowing for variable data length, parity, and stop bit settings.

It is optimized for use in systems where efficient data handling and interrupt-driven processing are critical, featuring configurable interrupt thresholds for transmit and receive operations.

Architecture

1. Clock Divider

The UART IP core features an internal clock divider that generates a lower-frequency clock from the system clock. This divided clock is used by both the transmit and receive controllers, enabling fine-tuned baud rate control. The clock divider is configurable via a dedicated register, allowing dynamic adjustments to match external communication speeds.

2. Transmit Controller

The transmit controller handles the serialization of data frames. Data is written into the transmit FIFO, and the controller serializes it according to the frame configuration settings. These settings include:

  • Data length: Configurable number of data bits (e.g., 5 to 9 bits).

  • Parity: Optional parity bit (none, even, odd).

  • Stop bit length: Configurable number of stop bits (1 or 2).

The transmit process continues as long as data is available in the FIFO. The transmit controller is also linked to the interrupt system, generating interrupts when the number of entries in the FIFO drops below a user-defined threshold, signaling the system to refill the FIFO before it empties completely.

Transmit FIFO

The transmit FIFO buffers outgoing data and operates in a First-In-First-Out manner. The FIFO size can be adjusted according to system requirements. A configurable threshold triggers the transmit interrupt when the FIFO occupancy falls below this threshold, allowing efficient management of data transmission.

3. Receive Controller

The receive controller manages the deserialization of incoming data. It uses an internal sampling unit to sample the incoming data stream based on the clock generated by the divider. The sampling process includes:

  • Pre-sampling: Samples data before the expected center of the data bit.

  • Center sampling: The primary sample at the expected center of the bit time.

  • Post-sampling: Samples data after the expected center for error checking.

This multi-sampling approach ensures robust data reception, particularly in noisy environments or when there are minor timing discrepancies. Once a valid frame is received, the data is pushed into the receive FIFO, and an interrupt is triggered to notify the system.

Receive FIFO

The receive FIFO stores incoming data frames and operates in a First-In-First-Out manner. The receive controller automatically triggers an interrupt as soon as valid data is received, allowing the processor or system to retrieve the data promptly.

4. Interrupt System

The UART IP core includes two primary interrupt sources:

  • Transmit Interrupt: Generated when the number of entries in the transmit FIFO drops below the configured threshold. This allows the system to refill the FIFO to maintain continuous data transmission.

  • Receive Interrupt: Triggered as soon as valid data is received and placed into the receive FIFO.

These interrupts can be masked and monitored via dedicated interrupt mask and pending registers, allowing the system to prioritize and handle the interrupts as required.

Frame Configuration

The frame format for both transmission and reception is configurable to support various communication protocols and requirements. The key parameters include:

  • Data length: Configurable between 5 and 9 bits.

  • Parity: Supports none, even, or odd parity.

  • Stop bits: Configurable between 1 or 2 stop bits.

These configurations are set via the Frame Configuration Register and apply to both the transmit and receive paths.

Data Flow and Processing

Transmit Data Flow:

  1. Data is written to the transmit FIFO.

  2. The transmit controller serializes the data based on the frame configuration.

  3. The data is transmitted bit by bit over the UART interface.

  4. If the FIFO occupancy drops below the configured threshold, a transmit interrupt is generated, prompting the system to add more data to the FIFO.

Receive Data Flow:

  1. Incoming serial data is sampled by the receive controller using the internal clock generated by the clock divider.

  2. The receive controller deserializes the data based on the frame configuration and checks for frame validity (data length, parity, stop bits).

  3. Valid data is pushed into the receive FIFO.

  4. A receive interrupt is triggered to notify the system that data is available for reading.

Considerations

  • The clock divider ensures that the UART operates at a baud rate that is a fraction of the system clock. The divider ratio must be configured appropriately to match the external device’s baud rate.

  • FIFO thresholds should be set according to system latency and processing time to ensure that the FIFOs do not overflow (on receive) or underflow (on transmit).

  • The pre- and post-sampling technique ensures high data integrity even under conditions where the incoming data may have slight timing jitter or noise.

This detailed architecture and functionality make the UART IP Core highly configurable and suitable for a range of serial communication applications, offering flexibility in baud rate, data frame structure, and interrupt-driven data handling.

Configuration

Available bus architectures:

  • APB3

  • Wishbone

  • AvalonMM

By default, all buses are defined with 12 bit address and 32 bit data width.

Parameter

UartCtrl.InitParameter defines the initialization values for certian registers.

UartCtrl.InitParameter

Name

Type

Description

Default

baudrate

Int

Default baudrate of the transmit/receive controller

0

dataLength

Int

Default length of each data frame

0

parity

Uart.ParityType

Disables or sets the parity type to even or odd

null

stop

Uart.StopType

Sets the number of stop bits to one or two

null

Note

Parameter in InitParameter with a value “0” are equal to disabled. This allows to only set certain parameters.

UartCtrl.MemoryMappedParameter defines the FIFO width.

UartCtrl.MemoryMappedParameter

Name

Type

Description

Default

txFifoDepth

Int

FIFO depth for outgoing data.

rxFifoDepth

Int

FIFO depth for incoming data.

UartCtrl.PermissionParameter defines the permission rules for bus access.

UartCtrl.PermissionParameter

Name

Type

Description

Default

busCanWriteClockDividerConfig

Boolean

Toggles bus access to the clock divider.

busCanWriteFrameConfig

Boolean

Toggles bus access to the frame configuration registers.

UartCtrl.Parameter configures the UART controller.

UartCtrl.Parameter

Name

Type

Description

Default

init

UartCtrl.InitParameter

Class to parametrize the initialization values.

InitParameter.disabled

permission

UartCtrl.PermissionParameter

Class to set bus access.

PermissionParameter.granted

memory

UartCtrl.MemoryMappedParameter

Class to define FIFO depth.

MemoryMappedParameter.default

clockDividerWidth

Int

Width of the clock divider counter.

20

dataWidthMax

Int

Maximum allowed data width.

9

dataWidthMin

Int

Minimum allowed data width.

5

preSamplingSize

Int

Number of pre-samples before the actual sampling happens.

1

samplingSize

Int

Number of samples to detect incoming bytes. This values should always be uneven.

5

postSamplingSize

Int

Number of post-samples after the actual sampling happened.

2

interrupt

Boolean

Flag to en- or disable interrupt support.

true

flowControl

Boolean

Flag to en- or disable flow control.

true

UartCtrl.Parameter has some functions with pre-predefined parameters for common use-cases.

object Parameter {
  def lightweight = Parameter(
    init = InitParameter.disabled,
    permission = PermissionParameter.granted,
    memory = MemoryMappedParameter.lightweight
  )
  def default(baudrate: Int = 115200) = Parameter(
    init = InitParameter.disabled,
    permission = PermissionParameter.granted,
    memory = MemoryMappedParameter.default
  )
  def full(baudrate: Int = 115200) = Parameter(
    init = InitParameter.default(baudrate),
    permission = PermissionParameter.granted,
    memory = MemoryMappedParameter.full
  )
}

Register Mapping

IP Identification:

The register map starts with an IP Identification block to provide all information about the underlying IP core to software drivers. This allows to provide backwards compatible drivers.

IP Identification Registers

Address

Bit

Field

Default

Permission

Description

0x000

31 - 24

API

0x0

Rx

API version of the implemented IP Identification.

23 - 16

Length

0x8

Rx

Length of the IP Identification block in Bytes.

15 - 0

ID

0x3

Rx

IP value of this IP core.

0x004

31 - 24

Major Version

0x1

Rx

Major number if this IP core. Version schema is major.minor.patch.

23 - 16

Minor Version

0x0

Rx

Minor number if this IP core. Version schema is major.minor.patch.

15 - 0

Patch Version

0x0

Rx

Patch number if this IP core. Version schema is major.minor.patch.

Self Disclosure:

This block discloses information about the IP core to software drivers to simplify them.

Self Disclosure Registers

Address

Bit

Field

Default

Permission

Description

0x008

23 - 16

dataWidthMin

Rx

Minimum allowed data width.

15 - 8

dataWidthMax

Rx

Maximum allowed data width.

7 - 0

clockDividerWidth

Rx

Width of the clock divider counter.

0x00C

23 - 16

preSamplingSize

Rx

Number of pre-samples before the actual sampling happens.

15 - 8

samplingSize

Rx

Number of samples to detect incoming bytes. This values should always be uneven.

7 - 0

postSamplingSize

Rx

Number of post-samples after the actual sampling happened.

0x010

15 - 8

txFifoDepth

Rx

Depth of the transmit FIFO.

7 - 0

rxFifoDepth

Rx

Depth of the receive FIFO.

0x014

2

busCanWriteFrameConfig

Rx

Flag whether the frame configuration is writable.

1

busCanWriteClockDividerConfig

Rx

Flag whether the clock divider is writable.

Transmit and Receive FIFO:

Transmit and Receive FIFO

Address

Bit

Field

Default

Permission

Description

0x018

16

validBit

Rx

This bit contains a 1 when the receive FIFO returned valid payload.

15 - 0

receiveFifo

Rx

Payload from the receive FIFO.

0x018

31 - 0

transmitFifo

xW

Sends data to the controller which will be transmitted to an external component.

0x01C

31 - 24

occupancy

Rx

Number of occupied slots in the receive FIFO.

23 - 16

vacancy

Rx

Number of empty slots in the transmit FIFO.

Clock Divider and Frame Config:

Clock Divider and Frame Config

Address

Bit

Field

Default

Permission

Description

0x020

clockDividerWidth - 0

clockDividerValue

Depends on UartCtrl.InitParameter

RW or Rx. Depens on UartCtrl.PermissionParameter

Value for the clock divider counter to divide down the input clock.

0x024

7 - 0

dataLength

Depends on UartCtrl.InitParameter

RW or Rx. Depens on UartCtrl.PermissionParameter

Length of the data in one frame.

15 - 8

parity

Depends on UartCtrl.InitParameter

RW or Rx. Depens on UartCtrl.PermissionParameter

Possible parity flags:
  • 0: Disable parity

  • 1: Even parity bit

  • 2: Odd parity bit

31 - 16

stop

Depends on UartCtrl.InitParameter

RW or Rx. Depens on UartCtrl.PermissionParameter

Defines the number of stop bits:
  • 0: One stop bit

  • 1: Two stop bits

Interrupt:

Interrupt

Address

Bit

Field

Default

Permission

Description

0x028

31 - 0

Transmit occupancy trigger

RW

An transmit FIFO occupancy threshold which will trigger an interupt when the FIFO has the same amount of remaining entries.

0x02C

2 - 0

Interrupt pending

RW

Returns pending interrupts for each interrupt source. Clears interrupts during write.

0x030

2 - 0

Interrupt mask

RW

Interrupt mask to enable interrupts.