pub struct DmaFrameBuffer<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> { /* private fields */ }Expand description
DMA-compatible framebuffer for HUB75 LED panels.
This is a framebuffer implementation that:
- Manages multiple frames for Binary Code Modulation (BCM)
- Provides DMA-compatible memory layout
- Implements the embedded-graphics
DrawTargettrait
§Type Parameters
ROWS: Total number of rows in the panelCOLS: Number of columns in the panelNROWS: Number of rows per scan (typically half of ROWS)BITS: Color depth (1-8 bits)FRAME_COUNT: Number of frames used for Binary Code Modulation
§Helper Functions
Use these functions to compute the correct values:
esp_hub75::compute_frame_count(BITS): Computes the required number of framesesp_hub75::compute_rows(ROWS): Computes the number of rows per scan
§Memory Layout
The buffer is aligned to ensure efficient DMA transfers and contains:
- A 64-bit alignment field
- An array of frames, each containing the full panel data
Implementations§
Source§impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
Sourcepub const fn new() -> Self
pub const fn new() -> Self
Create a new, ready-to-use framebuffer.
This creates a new framebuffer and automatically formats it with proper timing signals. The framebuffer is immediately ready for pixel operations and DMA transfers.
§Panics
Panics if BITS is greater than 8, as only 1-8 bit color depths are
supported. With the esp32-ordering feature, also panics if COLS is
not even (the ESP32’s byte-order swap requires an even column count).
§Example
use hub75_framebuffer::{Color,plain::DmaFrameBuffer,compute_rows,compute_frame_count};
const ROWS: usize = 32;
const COLS: usize = 64;
const BITS: u8 = 3; // Color depth (8 brightness levels, 7 frames)
const NROWS: usize = compute_rows(ROWS); // Number of rows per scan
const FRAME_COUNT: usize = compute_frame_count(BITS); // Number of frames for BCM
let mut framebuffer = DmaFrameBuffer::<ROWS, COLS, NROWS, BITS, FRAME_COUNT>::new();
// No need to call format() - framebuffer is ready to use!§Memory placement (⚠️ large buffer)
This framebuffer is a large inline array: one 16-bit word per pixel
clock per frame, for (2^BITS)-1 frames. For a 64×64 panel at
3-bit depth that is already tens of kilobytes, and it grows
exponentially with BITS. Never bind it to a task-local let —
that places the whole buffer on the task stack and overflows it.
The framebuffer is mutable, so give it a 'static home that hands
out &'static mut without unsafe — static mut is not an
option. Use static_cell::StaticCell. See the crate-level
Memory placement section for a worked example.
Sourcepub const fn bcm_chunk_count() -> usize
👎Deprecated since 0.11.0: use BCM_SEQUENCE instead
pub const fn bcm_chunk_count() -> usize
use BCM_SEQUENCE instead
Returns the number of BCM chunks in this framebuffer (always 1 for single-plane framebuffers — the entire buffer is one contiguous chunk).
Sourcepub const fn bcm_chunk_bytes() -> usize
👎Deprecated since 0.11.0: use BCM_SEQUENCE instead
pub const fn bcm_chunk_bytes() -> usize
use BCM_SEQUENCE instead
Returns the byte size of one BCM chunk (for single-plane framebuffers this equals the total DMA buffer size including the tail word, since BCM weighting is baked in).
Sourcepub const fn format(&mut self)
pub const fn format(&mut self)
Perform full formatting of the framebuffer with timing and control signals.
This sets up all the timing and control signals needed for proper HUB75 operation.
This is automatically called by new(), so you typically don’t need to call this
unless you want to completely reinitialize the framebuffer.
§Example
use hub75_framebuffer::{Color,plain::DmaFrameBuffer,compute_rows,compute_frame_count};
const ROWS: usize = 32;
const COLS: usize = 64;
const BITS: u8 = 3; // Color depth (8 brightness levels, 7 frames)
const NROWS: usize = compute_rows(ROWS); // Number of rows per scan
const FRAME_COUNT: usize = compute_frame_count(BITS); // Number of frames for BCM
let mut framebuffer = DmaFrameBuffer::<ROWS, COLS, NROWS, BITS, FRAME_COUNT>::new();
framebuffer.format(); // Reinitialize if neededSourcepub fn erase(&mut self)
pub fn erase(&mut self)
Fast erase operation that clears all pixel data while preserving timing signals.
This is much faster than format() when you just want to clear the display
since it preserves all the timing and control signals that are already set up.
Use this for clearing between frames or when you want to start drawing fresh content.
§Example
use hub75_framebuffer::{Color,plain::DmaFrameBuffer,compute_rows,compute_frame_count};
const ROWS: usize = 32;
const COLS: usize = 64;
const BITS: u8 = 3; // Color depth (8 brightness levels, 7 frames)
const NROWS: usize = compute_rows(ROWS); // Number of rows per scan
const FRAME_COUNT: usize = compute_frame_count(BITS); // Number of frames for BCM
let mut framebuffer = DmaFrameBuffer::<ROWS, COLS, NROWS, BITS, FRAME_COUNT>::new();
framebuffer.erase();Sourcepub fn set_pixel(&mut self, p: Point, color: Color)
pub fn set_pixel(&mut self, p: Point, color: Color)
Set a pixel in the framebuffer.
§Example
use hub75_framebuffer::{Color,plain::DmaFrameBuffer,compute_rows,compute_frame_count};
use embedded_graphics::prelude::*;
const ROWS: usize = 32;
const COLS: usize = 64;
const BITS: u8 = 3; // Color depth (8 brightness levels, 7 frames)
const NROWS: usize = compute_rows(ROWS); // Number of rows per scan
const FRAME_COUNT: usize = compute_frame_count(BITS); // Number of frames for BCM
let mut framebuffer = DmaFrameBuffer::<ROWS, COLS, NROWS, BITS, FRAME_COUNT>::new();
framebuffer.set_pixel(Point::new(10, 10), Color::RED);Trait Implementations§
Source§impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> Clone for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> Clone for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> Copy for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
Source§impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> Debug for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> Debug for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
Source§impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> Default for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> Default for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
Source§impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> DrawTarget for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> DrawTarget for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
Source§fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
Source§fn fill_contiguous<I>(
&mut self,
area: &Rectangle,
colors: I,
) -> Result<(), Self::Error>where
I: IntoIterator<Item = Self::Color>,
fn fill_contiguous<I>(
&mut self,
area: &Rectangle,
colors: I,
) -> Result<(), Self::Error>where
I: IntoIterator<Item = Self::Color>,
Source§impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> FrameBuffer for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> FrameBuffer for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
Source§const BCM_SEQUENCE: [BcmLenReps; 10]
const BCM_SEQUENCE: [BcmLenReps; 10]
(len, reps) of the segments in one sequence, in scan
order. Read moreSource§const BCM_SEQUENCE_LEN: usize = 1
const BCM_SEQUENCE_LEN: usize = 1
BCM_SEQUENCE.Source§const BCM_SEQUENCE_COUNT: usize = 1
const BCM_SEQUENCE_COUNT: usize = 1
NROWS for row-major framebuffers (one sequence per row), 1
for frame-major and threshold framebuffers (the sequence covers
the whole frame).Source§type Word = u16
type Word = u16
u8 for latched, u16
for direct-drive). Driver implementations can use this to enforce that pin
configurations match the framebuffer at compile time.Source§fn bcm_segment_ptr(&self, index: usize) -> *const u8
fn bcm_segment_ptr(&self, index: usize) -> *const u8
index-th BCM segment. Read moreSource§const BCM_SEGMENT_COUNT: usize = _
const BCM_SEGMENT_COUNT: usize = _
Source§const BCM_SEGMENTS_PER_GROUP: usize = 1
const BCM_SEGMENTS_PER_GROUP: usize = 1
BCM_SEQUENCE_LEN: groups never straddle
a sequence boundary. Read moreSource§fn bcm_segment_count(&self) -> usize
fn bcm_segment_count(&self) -> usize
Source§fn bcm_segment(&self, index: usize) -> BcmSegment
fn bcm_segment(&self, index: usize) -> BcmSegment
index-th BCM segment. Read more