Built for the Tang Nano 20K FPGA development board
## Source Files- top.sv: Top-level FPGA module connecting clocking, reset, the audio path, display bars, rendering, and HDMI output.
- reset_sync.sv: Asynchronous assert, synchronous deassert reset synchroniser. One instance per clock domain.
- hdmi_clock_gen.sv
- Generates pixel_clk and faster serial_clk for HDMI. Gowin Clock User Guide.
- video_sync.sv
- pixel_x, pixel_y: Current screen coordinates (0..1279, 0..719).
- de (Data Enable): High (1) inside the visible 1280 × 720 active area.
- hsync & vsync: Pulse high (1) during horizontal/vertical sync windows so the monitor can align each row and frame (used by hdmi_tx.sv).
- tmds_encoder.sv
- 8b/10b TMDS encoder implemented from User Guide (Chapter 3).
- hdmi_tx.sv
- Wraps the three TMDS encoders, OSER10 10:1 DDR serializers, and differential output buffers.
- bar_renderer.sv: Pixel multiplexing to draw bar graphics
- i2s_rx.sv: Driver for I2S microphone. Contains a synchroniser, a clock divider and a shift register.
- fft.sv: 64-point iterative FFT. Streams the magnitude of each of the 32 positive frequency bins to the display bars.
- spectrum_pattern_gen.sv: Synthetic animated bar heights for testing without audio input.
Flash to Tang Nano 20K
# flash volatile sram memory
make flash-sram
# flash nonvolatile memory
make flashrun isolated builds
~/oss-cad-suite/bin/yosys -p "read_verilog -sv [FILE_NAME].sv"Simulation
# Run default top integration test
make sim
# Run a specific testbench
make sim TB=hdmi_clock_gen_tb
make sim TB=top_tb
# View simulation waveforms in GTKWave / Surfer
make waves
make waves TB=hdmi_clock_gen_tb
# Run all testbenches
make testCheck Timing
# The final Max frequency lines count, earlier lines are estimates. Multiplier paths are not timed
make -B pnr 2>&1 | grep -E "Max frequency|ERROR"Format
make formatGenerate Diagrams
# One time install for the square-wired block diagrams
npm install -g netlistsvg@1.0.2
# Block diagrams of top, fft and bar_renderer in docs/images/diagrams/
make diagram
# Detailed gate-level schematic of one module in build/ (requires Graphviz)
make diagram-module MODULE=fftClean Build Files
make cleanCheck toolchain status
make check-toolsInstall OSS CAD Suite
make setup-toolchainTMDS encoding (Transition-Minimised Differential Signalling): A technology used to transmit high-speed digital video and audio data reliably over cables in interfaces like DVI and HDMI.
An HDMI cable does not have 10 separate wires for Red, 10 for Green, and 10 for Blue. It only has 1 differential pair per color channel. To squeeze all 10 bits of a pixel's TMDS symbol down a single wire before the next pixel arrives, hdmi_tx.sv uses a hardware Parallel-to-Serial converter (OSER10 — Output Serializer 10:1 DDR):
-
Pixel Clock (74.25 MHz): Evaluates pixel coordinates and RGB colour values once per pixel:
$$1650\text{ pixels wide} \times 750\text{ lines tall} \times 60\text{ frames/sec} = 74,250,000\text{ pixels/sec} = 74.25\text{ MHz}$$ - Serial Clock (371.25 MHz): Transmits 10-bit TMDS encoded colour data over HDMI pins.
-
Audio Clock (27 MHz): Onboard crystal clock for
i2s_rx.sv,fft.sv, and writes to the display bars. The single-cycle FFT butterfly is too slow to share the pixel clock.
The Phase-Locked Loop (PLL) generates the 371.25 MHz serial clock from the 27 MHz crystal, and CLKDIV divides it by 5 to generate the 74.25 MHz pixel clock.
PLL LOCK is asynchronous to every clock, so top.sv passes it through one reset_sync.sv per clock domain. Reset asserts immediately and releases on a clock edge.
- Active Resolution: 1280 × 720 = 921,600 pixels (Total frame with blanking: 1650 × 750 = 1,237,500 pixels)
- pixel_x [11:0]: 12-bit horizontal coordinate (2^11 = 2048 covers the 1280 active width and 1650 total line width; 12 bits [11:0] gives range 0..4095)
- pixel_y [11:0]: 12-bit vertical coordinate (matched to pixel_x width for consistency)
- FFT Hardware State Machine
S_COLLECT: Buffers 64 audio samples (n = 64) at bit-reversed indices (reverseBits(j)) so output bins emerge in normal order.S_BUTTERFLY: Steps sequential counter registers(s, k, j)acrossp = 6stages × 32 pairs = 192 clock cycles (1 butterfly/cycle) using Q1.15 fixed-point twiddle ROM tablessrc/rom/twiddle_*.hexS_MAGNITUDE: Computes magnitude for the 32 positive frequency bins to drive the display bars in the top level.
| INMP441 | Tang Nano 20K |
|---|---|
| VDD | 3V3 |
| GND | GND |
| L/R | GND (selects the left channel) |
| SCK | Pin 27 |
| WS | Pin 28 |
| SD | Pin 29 |

