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 = 0b00000011
Loopback 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] |