An arbitrary waveform generator for the Terasic DE0 board (Altera Cyclone III
EP3C16F484C6). The FPGA produces 8-bit samples with a DDS phase accumulator
driving a 256/1024-point wave table, streams them to a host PC over UART, and
the PC plots the waveform in real time. Stage 3.0 adds a bidirectional command
protocol so the PC can upload arbitrary user wave tables into FPGA RAM.
The repo is split into two self-contained stages, each compiles, downloads, and runs independently:
| Folder | Stage | One line |
|---|---|---|
stage-2.0/ |
2.0 — production-ready | ROM-backed sine / triangle / square / sawtooth, switch-selectable waveform and frequency, FPGA → PC sample stream, PC GUI viewer. |
stage-3.0/ |
3.0 — in progress (sub-stage 3.1 delivered) | RAM replaces ROM, PC ↔ FPGA framed protocol, PC can upload wave tables; later sub-stages add continuously variable frequency (3.3) and amplitude scaling (3.4). |
- Board Terasic DE0 (Altera Cyclone III
EP3C16F484C6) - Synthesis Quartus II 13.0 SP1 — newer Quartus has dropped Cyclone III support
- Programmer USB-Blaster — on Apple Silicon + Parallels Win11 ARM, the ARM64-signed driver is required
- Serial bridge USB-TTL adapter (CH340 or similar) wired to header J4 (GPIO0)
- Host Python 3.10+,
pyserial+numpy+matplotlib/PyQt6(see each stage'spc/requirements.txt)
SW[3:2] freq ─┐
SW[1:0] wave ─┤ ┌─────────┐
▼ ▼ │ 50 MHz
┌────────────┐ ┌──────────────┐ │
│ phase_acc │──▶│ wave_rom 1Kx8│──┘
└────────────┘ └──────┬───────┘
│ 8-bit sample @ 2 kHz
▼
┌─────────────┐
│ frame pack │ AA 55 wid freq sample
└─────┬───────┘
▼ 115200 8N1
┌─────────────┐
│ uart_tx │──────────▶ PC (matplotlib / Qt)
└─────────────┘
55 A5 CMD LEN PAYLOAD... CKSUM
CKSUM = (CMD + LEN + sum(payload)) & 0xFF
AA 55 TYPE LEN_L LEN_H PAYLOAD... CKSUM
CKSUM = (TYPE + LEN_L + LEN_H + sum(payload)) & 0xFF
Stage 3.1 commands: 0x10 ping, 0x20 upload-begin, 0x21 upload-chunk,
0x22 upload-commit, 0x23 upload-abort, 0x24 request-status. Responses:
0x81 ACK, 0x83 upload-status. All multi-byte fields are little-endian.
CLOCK_50 G21
KEY[0] H2 active-low pushbutton (BUTTON0)
SW[0..3] J6 H5 H6 G4
LEDG[0..3] J1 J2 J3 H1
UART_TXD AB16 J4 GPIO0 pin 2 (FPGA out → USB-TTL RXD)
UART_RXD AA16 J4 GPIO0 pin 4 (FPGA in ← USB-TTL TXD)
GND J4 GPIO0 pin 12
Note: the silkscreen
RS-232on DE0 marks test pads, not a DB9 header, and is not the UART used here. Wire the USB-TTL adapter to J4 GPIO0; do not use J5.
1. Open stage-2.0/429.qpf in Quartus II 13.0 SP1; press Ctrl+L to compile.
2. Programmer → output_files/429.sof, tick Program/Configure, Start.
3. cd stage-2.0/pc && pip install -r requirements.txt
4. python plot_wave.py COM3 (or run.bat on Windows)
5. SW[1:0] selects waveform, SW[3:2] selects frequency, KEY[0] resets.
For stage 3.0, follow the same compile + download flow, then launch
pc/run_qt_v3.bat and use the GUI's Ping / Upload / Status buttons.
stage-X.Y/
├── 429.qpf 429.qsf Quartus project
├── rtl/ Verilog sources
├── sim/ ModelSim testbench
├── mif/ MATLAB script + .mif for the wave table
└── pc/ PC-side Python GUI and Windows launchers
MIT — see LICENSE.
DE0 is a Terasic product. Cyclone III has been removed from current Quartus releases, so this project pins the toolchain to Quartus II 13.0 SP1.
A complete FPGA + PC pipeline implementing 7 envelope extraction algorithms for a 10 MHz ultrasonic RF echo trace (50 MSPS, 14-bit signed). The system performs 3-peak detection (excitation residual + 2 interface reflections), computes inter-peak distances
Two parallel Quartus projects share the same datapath, differing only in the envelope-method bank:
| Project | RTL bank | Use case |
|---|---|---|
stage-4.0/ (core) |
env_abs / env_square / env_hilbert / env_quadrature |
The 4 classical methods from the course brief |
stage-4.0-extra/ (extension) |
env_tkeo / env_rms / env_power |
TKEO, sliding RMS, square-law detector — the +bonus methods |
Common downstream modules (peak_detect, tx_framer, UART, top 7-seg display) are bit-identical across both projects.
ROM(a.mif, 2048×14b) ──┐
├─► env_X (one of 7) ──► peak_detect (3 peaks, GUARD=64)
replay_ctrl ───────────┘ │
├──► HEX 7-seg (d12 in 0.1 mm)
└──► tx_framer ──► UART_TX
│
▼
Qt GUI (PyQt5 + pyqtgraph) on PC
SYNC(2) | LEN(2) | ALGO(1) | RSV(1) | DATA(4096) | META(24) | TAIL(2)
META holds 12 ×16-bit fields: idx1, idx2, idx3, peak1, peak2, peak3, dn12, dn23, dist12_0p1mm, dist23_0p1mm, delay_us_q8, round_us_q8.
All 7 methods converge to
- Flash
stage-4.0/de0.sof(or-extra/extra.sof) to the DE0 board. pip install pyserial PyQt5 pyqtgraph numpy matplotlibon the PC.python stage-4.0/pc/uart_gui.py— pick the COM port, click "方法1..4" buttons.- Reproduce results offline:
python stage-4.0/pc/verify_envelope.py.
Full theory derivation, RTL block diagrams, bit-level frame decoding and 7-method comparison are in docs/stage-4-ultrasonic-envelope-report.pdf (17 pages).