A HUB75 controller has to shift every column, pulse the latch, settle the row address, blank the outputs, and display every BCM plane for every row group. Use this calculator to estimate whether the requested panel geometry, pixel clock, scan ratio, and color depth can meet the target refresh rate.
Estimate assumes shifting and display dwell do not overlap. Confirm the exact panel timing and measure the finished hardware.
What the calculator models
VHDL-2008 reference implementation
This article uses synthesizable VHDL-2008. The complete tested VHDL bundle is linked below; adapt clock constraints, I/O standards, and timing parameters to the target board and panel.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity hub75_row_scanner is
generic (COLUMNS : positive := 64; ROW_GROUPS : positive := 16);
port (
clk : in std_logic;
rst : in std_logic;
dwell_done: in std_logic;
pixel_bits: in std_logic_vector(5 downto 0);
hub_clk : out std_logic;
lat : out std_logic;
oe_n : out std_logic;
row_addr : out natural range 0 to ROW_GROUPS - 1;
rgb : out std_logic_vector(5 downto 0)
);
end entity;
architecture rtl of hub75_row_scanner is
type state_t is (blank, shift_low, shift_high, latch, set_row, display);
signal state : state_t := blank;
signal col : natural range 0 to COLUMNS - 1 := 0;
signal row : natural range 0 to ROW_GROUPS - 1 := 0;
begin
process (clk)
begin
if rising_edge(clk) then
if rst = '1' then
state <= blank; col <= 0; row <= 0;
else
case state is
when blank => col <= 0; state <= shift_low;
when shift_low => state <= shift_high;
when shift_high => if col = COLUMNS - 1 then state <= latch; else col <= col + 1; state <= shift_low; end if;
when latch => state <= set_row;
when set_row => state <= display;
when display => if dwell_done = '1' then if row = ROW_GROUPS - 1 then row <= 0; else row <= row + 1; end if; state <= blank; end if;
end case;
end if;
end if;
end process;
hub_clk <= '1' when state = shift_high else '0';
lat <= '1' when state = latch else '0';
oe_n <= '0' when state = display else '1';
row_addr <= row;
rgb <= pixel_bits when state = shift_low else (others => '0');
end architecture;
Download the VHDL-2008 FPGA LED controller examples
For each row group and bitplane, the controller shifts one column word per pixel-clock tick and pays a fixed overhead for blanking, latching, and address settling. Binary-coded modulation then adds weighted display time. The estimate is:
frame clocks = row groups × [bitplanes × (columns + overhead) + base dwell × (2bits − 1)]
The maximum full-frame refresh is the pixel clock divided by that total. This is a planning model, not a substitute for the panel’s electrical timing. Some architectures shift the next plane while displaying the current one; that overlap improves the result and should be modeled separately.
How to enter the scan ratio
A 64×32 panel marked 1/16 scan has 16 row addresses. HUB75 normally shifts two RGB pixels in parallel, one in the upper half and one in the lower half, so the number of row groups is 16—not 32. A 1/32-scan panel uses 32 row addresses. Confirm the exact panel because identical connectors do not guarantee identical internal mapping.
Worked example
Consider a 64-column, 1/16-scan panel at a 20 MHz pixel clock with eight BCM bits, two overhead clocks per plane, and a base dwell of two clocks. The controller must pay the 64-column shift cost eight times for each row group, plus 255 weighted dwell units. Increasing the base dwell improves settling margin but lowers refresh. Increasing color depth adds another shift transaction and nearly doubles the weighted dwell range.
Interpret the result conservatively
- Below 100 Hz: visible flicker is likely and cameras will usually show severe bands.
- 100–200 Hz: may look steady to the eye but remains camera-sensitive.
- 200–400 Hz: a practical starting range for many installations.
- Above 400 Hz: offers more camera margin, but optical behavior still depends on plane order and exposure.
These are engineering heuristics, not universal thresholds. Validate the final hardware with an oscilloscope or photodiode, the intended brightness, and the actual camera exposure conditions.
If the budget fails
- Reduce color depth or use temporal dithering for the lowest bits.
- Increase the shift clock within the panel and level-shifter limits.
- Overlap shifting with the current display dwell using a separate output latch.
- Split or reorder the most-significant planes without changing total weight.
- Drive several panel chains in parallel instead of extending one serial chain.
- Use a driver that generates grayscale locally when architecture permits.
Continue the design
Read HUB75 signals and row scanning for the safe transaction sequence, then the deeper refresh-rate derivation. The complete FPGA LED controller series connects those topics to BCM, framebuffers, and verification.
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 VHDL-2008 verification.