Skip to main content

DmaFrameBuffer

Struct DmaFrameBuffer 

Source
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 DrawTarget trait

§Type Parameters

  • ROWS: Total number of rows in the panel
  • COLS: Number of columns in the panel
  • NROWS: 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 frames
  • esp_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>

Source

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.

Source

pub const fn bcm_chunk_count() -> usize

👎Deprecated since 0.11.0:

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).

Source

pub const fn bcm_chunk_bytes() -> usize

👎Deprecated since 0.11.0:

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).

Source

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 needed
Source

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();
Source

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>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

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>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
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>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
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>

Source§

type Color = Rgb888

The pixel color type the targetted display supports.
Source§

type Error = !

Error type to return when a drawing operation fails. Read more
Source§

fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where I: IntoIterator<Item = Pixel<Self::Color>>,

Draw individual pixels to the display without a defined order. Read more
Source§

fn fill_contiguous<I>( &mut self, area: &Rectangle, colors: I, ) -> Result<(), Self::Error>
where I: IntoIterator<Item = Self::Color>,

Fill a given area with an iterator providing a contiguous stream of pixel colors. Read more
Source§

fn fill_solid( &mut self, area: &Rectangle, color: Self::Color, ) -> Result<(), Self::Error>

Fill a given area with a solid color. Read more
Source§

fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error>

Fill the entire display with a solid color. Read more
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>

Source§

const BCM_SEQUENCE: [BcmLenReps; 10]

Static (len, reps) of the segments in one sequence, in scan order. Read more
Source§

const BCM_SEQUENCE_LEN: usize = 1

Number of BCM segments in one sequence, i.e. the number of meaningful entries in BCM_SEQUENCE.
Source§

const BCM_SEQUENCE_COUNT: usize = 1

Number of times the sequence repeats in one complete panel refresh: 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

The DMA word type used by this framebuffer (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

Returns the byte pointer for the index-th BCM segment. Read more
Source§

const BCM_SEGMENT_COUNT: usize = _

Total number of BCM segments streamed for one complete panel refresh (all rows, all planes). Read more
Source§

const BCM_SEGMENTS_PER_GROUP: usize = 1

Number of consecutive segments that a driver may chain into a single DMA transfer. Must divide BCM_SEQUENCE_LEN: groups never straddle a sequence boundary. Read more
Source§

fn bcm_segment_count(&self) -> usize

Total number of BCM segments streamed for one complete panel refresh. Read more
Source§

fn bcm_segment(&self, index: usize) -> BcmSegment

Returns the index-th BCM segment. Read more
Source§

fn bcm_segments_per_group(&self) -> usize

Number of consecutive segments that form one transfer group. Read more
Source§

impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> FrameBufferOperations for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>

Source§

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.
Source§

fn set_pixel(&mut self, p: Point, color: Color)

Set a pixel in the framebuffer.
Source§

impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> MutableFrameBuffer 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> OriginDimensions for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>

Source§

fn size(&self) -> Size

Returns the size of the bounding box.
Source§

impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> OriginDimensions for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>

Source§

fn size(&self) -> Size

Returns the size of the bounding box.

Auto Trait Implementations§

§

impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> Freeze for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
where FrameData<ROWS, COLS, NROWS, FRAME_COUNT>: Freeze,

§

impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> RefUnwindSafe for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
where FrameData<ROWS, COLS, NROWS, FRAME_COUNT>: RefUnwindSafe,

§

impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> Send for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
where FrameData<ROWS, COLS, NROWS, FRAME_COUNT>: Send,

§

impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> Sync for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
where FrameData<ROWS, COLS, NROWS, FRAME_COUNT>: Sync,

§

impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> Unpin for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
where FrameData<ROWS, COLS, NROWS, FRAME_COUNT>: Unpin,

§

impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> UnsafeUnpin for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
where FrameData<ROWS, COLS, NROWS, FRAME_COUNT>: UnsafeUnpin,

§

impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const BITS: u8, const FRAME_COUNT: usize> UnwindSafe for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
where FrameData<ROWS, COLS, NROWS, FRAME_COUNT>: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Az for T

Source§

fn az<Dst>(self) -> Dst
where T: Cast<Dst>,

Casts the value.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<Src, Dst> CastFrom<Src> for Dst
where Src: Cast<Dst>,

Source§

fn cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<T> CheckedAs for T

Source§

fn checked_as<Dst>(self) -> Option<Dst>
where T: CheckedCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> CheckedCastFrom<Src> for Dst
where Src: CheckedCast<Dst>,

Source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Dimensions for T

Source§

fn bounding_box(&self) -> Rectangle

Returns the bounding box.
Source§

impl<T> DrawTargetExt for T
where T: DrawTarget,

Source§

fn translated(&mut self, offset: Point) -> Translated<'_, T>

Creates a translated draw target based on this draw target. Read more
Source§

fn cropped(&mut self, area: &Rectangle) -> Cropped<'_, T>

Creates a cropped draw target based on this draw target. Read more
Source§

fn clipped(&mut self, area: &Rectangle) -> Clipped<'_, T>

Creates a clipped draw target based on this draw target. Read more
Source§

fn color_converted<C>(&mut self) -> ColorConverted<'_, T, C>
where C: PixelColor + Into<<T as DrawTarget>::Color>,

Creates a color conversion draw target. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> OverflowingAs for T

Source§

fn overflowing_as<Dst>(self) -> (Dst, bool)
where T: OverflowingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dst
where Src: OverflowingCast<Dst>,

Source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
Source§

impl<T> SaturatingAs for T

Source§

fn saturating_as<Dst>(self) -> Dst
where T: SaturatingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dst
where Src: SaturatingCast<Dst>,

Source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> UnwrappedAs for T

Source§

fn unwrapped_as<Dst>(self) -> Dst
where T: UnwrappedCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dst
where Src: UnwrappedCast<Dst>,

Source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<T> WrappingAs for T

Source§

fn wrapping_as<Dst>(self) -> Dst
where T: WrappingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> WrappingCastFrom<Src> for Dst
where Src: WrappingCast<Dst>,

Source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.