Skip to content

Commit

Permalink
Use AsMut for SPI buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
GrantM11235 committed Dec 8, 2024
1 parent 7ceede3 commit 9a7e17c
Showing 1 changed file with 40 additions and 12 deletions.
52 changes: 40 additions & 12 deletions mipidsi/src/interface/spi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,44 @@ pub enum SpiError<SPI, DC> {
/// The buffer is used to gather batches of pixel data to be sent over SPI.
/// Larger buffers will genererally be faster (with diminishing returns), at the expense of using more RAM.
/// The buffer should be at least big enough to hold a few pixels of data.
pub struct SpiInterface<'a, SPI, DC> {
///
/// The buffer can be any type that implements [`AsMut<[u8]>`](AsMut) such as
/// - Mutable slices, `&mut [u8]`
/// - Owned arrays, `[u8; N]`
/// - Or even heap types like `Box<[u8]>` or `Vec<u8>`
///
/// # Examples:
///
/// Slice buffer
/// ```rust
/// # use mipidsi::interface::SpiInterface;
/// # let spi = mipidsi::_mock::MockSpi;
/// # let dc = mipidsi::_mock::MockOutputPin;
/// let mut buffer = [0_u8; 128];
/// let iface = SpiInterface::new(spi, dc, &mut buffer);
/// ```
///
/// Array buffer
/// ```rust
/// # use mipidsi::interface::SpiInterface;
/// # let spi = mipidsi::_mock::MockSpi;
/// # let dc = mipidsi::_mock::MockOutputPin;
/// let iface = SpiInterface::new(spi, dc, [0_u8; 128]);
/// ```
pub struct SpiInterface<SPI, DC, B> {
spi: SPI,
dc: DC,
buffer: &'a mut [u8],
buffer: B,
}

impl<'a, SPI: SpiDevice, DC: OutputPin> SpiInterface<'a, SPI, DC> {
impl<SPI: SpiDevice, DC: OutputPin, B: AsMut<[u8]>> SpiInterface<SPI, DC, B> {
/// Create new interface
pub fn new(spi: SPI, dc: DC, buffer: &'a mut [u8]) -> Self {
pub fn new(spi: SPI, dc: DC, buffer: B) -> Self {
Self { spi, dc, buffer }
}
}

impl<SPI: SpiDevice, DC: OutputPin> Interface for SpiInterface<'_, SPI, DC> {
impl<SPI: SpiDevice, DC: OutputPin, B: AsMut<[u8]>> Interface for SpiInterface<SPI, DC, B> {
type Word = u8;
type Error = SpiError<SPI::Error, DC::Error>;

Expand All @@ -47,12 +71,14 @@ impl<SPI: SpiDevice, DC: OutputPin> Interface for SpiInterface<'_, SPI, DC> {
) -> Result<(), Self::Error> {
let mut arrays = pixels.into_iter();

assert!(self.buffer.len() >= N);
let buffer = self.buffer.as_mut();

assert!(buffer.len() >= N);

let mut done = false;
while !done {
let mut i = 0;
for chunk in self.buffer.chunks_exact_mut(N) {
for chunk in buffer.chunks_exact_mut(N) {
if let Some(array) = arrays.next() {
let chunk: &mut [u8; N] = chunk.try_into().unwrap();
*chunk = array;
Expand All @@ -62,7 +88,7 @@ impl<SPI: SpiDevice, DC: OutputPin> Interface for SpiInterface<'_, SPI, DC> {
break;
};
}
self.spi.write(&self.buffer[..i]).map_err(SpiError::Spi)?;
self.spi.write(&buffer[..i]).map_err(SpiError::Spi)?;
}
Ok(())
}
Expand All @@ -72,23 +98,25 @@ impl<SPI: SpiDevice, DC: OutputPin> Interface for SpiInterface<'_, SPI, DC> {
pixel: [Self::Word; N],
count: u32,
) -> Result<(), Self::Error> {
let fill_count = core::cmp::min(count, (self.buffer.len() / N) as u32);
let buffer = self.buffer.as_mut();

let fill_count = core::cmp::min(count, (buffer.len() / N) as u32);
let filled_len = fill_count as usize * N;
for chunk in self.buffer[..(filled_len)].chunks_exact_mut(N) {
for chunk in buffer[..(filled_len)].chunks_exact_mut(N) {
let chunk: &mut [u8; N] = chunk.try_into().unwrap();
*chunk = pixel;
}

let mut count = count;
while count >= fill_count {
self.spi
.write(&self.buffer[..filled_len])
.write(&buffer[..filled_len])
.map_err(SpiError::Spi)?;
count -= fill_count;
}
if count != 0 {
self.spi
.write(&self.buffer[..(count as usize * pixel.len())])
.write(&buffer[..(count as usize * pixel.len())])
.map_err(SpiError::Spi)?;
}
Ok(())
Expand Down

0 comments on commit 9a7e17c

Please sign in to comment.