Skip to content

Sherry11-hub/UART-DMA-Controller

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Programmable UART-to-Memory DMA Controller

Overview

This project implements a small, programmable DMA-style controller that receives bytes from an asynchronous UART and writes them into memory. The design is split into three main parts:

  1. uart_rx: Asynchronous UART receiver (8N1) producing rx_data and a one-clock rx_done pulse.
  2. dma_ctrl: DMA controller that waits for rx_done, writes received bytes into consecutive RAM addresses, and stops after a programmable number of bytes (block_size).
  3. top: A top-level wrapper tying the UART receiver and DMA controller together and providing done_interrupt when the transfer completes.

The included testbench (tb_top.v) simulates a serial RX line, sends 16 bytes (0xA1..0xB0), dumps waveforms to dump.vcd, and verifies that RAM contains the expected data.

Features

  • Asynchronous UART: 8N1 UART RX with midpoint sampling using a 100 MHz clock input.
  • Variable Block Size DMA: Transfer length is controlled by an 8-bit block_size input.
  • RAM Storage: Bytes are written into consecutive RAM addresses; the address increments on each received byte.

Tools Used

  • Icarus Verilog (for compilation and simulation)
  • GTKWave (for viewing dump.vcd)
  • Cursor (for development)

Simulation Results

Below is the GTKWave output showing the UART receiving data and the DMA controller writing it to sequential RAM addresses. Note the done_interrupt firing after the final byte.

Waveform Result

Technical Challenges & Solutions

Metastability & Synchronization: Since the external rx signal is asynchronous to the 100 MHz system clock, I implemented a 2-stage flip-flop synchronizer in the uart_rx module. This prevents metastable states from propagating into the FSM logic.

Precise Mid-bit Sampling: To ensure data integrity at 9600 baud, I designed a clock-divider-based tick generator that samples the incoming serial line at exactly 1.5 bit times after the start-bit edge, effectively capturing the data at its most stable midpoint.

Modular Flow Control: By using a FIFO buffer between the UART and the DMA, I decoupled the data reception from the memory write cycles. This ensures that even if the system bus is busy, no incoming UART bytes are dropped.

FSM-Based DMA Logic: The DMA was designed as a finite state machine to strictly manage the Request-Write-Increment cycle, ensuring that ram_we (Write Enable) is only pulsed when valid data is ready and the address pointer is correctly aligned.

How to Run

  1. Compile and simulate From the project directory:

    iverilog -o tb_top_sim tb_top.v top.v src/uart_rx.v src/dma_ctrl.v
    vvp tb_top_sim
  2. View results in GTKWave The testbench generates a VCD waveform file:

    • dump.vcd

    Open it in GTKWave:

    gtkwave dump.vcd

Signals / Interfaces (Quick Reference)

  • uart_rx:
    • Inputs: clk, rx
    • Outputs: rx_data[7:0], rx_done (pulse)
  • dma_ctrl:
    • Inputs: clk, rx_done, rx_data[7:0], block_size[7:0]
    • Outputs: ram_addr, ram_wdata, ram_we, done_interrupt (pulse)
  • top:
    • Inputs: clk, rst, rx, block_size[7:0]
    • Output: done_interrupt (pulse)

About

A synthesizable Verilog DMA controller for UART data movement with 100MHz clock synchronization.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors