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 with external latch circuit support.
This implementation is optimized for memory usage and external latch circuit support:
- Uses 8-bit entries instead of 16-bit
- Separates address and data words
- Supports the external latch circuit for row selection
- 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:
- An array of frames, each containing the full panel data
- Each frame contains NROWS rows
- Each row contains both data and address words
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 framebuffer with the given number of frames. The framebuffer is automatically formatted and ready to use.
§Panics
With the esp32-ordering feature, panics if COLS is not
divisible by 4 (the ESP32’s byte-order rearrangement requires
column counts that are multiples of 4).
§Example
use hub75_framebuffer::{latched::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();
// Ready to use immediately§Memory placement (⚠️ large buffer)
This framebuffer is a large inline array of 8-bit words, one per
pixel clock per frame, for (2^BITS)-1 frames. Even at 8-bit
words the frame count grows exponentially with BITS, so the
buffer quickly reaches tens of kilobytes. 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, since BCM weighting is baked in).
Sourcepub const fn format(&mut self)
pub const fn format(&mut self)
Format the framebuffer, setting up all control bits and clearing pixel data.
This method does a full format of all control bits and clears all pixel data.
Normally you don’t need to call this as new() automatically formats the framebuffer.
§Example
use hub75_framebuffer::{Color,latched::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(); // Not needed - new() already calls thisSourcepub fn erase(&mut self)
pub fn erase(&mut self)
Erase pixel colors while preserving control bits.
This is much faster than format() and is the typical way to clear the display.
§Example
use hub75_framebuffer::{Color,latched::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();
// ... draw some pixels ...
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,latched::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 = u8
type Word = u8
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