LED display bugs are unusually visual: a single missed clock becomes a shifted column, an unsafe latch becomes a flash, and a clock-domain error becomes a torn frame. The fastest path to a fix is to translate the visible symptom into a timing hypothesis, then prove or reject it with a test pattern, assertion, oscilloscope, or logic analyzer.
Symptom-to-cause map
| Symptom | Likely causes |
|---|---|
| Whole display flickers | Low refresh rate, irregular frame timing, power droop |
| Faint previous row | OE active during latch or address change, insufficient blanking |
| Image shifted one column | Wrong clock count, block-RAM latency, data changed on wrong edge |
| Red and blue exchanged | Connector or bit-order mismatch |
| Horizontal tear | Framebuffer changed before frame boundary |
| Low-level shimmer | LSB dwell too short, jitter, unsynchronized brightness update |
| Camera bands | Refresh interaction with exposure or rolling shutter |
Use diagnostic patterns
- Solid red, green, and blue reveal channel mapping.
- Alternating columns reveal shift direction and off-by-one clocks.
- A single moving pixel reveals row/column addressing.
- One bitplane at a time reveals dwell-weight errors.
- A gray ramp reveals gamma, missing low bits, and framebuffer format mistakes.
Probe the timing contract
Capture CLK, LAT, OE, row address, and at least one color data line. Trigger on LAT. Count column clocks between latches, measure how long OE remains active for each plane, and confirm the row address is stable before light is enabled. A passthrough adapter or spare test points make this much easier than probing a ribbon cable.
Turn expectations into assertions
// Outputs must be blank while latching.
assert property (@(posedge clk) lat |-> oe_n);
// A bank swap is legal only at the frame boundary.
assert property (@(posedge clk) $changed(front_bank) |-> $past(frame_done));
// The serializer emits exactly COLUMNS rising edges per row/plane.
assert property (@(posedge clk) latch_event |-> shift_count == COLUMNS);
Separate logic faults from electrical faults
If the FPGA waveform is correct but the panel is not, inspect voltage levels, ground bounce, cable length, edge rate, current-supply wiring, and connector orientation. Reduce brightness and display one channel; if the failure changes with total current, power integrity is a stronger suspect than bitplane math.
A disciplined debug order
- Verify the clock and reset.
- Verify active polarities with a static output.
- Count shifts and check data setup around the external clock.
- Check blank-latch-address-enable ordering.
- Measure row and frame rates.
- Enable one bitplane, then add planes.
- Add framebuffer swaps only after static frames are clean.
- Finally test maximum brightness, cable length, and camera behavior.
Change one variable at a time and save known-good captures. LED controllers become manageable when every visible artifact is tied back to a small timing contract that can be measured.
FPGA LED controller tutorial series
This article is part of the FPGA LED Controller Tutorials learning path. Continue with PWM vs. BCM, the HUB75 timing calculator, or SystemVerilog verification.
Leave a Reply