
This project implements a full-featured UART (Universal Asynchronous Receiver-Transmitter) controller designed specifically for the Tiny Tapeout platform. The UART enables bidirectional serial communication with configurable parameters and includes interrupt generation capabilities.
UART (Universal Asynchronous Receiver-Transmitter) is a hardware communication protocol that enables serial data transmission between devices without requiring a shared clock signal. Unlike synchronous protocols, UART relies on predefined timing agreements between communicating devices.
Core UART Principles:
Asynchronous Communication: No shared clock line between devices. Each device maintains its own clock and relies on precise timing synchronization based on agreed baud rates.
Serial Data Format: Data is transmitted one bit at a time in a specific frame structure:
[START] [D0] [D1] [D2] [D3] [D4] [D5] [D6] [D7] [PARITY] [STOP]
Baud Rate: Transmission speed measured in bits per second (bps). Common rates include 9600, 19200, 38400, 57600, 115200 bps.
Oversampling: Internal clock runs at 16x baud rate for precise bit timing and noise immunity. This allows accurate detection of bit transitions and sampling at optimal points.
The UART module (tt_um_uart) serves as a wrapper around a more comprehensive uart_top module, mapping its functionality to Tiny Tapeout's standardized 8-bit I/O interface.
Internal Structure:
Input Mapping (ui_in[7:0]):
ui_in[0]: tr_en - Transmitter enableui_in[1]: mode_osl - Mode/operational selectui_in[2]: clk_sel - Clock selection (0 = 16x oversampling, 1 = full rate)ui_in[3]: tx_data_w_en - TX data write enableui_in[4]: tr_data_load - Transmit data load signalui_in[5]: rx_data_read_en - RX data read enableBidirectional I/O (uio_in[7:0] / uio_out[7:0]):
uio_in[7:1]: tr_fifo_data_w - 7-bit transmit data inputuio_in[0]: rx_data_in - Serial receive data inputuio_out[0]: tx_line - Serial transmit data outputuio_out[1]: tx_i_int - TX input interruptuio_out[2]: rx_i_int - RX input interruptuio_out[3]: tx_o_int - TX output interruptuio_out[4]: rx_o_int - RX output interruptuio_out[5]: tr_busy - Transmitter busy flaguio_out[7:6]: Reserved (tied to 0)Output (uo_out[7:0]):
uo_out[7:0]: rx_data - 8-bit received dataState Machine Operation:
The UART operates through several interconnected state machines:
TX State Machine:
RX State Machine:
Detailed Operation Sequence:
rst_n (active low)dlh_dll = 16'h0020 creating a divisor for the input clockui_in control bitsuio_in[7:1] (MSB alignment)ui_in[3] (tx_data_w_en) to load data into TX FIFOuio_out[5] (tr_busy) for completion statusuio_in[0] for start bituo_out[7:0] when frame completesui_in[5] (rx_data_read_en) to acknowledge receiptThe module uses a fixed baud rate configuration with dlh_dll = 16'h0020 (32 decimal), which acts as a clock divider for the internal baud rate generator.
Timing Calculations:
Bit Timing Precision:
Clock Selection Impact:
ui_in[2] = 0: Standard 16x oversampling mode (recommended)ui_in[2] = 1: Direct clock mode (advanced applications only)FIFO Implementation:
Interrupt System:
uio_out[1]): Triggered when TX FIFO has spaceuio_out[2]): Triggered when RX FIFO has datauio_out[3]): Transmission completion eventsuio_out[4]): Reception completion and error eventsError Handling:
Power and Resource Optimization:
Setup the environment:
pip install cocotb
Execute the test:
make
The provided test (test.py) performs the following sequence:
Clock and Reset Setup:
Configuration:
ui_in = 0b00000011Loopback Test:
0xA5 via uio_in[7:1]uio_in[0]Verification:
The test should output:
TX sending byte: 0xA5
RX received byte: 0xA5
The testbench generates tb.vcd for waveform viewing. Key signals to monitor:
For basic UART communication:
uio_out[0] to receiving device's RX inputuio_in[0]USB-to-Serial Converter:
RS-232 Level Shifter (if needed):
Microcontroller Interface:
Test Equipment:
Tiny Tapeout UART ←→ External Device
───────────────── ────────────────
uio_out[0] (TX) ──→ RX Input
uio_in[0] (RX) ←── TX Output
GND ──→ GND
| Pin | Direction | Function | External Connection |
|---|---|---|---|
uio_out[0] |
Output | TX Data | → External RX |
uio_in[0] |
Input | RX Data | ← External TX |
uio_out[5:1] |
Output | Status/Interrupts | → Status LEDs (optional) |
ui_in[5:0] |
Input | Control | ← Control switches/MCU |
| # | Input | Output | Bidirectional |
|---|---|---|---|
| 0 | TR_EN | RX_DATA[0] | RX_IN/TX_OUT |
| 1 | MODE_OSL | RX_DATA[1] | TX_FIFO[1]/TX_I_INT |
| 2 | CLK_SEL | RX_DATA[2] | TX_FIFO[2]/RX_I_INT |
| 3 | TX_WR_EN | RX_DATA[3] | TX_FIFO[3]/TX_O_INT |
| 4 | TR_DATA_LOAD | RX_DATA[4] | TX_FIFO[4]/RX_O_INT |
| 5 | RX_RD_EN | RX_DATA[5] | TX_FIFO[5]/TR_BUSY |
| 6 | RX_DATA[6] | TX_FIFO[6] | |
| 7 | RX_DATA[7] | TX_FIFO[7] |