From 5a64bf651c66f2da16cd3ae20ed9ba2489f40d7a Mon Sep 17 00:00:00 2001 From: Christian Perez Llamas <932644+chris-zen@users.noreply.github.com> Date: Thu, 10 Nov 2022 00:10:42 +0100 Subject: [PATCH] Buffer trait. Simpler config. --- embassy-nrf/src/i2s.rs | 122 +++++++++++++++++++----------------- examples/nrf/src/bin/i2s.rs | 7 +-- 2 files changed, 66 insertions(+), 63 deletions(-) diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs index 8752dfde..3f5491ee 100644 --- a/embassy-nrf/src/i2s.rs +++ b/embassy-nrf/src/i2s.rs @@ -284,7 +284,7 @@ impl<'d, T: Instance> I2S<'d, T> { /// Stops the I2S transfer and waits until it has stopped. #[inline(always)] - pub fn stop(&self) -> &Self { + pub async fn stop(&self) -> &Self { todo!() } @@ -307,10 +307,12 @@ impl<'d, T: Instance> I2S<'d, T> { /// Transmits the given `tx_buffer`. /// Buffer address must be 4 byte aligned and located in RAM. /// Returns a value that represents the in-progress DMA transfer. - // TODO Define a better interface for the input buffer #[allow(unused_mut)] - pub async fn tx(&mut self, ptr: *const u8, len: usize) -> Result<(), Error> { - self.output.tx(ptr, len).await + pub async fn tx(&mut self, buffer: B) -> Result<(), Error> + where + B: Buffer, + { + self.output.tx(buffer).await } fn apply_config(c: &CONFIG, config: &Config) { @@ -319,54 +321,12 @@ impl<'d, T: Instance> I2S<'d, T> { c.mckfreq.write(|w| w.mckfreq()._32mdiv16()); c.mode.write(|w| w.mode().master()); - c.ratio.write(|w| { - let ratio = w.ratio(); - match config.ratio { - Ratio::_32x => ratio._32x(), - Ratio::_48x => ratio._48x(), - Ratio::_64x => ratio._64x(), - Ratio::_96x => ratio._96x(), - Ratio::_128x => ratio._128x(), - Ratio::_192x => ratio._192x(), - Ratio::_256x => ratio._256x(), - Ratio::_384x => ratio._384x(), - Ratio::_512x => ratio._512x(), - } - }); - - c.swidth.write(|w| { - let swidth = w.swidth(); - match config.swidth { - SampleWidth::_8bit => swidth._8bit(), - SampleWidth::_16bit => swidth._16bit(), - SampleWidth::_24bit => swidth._24bit(), - } - }); - - c.align.write(|w| { - let align = w.align(); - match config.align { - Align::Left => align.left(), - Align::Right => align.right(), - } - }); - - c.format.write(|w| { - let format = w.format(); - match config.format { - Format::I2S => format.i2s(), - Format::Aligned => format.aligned(), - } - }); - - c.channels.write(|w| { - let channels = w.channels(); - match config.channels { - Channels::Stereo => channels.stereo(), - Channels::Left => channels.left(), - Channels::Right => channels.right(), - } - }); + c.ratio.write(|w| unsafe { w.ratio().bits(config.ratio.into()) }); + c.swidth.write(|w| unsafe { w.swidth().bits(config.swidth.into()) }); + c.align.write(|w| w.align().bit(config.align.into())); + c.format.write(|w| w.format().bit(config.format.into())); + c.channels + .write(|w| unsafe { w.channels().bits(config.channels.into()) }); } } @@ -374,18 +334,23 @@ impl<'d, T: Instance> I2sOutput<'d, T> { /// Transmits the given `tx_buffer`. /// Buffer address must be 4 byte aligned and located in RAM. /// Returns a value that represents the in-progress DMA transfer. - // TODO Define a better interface for the input buffer - pub async fn tx(&mut self, ptr: *const u8, len: usize) -> Result<(), Error> { + pub async fn tx(&mut self, buffer: B) -> Result<(), Error> + where + B: Buffer, + { + let ptr = buffer.bytes_ptr(); + let len = buffer.bytes_len(); + if ptr as u32 % 4 != 0 { return Err(Error::BufferMisaligned); } - let maxcnt = (len / (core::mem::size_of::() / core::mem::size_of::())) as u32; - if maxcnt > MAX_DMA_MAXCNT { - return Err(Error::BufferTooLong); - } if (ptr as usize) < SRAM_LOWER || (ptr as usize) > SRAM_UPPER { return Err(Error::DMABufferNotInDataMemory); } + let maxcnt = ((len + core::mem::size_of::() - 1) / core::mem::size_of::()) as u32; + if maxcnt > MAX_DMA_MAXCNT { + return Err(Error::BufferTooLong); + } let r = T::regs(); let _s = T::state(); @@ -401,6 +366,47 @@ impl<'d, T: Instance> I2sOutput<'d, T> { } } +pub trait Buffer: Sized { + fn bytes_ptr(&self) -> *const u8; + fn bytes_len(&self) -> usize; +} + +impl Buffer for &[u8] { + #[inline] + fn bytes_ptr(&self) -> *const u8 { + self.as_ptr() + } + + #[inline] + fn bytes_len(&self) -> usize { + self.len() + } +} + +impl Buffer for &[i16] { + #[inline] + fn bytes_ptr(&self) -> *const u8 { + self.as_ptr() as *const u8 + } + + #[inline] + fn bytes_len(&self) -> usize { + self.len() * core::mem::size_of::() + } +} + +impl Buffer for &[i32] { + #[inline] + fn bytes_ptr(&self) -> *const u8 { + self.as_ptr() as *const u8 + } + + #[inline] + fn bytes_len(&self) -> usize { + self.len() * core::mem::size_of::() + } +} + pub(crate) mod sealed { use core::sync::atomic::AtomicU8; diff --git a/examples/nrf/src/bin/i2s.rs b/examples/nrf/src/bin/i2s.rs index a395c714..e8ddb4a4 100644 --- a/examples/nrf/src/bin/i2s.rs +++ b/examples/nrf/src/bin/i2s.rs @@ -26,14 +26,11 @@ async fn main(_spawner: Spawner) { signal_buf.0[2 * x + 1] = triangle_wave(x as i32, len, 2048, 0, 1) as i16; } - let ptr = &signal_buf.0 as *const i16 as *const u8; - let len = signal_buf.0.len() * core::mem::size_of::(); - - i2s.start(); i2s.set_tx_enabled(true); + i2s.start(); loop { - match i2s.tx(ptr, len).await { + match i2s.tx(signal_buf.0.as_slice()).await { Ok(_) => todo!(), Err(_) => todo!(), };