Build FPGA LED controllers from a single PWM output to a multiplexed HUB75 RGB matrix. This learning path connects the timing math, synthesizable SystemVerilog, self-checking simulations, framebuffer architecture, clock-domain crossing, and hardware debugging into one practical series.
Choose your starting point
| If you want to… | Start here |
|---|---|
| Dim one LED or learn the core timing pattern | Parameterized FPGA PWM dimmer |
| Drive many channels with shared weighted timing | 8-bit binary-coded modulation engine |
| Bring up an RGB matrix safely | HUB75 signals and row scanning |
| Check whether a panel timing budget is possible | Interactive HUB75 timing calculator |
| Diagnose flicker, ghosting, tearing, or wrong colors | FPGA LED debugging guide |
1. Learn brightness timing
Start with one output. The PWM tutorial shows how a counter becomes a time axis, why resolution reduces carrier frequency, and how to latch brightness at a period boundary. The BCM tutorial reorganizes the same average duty cycle into weighted bitplanes. Read the comparison when choosing between them.
- FPGA PWM LED Dimmer in SystemVerilog
- Binary-Coded Modulation on FPGA
- FPGA PWM vs. BCM: which method should you use?
- Center-Aligned vs. Edge-Aligned PWM
- Gamma-Corrected LED Dimming With a Lookup Table
2. Scale to displays and matrices
A multiplexed display adds row selection, shifting, blanking, latching, memory bandwidth, and a hard refresh deadline. Work through the row scanner before increasing color depth. The calculator converts panel geometry, scan ratio, pixel clock, and bit depth into an estimated maximum refresh rate.
- Ghost-Free Seven-Segment Display Controller
- HUB75 Signals and Row Scanning
- HUB75 Refresh-Rate Math
- HUB75 Timing Calculator
- Double-Buffered FPGA LED Framebuffer With Block RAM
3. Connect drivers and clock domains
Dedicated LED drivers move some or all grayscale timing out of the FPGA. That can simplify refresh but introduces device-specific serial packing and latch rules. If pixels arrive from software, Ethernet, a camera, or another clock domain, transfer ownership at a frame boundary rather than crossing a multi-bit framebuffer address bus casually.
- External PWM Bitframes vs. 16-Bit Grayscale
- Driving TLC5940 and TLC5955 LED Drivers From an FPGA
- Clock Domain Crossing for Tear-Free LED Updates
4. Verify before hardware
A controller is easier to trust when the testbench checks behavior instead of requiring a human to stare at every waveform. The downloadable project uses executable invariants: PWM high clocks match the requested level, BCM illuminated slots sum to the numeric code, and HUB75 never latches while outputs are enabled.
- FPGA LED Controller Verification With SystemVerilog Assertions
- Debugging Flicker, Ghosting, Tearing, and Wrong Colors
Download and run the complete examples
The project contains synthesizable modules and self-checking testbenches for PWM, BCM, and HUB75 row scanning. It is deliberately vendor-neutral and runs with Icarus Verilog:
unzip fpga-led-controller-examples.zip
cd fpga-led-controller-examples
make test
All tests were executed before publication. Treat the modules as readable reference designs: adapt pin constraints, I/O voltage, clocking, memory latency, scan ratio, and external-driver timing for the exact FPGA board and LED hardware.
Hardware safety
FPGA pins generate logic-level signals; they do not power LED matrices or high-current emitters. Use the panel’s intended power connector, adequate wiring and fusing, a shared ground, and level shifting when the electrical specification requires it. Confirm active polarity before enabling outputs.