Skip to content

Repository files navigation

ESP-HUB75

Crates.io Documentation License

A no-std Rust driver for HUB75-style LED matrix panels on ESP32-series microcontrollers. HUB75 is a standard interface for driving large, bright, and colorful RGB LED displays, commonly used in digital signage and art installations.

This library provides a high-performance implementation that uses Direct Memory Access (DMA) to drive the display with minimal CPU overhead. It is designed to work with a variety of ESP32 models, using the most efficient peripheral available on each chip:

  • ESP32-S3: Uses the LCD_CAM peripheral
  • ESP32-C6: Uses the PARL_IO peripheral
  • ESP32-C5: Uses the PARL_IO peripheral (8-bit mode only; requires a latch circuit and Hub75Pins8)
  • ESP32: Uses the I2S peripheral in parallel mode

The driver is built on top of the embedded-graphics crate, allowing you to easily draw shapes, text, and images on the display. It also uses a zero-copy framebuffer for efficient memory usage.

Framebuffers

The hub75-framebuffer crate provides two families of framebuffer: the standard framebuffers and the bitplane framebuffers. Each family has a direct-drive variant (16-bit, no external latch) and a latched variant (8-bit, requires an external address-latch circuit). Both families can be sent directly to the peripheral without any extra formatting step. The difference is how they achieve Binary Code Modulation (BCM):

  • Standard framebuffers (framebuffer::plain::DmaFrameBuffer / framebuffer::latched::DmaFrameBuffer) pre-render a complete copy of the pixel data for every BCM bit-weight. This makes DMA output straightforward but multiplies memory usage by the number of frames (frame_count).
  • Bitplane framebuffers (framebuffer::bitplane::plain::DmaFrameBuffer / framebuffer::bitplane::latched::DmaFrameBuffer) store only one bit per pixel per plane. The driver uses DMA descriptors to assemble the BCM output on the fly, avoiding the duplicated memory. The result is significantly lower RAM usage with the same visual quality.

Bitplane framebuffers are strongly recommended for most applications.

Hardware Requirements

  • An ESP32-series microcontroller (ESP32, ESP32-S3, ESP32-C5, or ESP32-C6)
  • A HUB75 LED matrix panel
  • A 5V power supply capable of providing several amps of current
  • A 3.3V to 5V level shifter (e.g., 74HCT245) is highly recommended

Note: The ESP32 operates at 3.3V, while HUB75 panels require 5V logic signals. While it may sometimes work without one, using a level shifter ensures reliable operation and prevents damage to your hardware.

Pin Configurations

This driver supports two types of HUB75 pin configurations, which you can select based on your hardware setup:

  • Hub75Pins16 (Direct Drive): This is the standard configuration where the row address lines are sent with every pixel. It requires more GPIO pins but works with any standard HUB75 panel.

  • Hub75Pins8 (Latched): This configuration is for controller boards that include an external 74HC574-style latch for the row address lines. This is more memory-efficient and requires fewer GPIO pins. For more details on the required circuit, see the hub75-framebuffer crate's documentation or its GitHub repository.

Examples

The following examples demonstrate how to use this crate with different ESP32 variants.

ESP32-S3 (LCD_CAM Interface)

ESP32-C6 / ESP32-C5 (PARL_IO Interface)

Note: The ESP32-C5 does not support 16-bit mode, so only the latched examples (parl_io_latch.rs) can be used with it.

ESP32 (I2S Parallel Interface)

Crate Features

  • esp32: Enable support for the ESP32
  • esp32s3: Enable support for the ESP32-S3
  • esp32c5: Enable support for the ESP32-C5
  • esp32c6: Enable support for the ESP32-C6
  • defmt: Enable logging with defmt
  • log: Enable logging with the log crate
  • invert-blank: Invert the blank signal. This only applies to 8-bit latched configurations (Hub75Pins8); in 16-bit direct-drive mode the blank signal is always active-low. Some latch controller boards include a hardware inverter on the blank line — enable this feature to compensate.
  • invert-clock: Invert the clock signal. By default the driver outputs data that changes on the falling edge of CLK so that it is stable when the panel latches on the rising edge. Enable this feature if your panel requires the opposite polarity.
  • full-chain-dma: Build the entire BCM repetition chain in a single DMA transfer instead of one plane per interrupt. This reduces interrupt frequency at the cost of more DMA descriptor RAM. Note that the ESP32-C6 PARL_IO peripheral has a 65 535-byte per-transfer limit, which constrains the maximum panel size and plane count when this feature is enabled.
  • circular-dma: Circular DMA descriptor chain (implies full-chain-dma). The DMA engine starts once and loops forever; buffer swaps are instant pointer-delta updates with no DMA stop/restart. A frame-boundary ISR is always active in this mode, providing both frame_count() and the completion signal for Hub75Swap::wait() / Hub75Swap::wait_for_done(). Only supported on ESP32 and ESP32-S3 — enabling this on ESP32-C5/C6 is a compile-time error because the PARL_IO peripheral does not support circular chains.
  • skip-black-pixels: Forwards to the hub75-framebuffer crate, enabling an optimization that skips writing black pixels to the framebuffer.
  • tail-closes-latch: Forwards to the hub75-framebuffer crate. Applies to plain and bitplane::plain framebuffers only (not the latched variants). Appends a single extra "tail" word at the end of each DMA buffer (plain) or at the end of each bit-plane (bitplane::plain) that parks the bus with LATCH=0 and OE=BLANK, cleanly terminating the transfer.
  • iram: Place the driver’s hot-path (render / DMA wait functions) in Instruction RAM (IRAM) to avoid flash-cache stalls (for example during Wi-Fi, PSRAM, or SPI-flash activity) that can cause visible flicker. Enabling this feature consumes roughly 5–10 KiB of IRAM.
  • lead-blank-1/2/4/8/16 / trail-blank-1/2/4/8/16: Forwards to hub75-framebuffer. Control the number of pixel-clock cycles of blanking (OE HIGH) inserted around row address changes. The lead blank controls blanking before the address change, and the trail blank controls blanking after. Higher values reduce ghosting at the cost of slightly less brightness.
  • inter-row-blank-4/8/16/32: Forwards to hub75-framebuffer. Insert additional dead clock cycles at the end of each row. In plain framebuffers the gap defers the address change to the first pixel of the next row, giving slow panels more time to finish blanking. In latched framebuffers the gap adds extra blanked cycles after the address change.

Known Working Panels

This library should work with any "normal" RGB matrix panels. The following panels have been tested and confirmed to work:

Panel Scan Rate Column Driver Row Driver
Waveshare RGB-Matrix-P3-64x64 1/32 SM5166 SM16208
Waveshare RGB-Matrix-P3-64x32 1/16 ICN2037 SM5166
Generic 64x32 1/16 DP5125D RUC7258E

Note: Help us grow this list! Please let us know of other working and non working panels/chips.

License

This project is dual-licensed under either of the following:

Contributing

We welcome contributions! Please feel free to submit a Pull Request.

By contributing, you agree that your submissions will be licensed under both the Apache-2.0 and MIT licenses.

Support

If you need help, please open an issue on our GitHub repository.

About

A no-std Rust library for driving HUB75 LED matrix displays from ESP32 series microcontrollers.

Topics

Resources

Stars

30 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages