FPGA Project: ADC → FFT → UART


This project reads analog signals using an ADC, performs FFT on the digital data in real time using FPGA, and sends the frequency-domain results to a PC via UART (serial port).
Project Overview
Flow Diagram
scss
Analog Signal
↓
[ ADC (e.g., SPI/I2C) ]
↓
[ FPGA ]
├─ Input Buffer
├─ FFT Core (Radix-2, 64 or 128 points)
└─ UART Transmitter
↓
PC Terminal (Plot FFT data)
Hardware Requirements
Component | Purpose |
FPGA Board | e.g., Xilinx Artix-7, Cyclone IV/V |
ADC Module | e.g., MCP3008 (SPI), AD7606 (Parallel) |
Clock Source | External oscillator or onboard clock |
Serial-USB Converter | e.g., FTDI, CH340 for UART output |
PC Terminal | e.g., PuTTY, RealTerm, or Python GUI |
Functional Blocks
1. ADC Interface (SPI or Parallel)
Connect ADC to FPGA.
Sample signal at regular intervals.
Store
N
samples (e.g., 64 or 128) in a buffer.
Example: MCP3008 (10-bit SPI ADC)
Use SPI master FSM to read values and convert to 16-bit fixed-point numbers.
2. FFT Core (Custom or IP Core)
Use pipelined or iterative Radix-2 FFT.
Can be:
Xilinx FFT IP (Vivado)
Open-source FFT HDL core
Input:
N
samples (real only; imaginary = 0)Output: Complex frequency bins (magnitude or raw)
3. Magnitude Calculation (Optional)
Compute |X(k)| = √(Re² + Im²)
Use CORDIC or approximation (e.g.,
abs(Re) + abs(Im)/2
)
4. UART Transmitter
Transmit FFT output (e.g., 64 magnitudes) at baud rate like 115200
Packet structure: Start byte → data → Stop byte
verilog
// UART byte-wise output FSM
always @(posedge clk) begin
case (state)
SEND_START: tx_data <= 8'hAA;
SEND_DATA: tx_data <= fft_result[counter];
SEND_END: tx_data <= 8'h55;
endcase
end
Implementation Tips
FFT Word Length
Use fixed-point (e.g., Q1.15) to save logic
Scale down intermediate results to avoid overflow
Clock Domains
Use clock domain crossing if ADC and FFT run at different rates
FIFO buffer is helpful
UART Format
Send 8-bit or 16-bit FFT magnitudes
Add framing (start/stop byte) to avoid misalignment
Example Output (UART Stream)
css
[0xAA] [mag_bin0_H] [mag_bin0_L] ... [mag_bin63_H] [mag_bin63_L] [0x55]
PC-side Visualization (Python + PySerial)
python
import serial
import matplotlib.pyplot as plt
ser = serial.Serial('COM3', 115200)
while True:
if ser.read() == b'\xAA':
data = ser.read(128)
mags = [int.from_bytes(data[i:i+2], 'big') for i in range(0, 128, 2)]
plt.plot(mags)
plt.pause(0.01)
Summary
Block | Description |
ADC | Captures analog input |
FFT Core | Computes frequency spectrum |
UART Tx | Streams result to PC |
PC Software | Displays real-time FFT graph |
Subscribe to my newsletter
Read articles from ampheo directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
