From a180cc107727255a3d7ca889afe30c7b693e43e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Alse=CC=81r?= Date: Wed, 2 Sep 2020 23:34:14 +0200 Subject: [PATCH 1/4] Use traits for I2S TX & RX --- examples/i2s-controller-demo/src/main.rs | 50 ++--- examples/i2s-peripheral-demo/Cargo.toml | 2 - examples/i2s-peripheral-demo/src/main.rs | 39 ++-- nrf-hal-common/src/i2s.rs | 236 ++++++++++++++++++++--- 4 files changed, 251 insertions(+), 76 deletions(-) diff --git a/examples/i2s-controller-demo/src/main.rs b/examples/i2s-controller-demo/src/main.rs index b487839b..f69604a0 100644 --- a/examples/i2s-controller-demo/src/main.rs +++ b/examples/i2s-controller-demo/src/main.rs @@ -14,6 +14,7 @@ use small_morse::{encode, State}; use { core::{ panic::PanicInfo, + pin, sync::atomic::{compiler_fence, Ordering}, }, hal::{ @@ -32,11 +33,11 @@ use { #[rtic::app(device = crate::hal::pac, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)] const APP: () = { struct Resources { - i2s: hal::i2s::I2S, - #[init([0; 32])] - signal_buf: [i16; 32], - #[init([0; 32])] - mute_buf: [i16; 32], + // i2s: hal::i2s::I2S, + // #[init([0; 32])] + signal_buf: pin::Pin<&'static [i16]>, + // #[init([0; 32])] + mute_buf: pin::Pin<&'static [i16]>, #[init(None)] queue: Option>, producer: Producer<'static, State, U256>, @@ -49,10 +50,20 @@ const APP: () = { btn1: Pin>, btn2: Pin>, led: Pin>, + transfer: Option>, } - #[init(resources = [queue, signal_buf, mute_buf], spawn = [tick])] + #[init(resources = [queue], spawn = [tick])] fn init(mut ctx: init::Context) -> init::LateResources { + static mut MUTE_BUF: [i16; 32] = [0i16; 32]; + static mut SIGNAL_BUF: [i16; 32] = [0i16; 32]; + // Fill signal buffer with triangle waveform, 2 channels interleaved + let len = SIGNAL_BUF.len() / 2; + for x in 0..len { + SIGNAL_BUF[2 * x] = triangle_wave(x as i32, len, 2048, 0, 1) as i16; + SIGNAL_BUF[2 * x + 1] = triangle_wave(x as i32, len, 2048, 0, 1) as i16; + } + let _clocks = hal::clocks::Clocks::new(ctx.device.CLOCK).enable_ext_hfosc(); // Enable the monotonic timer (CYCCNT) ctx.core.DCB.enable_trace(); @@ -75,16 +86,7 @@ const APP: () = { None, Some(&sdout_pin), ); - i2s.tx_buffer(&ctx.resources.mute_buf[..]).ok(); - i2s.enable().start(); - - // Fill signal buffer with triangle waveform, 2 channels interleaved - let signal_buf = ctx.resources.signal_buf; - let len = signal_buf.len() / 2; - for x in 0..len { - signal_buf[2 * x] = triangle_wave(x as i32, len, 2048, 0, 1) as i16; - signal_buf[2 * x + 1] = triangle_wave(x as i32, len, 2048, 0, 1) as i16; - } + i2s.start(); // Configure buttons let btn1 = p0.p0_11.into_pullup_input().degrade(); @@ -117,7 +119,6 @@ const APP: () = { ctx.spawn.tick().ok(); init::LateResources { - i2s, producer, consumer, gpiote, @@ -126,6 +127,9 @@ const APP: () = { led: p0.p0_13.into_push_pull_output(Level::High).degrade(), uarte, uarte_timer: Timer::new(ctx.device.TIMER0), + transfer: i2s.tx(pin::Pin::new(&MUTE_BUF[..])).ok(), + signal_buf: pin::Pin::new(&SIGNAL_BUF[..]), + mute_buf: pin::Pin::new(&MUTE_BUF[..]), } } @@ -150,7 +154,7 @@ const APP: () = { } } Err(hal::uarte::Error::Timeout(n)) if n > 0 => { - if let Ok(msg) = core::str::from_utf8(&uarte_rx_buf[0..n]) { + if let Ok(msg) = core::str::from_utf8(&uarte_rx_buf[..n]) { rprintln!("{}", msg); for action in encode(msg) { for _ in 0..action.duration { @@ -164,18 +168,18 @@ const APP: () = { } } - #[task(resources = [consumer, i2s, signal_buf, mute_buf, led, speed], schedule = [tick])] + #[task(resources = [consumer, transfer, signal_buf, mute_buf, led, speed], schedule = [tick])] fn tick(ctx: tick::Context) { - let i2s = ctx.resources.i2s; + let (_buf, i2s) = ctx.resources.transfer.take().unwrap().wait(); match ctx.resources.consumer.dequeue() { Some(State::On) => { // Move TX pointer to signal buffer (sound ON) - i2s.tx_buffer(&ctx.resources.signal_buf[..]).ok(); + *ctx.resources.transfer = i2s.tx(*ctx.resources.signal_buf).ok(); ctx.resources.led.set_low().ok(); } _ => { // Move TX pointer to silent buffer (sound OFF) - i2s.tx_buffer(&ctx.resources.mute_buf[..]).ok(); + *ctx.resources.transfer = i2s.tx(*ctx.resources.mute_buf).ok(); ctx.resources.led.set_high().ok(); } } @@ -190,7 +194,7 @@ const APP: () = { ctx.schedule.debounce(ctx.start + 3_000_000.cycles()).ok(); } - #[task(resources = [btn1, btn2, i2s, speed])] + #[task(resources = [btn1, btn2, speed])] fn debounce(ctx: debounce::Context) { if ctx.resources.btn1.is_low().unwrap() { rprintln!("Go slower"); diff --git a/examples/i2s-peripheral-demo/Cargo.toml b/examples/i2s-peripheral-demo/Cargo.toml index dd01b2c8..f6a872b4 100644 --- a/examples/i2s-peripheral-demo/Cargo.toml +++ b/examples/i2s-peripheral-demo/Cargo.toml @@ -12,8 +12,6 @@ cortex-m = "0.6.2" cortex-m-rtic = "0.5.3" rtt-target = {version = "0.2.0", features = ["cortex-m"] } nrf52840-hal = { features = ["rt"], path = "../../nrf52840-hal" } -small_morse = "0.1.0" -m = "0.1.1" [dependencies.embedded-hal] version = "0.2.3" diff --git a/examples/i2s-peripheral-demo/src/main.rs b/examples/i2s-peripheral-demo/src/main.rs index cb50753c..32a7176b 100644 --- a/examples/i2s-peripheral-demo/src/main.rs +++ b/examples/i2s-peripheral-demo/src/main.rs @@ -2,13 +2,13 @@ #![no_main] // I2S `peripheral mode` demo -// RMS level indicator using an RGB LED (APA102 on ItsyBitsy nRF52840) +// Signal average level indicator using an RGB LED (APA102 on ItsyBitsy nRF52840) use embedded_hal::blocking::spi::Write; -use m::Float; use { core::{ panic::PanicInfo, + pin, sync::atomic::{compiler_fence, Ordering}, }, hal::{ @@ -29,14 +29,14 @@ const RED: [u8; 9] = [0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x10, 0xFF]; #[rtic::app(device = crate::hal::pac, peripherals = true)] const APP: () = { struct Resources { - i2s: I2S, - #[init([0; 128])] - rx_buf: [i16; 128], rgb: Spim, + transfer: Option>, } - #[init(resources = [rx_buf])] + #[init] fn init(ctx: init::Context) -> init::LateResources { + static mut RX_BUF: [i16; 128] = [0i16; 128]; + let _clocks = hal::clocks::Clocks::new(ctx.device.CLOCK).enable_ext_hfosc(); rtt_init_print!(); rprintln!("Play me some audio..."); @@ -56,10 +56,9 @@ const APP: () = { Some(&sdin_pin), None, ); - i2s.enable_interrupt(I2SEvent::RxPtrUpdated) - .rx_buffer(&mut ctx.resources.rx_buf[..]) - .ok(); - i2s.enable().start(); + i2s.enable_interrupt(I2SEvent::RxPtrUpdated).start(); + let rx_buf = pin::Pin::new(&mut RX_BUF[..]); + let transfer = i2s.rx(rx_buf).ok(); // Configure APA102 RGB LED control let p1 = hal::gpio::p1::Parts::new(ctx.device.P1); @@ -80,28 +79,26 @@ const APP: () = { }, 0, ); - - init::LateResources { i2s, rgb } + init::LateResources { rgb, transfer } } - #[task(binds = I2S, resources = [i2s, rx_buf, rgb])] + #[task(binds = I2S, resources = [rgb, transfer])] fn on_i2s(ctx: on_i2s::Context) { - let on_i2s::Resources { i2s, rx_buf, rgb } = ctx.resources; + let (rx_buf, i2s) = ctx.resources.transfer.take().unwrap().wait(); if i2s.is_event_triggered(I2SEvent::RxPtrUpdated) { i2s.reset_event(I2SEvent::RxPtrUpdated); - // Calculate mono summed RMS of received buffer - let rms = Float::sqrt( - (rx_buf.iter().map(|x| *x as i32).map(|x| x * x).sum::() / rx_buf.len() as i32) - as f32, - ) as u16; - let color = match rms { + // Calculate mono summed average of received buffer + let avg = (rx_buf.iter().map(|x| (*x).abs() as u32).sum::() / rx_buf.len() as u32) + as u16; + let color = match avg { 0..=4 => &OFF, 5..=10_337 => &GREEN, 10_338..=16_383 => &ORANGE, _ => &RED, }; - as Write>::write(rgb, color).ok(); + as Write>::write(ctx.resources.rgb, color).ok(); } + *ctx.resources.transfer = i2s.rx(rx_buf).ok(); } }; diff --git a/nrf-hal-common/src/i2s.rs b/nrf-hal-common/src/i2s.rs index 0915abe1..28e86ed8 100644 --- a/nrf-hal-common/src/i2s.rs +++ b/nrf-hal-common/src/i2s.rs @@ -10,7 +10,11 @@ use crate::{ pac::generic::Reg, target_constants::{SRAM_LOWER, SRAM_UPPER}, }; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::{ + ops::{Deref, DerefMut}, + sync::atomic::{compiler_fence, Ordering}, +}; + use i2s::{_EVENTS_RXPTRUPD, _EVENTS_STOPPED, _EVENTS_TXPTRUPD, _TASKS_START, _TASKS_STOP}; pub struct I2S { @@ -80,10 +84,11 @@ impl I2S { }); } + i2s.enable.write(|w| w.enable().enabled()); Self { i2s } } - /// Takes ownership of the raw I2S peripheral, returning a safe wrapper i peripheral mode. + /// Takes ownership of the raw I2S peripheral, returning a safe wrapper in peripheral mode. pub fn new_peripheral( i2s: I2S_PAC, mck_pin: Option<&Pin>>, @@ -161,16 +166,19 @@ impl I2S { /// Starts I2S transfer. #[inline(always)] - pub fn start(&self) { + pub fn start(&self) -> &Self { + self.enable(); self.i2s.tasks_start.write(|w| unsafe { w.bits(1) }); + self } /// Stops the I2S transfer and waits until it has stopped. #[inline(always)] - pub fn stop(&self) { + pub fn stop(&self) -> &Self { compiler_fence(Ordering::SeqCst); self.i2s.tasks_stop.write(|w| unsafe { w.bits(1) }); while self.i2s.events_stopped.read().bits() == 0 {} + self } /// Enables/disables I2S transmission (TX). @@ -244,51 +252,125 @@ impl I2S { self } - /// Sets the transmit data buffer (TX). - /// NOTE: The TX buffer must live until the transfer is done, or corrupted data will be transmitted. + /// Returns the I2S channel configuation. #[inline(always)] - pub fn tx_buffer(&self, buf: &B) -> Result<(), Error> { - if (buf.ptr() as usize) < SRAM_LOWER || (buf.ptr() as usize) > SRAM_UPPER { - return Err(Error::DMABufferNotInDataMemory); + pub fn channels(&self) -> Channels { + match self.i2s.config.channels.read().bits() { + 0 => Channels::Stereo, + 1 => Channels::Left, + _ => Channels::Right, } + } - if buf.maxcnt() > MAX_DMA_MAXCNT { + /// Receives data into the given `buffer` until it's filled. + /// Returns a value that represents the in-progress DMA transfer. + #[allow(unused_mut)] + pub fn rx(mut self, mut buffer: core::pin::Pin) -> Result, Error> + where + Word: SupportedWordSize, + B: DerefMut + 'static, + B::Target: AsMut<[Word]> + Unpin + I2SBuffer, + { + if buffer.as_mut().maxcnt() > MAX_DMA_MAXCNT { + return Err(Error::BufferTooLong); + } + self.i2s + .rxd + .ptr + .write(|w| unsafe { w.ptr().bits(buffer.as_mut().ptr()) }); + self.i2s + .rxtxd + .maxcnt + .write(|w| unsafe { w.bits(buffer.as_mut().maxcnt()) }); + Ok(Transfer { + inner: Some(Inner { buffer, i2s: self }), + }) + } + + /// Full duplex DMA transfer. + /// Transmits the given `tx_buffer` while simultaneously receiving data + /// into the given `rx_buffer` until it is filled. The buffers must be of equal size. + /// Returns a value that represents the in-progress DMA transfer. + #[allow(unused_mut)] + pub fn transfer( + mut self, + tx_buffer: core::pin::Pin, + mut rx_buffer: core::pin::Pin, + ) -> Result, Error> + where + Word: SupportedWordSize, + TxB: Deref + 'static, + TxB::Target: AsRef<[Word]> + I2SBuffer, + RxB: DerefMut + 'static, + RxB::Target: AsMut<[Word]> + Unpin + I2SBuffer, + { + if (tx_buffer.as_ref().ptr() as usize) < SRAM_LOWER + || (tx_buffer.as_ref().ptr() as usize) > SRAM_UPPER + { + return Err(Error::DMABufferNotInDataMemory); + } + if tx_buffer.as_ref().maxcnt() != rx_buffer.as_mut().maxcnt() { + return Err(Error::BuffersDontMatch); + } + if tx_buffer.as_ref().maxcnt() > MAX_DMA_MAXCNT { return Err(Error::BufferTooLong); } self.i2s .txd .ptr - .write(|w| unsafe { w.ptr().bits(buf.ptr()) }); + .write(|w| unsafe { w.ptr().bits(tx_buffer.as_ref().ptr()) }); + self.i2s + .rxd + .ptr + .write(|w| unsafe { w.ptr().bits(rx_buffer.as_mut().ptr()) }); self.i2s .rxtxd .maxcnt - .write(|w| unsafe { w.bits(buf.maxcnt()) }); - - Ok(()) - } - - /// Sets the receive data buffer (RX). - #[inline(always)] - pub fn rx_buffer(&self, buf: &'static mut B) -> Result<(), Error> { - if (buf.ptr() as usize) < SRAM_LOWER || (buf.ptr() as usize) > SRAM_UPPER { + .write(|w| unsafe { w.bits(rx_buffer.as_mut().maxcnt()) }); + + self.start(); + + Ok(TransferFullDuplex { + inner: Some(InnerFullDuplex { + tx_buffer, + rx_buffer, + i2s: self, + }), + }) + } + + /// Transmits the given `tx_buffer`. + /// Returns a value that represents the in-progress DMA transfer. + #[allow(unused_mut)] + pub fn tx(mut self, buffer: core::pin::Pin) -> Result, Error> + where + Word: SupportedWordSize, + B: Deref + 'static, + B::Target: AsRef<[Word]> + I2SBuffer, + { + if (buffer.as_ref().ptr() as usize) < SRAM_LOWER + || (buffer.as_ref().ptr() as usize) > SRAM_UPPER + { return Err(Error::DMABufferNotInDataMemory); } - if buf.maxcnt() > MAX_DMA_MAXCNT { + if buffer.as_ref().maxcnt() > MAX_DMA_MAXCNT { return Err(Error::BufferTooLong); } self.i2s - .rxd + .txd .ptr - .write(|w| unsafe { w.ptr().bits(buf.ptr()) }); + .write(|w| unsafe { w.ptr().bits(buffer.as_ref().ptr()) }); self.i2s .rxtxd .maxcnt - .write(|w| unsafe { w.bits(buf.maxcnt()) }); + .write(|w| unsafe { w.bits(buffer.as_ref().maxcnt()) }); - Ok(()) + Ok(Transfer { + inner: Some(Inner { buffer, i2s: self }), + }) } /// Sets the transmit buffer RAM start address. @@ -404,6 +486,7 @@ impl I2S { pub enum Error { DMABufferNotInDataMemory, BufferTooLong, + BuffersDontMatch, } /// I2S Mode @@ -501,9 +584,9 @@ impl From for bool { /// Enable channels. #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum Channels { + Stereo, Left, Right, - Stereo, } impl From for u8 { fn from(variant: Channels) -> Self { @@ -520,11 +603,12 @@ pub enum I2SEvent { } /// Trait to represent valid sample buffers. -pub trait I2SBuffer { +pub trait I2SBuffer: private::Sealed { fn ptr(&self) -> u32; fn maxcnt(&self) -> u32; } +impl private::Sealed for [i8] {} impl I2SBuffer for [i8] { fn ptr(&self) -> u32 { self.as_ptr() as u32 @@ -534,6 +618,7 @@ impl I2SBuffer for [i8] { } } +impl private::Sealed for [i16] {} impl I2SBuffer for [i16] { fn ptr(&self) -> u32 { self.as_ptr() as u32 @@ -543,6 +628,7 @@ impl I2SBuffer for [i16] { } } +impl private::Sealed for [i32] {} impl I2SBuffer for [i32] { fn ptr(&self) -> u32 { self.as_ptr() as u32 @@ -552,29 +638,119 @@ impl I2SBuffer for [i32] { } } +impl private::Sealed for [u8] {} impl I2SBuffer for [u8] { fn ptr(&self) -> u32 { self.as_ptr() as u32 } fn maxcnt(&self) -> u32 { - self.len() as u32 / 4 + self.len() as u32 / 8 } } +impl private::Sealed for [u16] {} impl I2SBuffer for [u16] { fn ptr(&self) -> u32 { self.as_ptr() as u32 } fn maxcnt(&self) -> u32 { - self.len() as u32 / 2 + self.len() as u32 / 4 } } +impl private::Sealed for [u32] {} impl I2SBuffer for [u32] { fn ptr(&self) -> u32 { self.as_ptr() as u32 } fn maxcnt(&self) -> u32 { - self.len() as u32 + self.len() as u32 / 2 } } + +/// A DMA transfer +pub struct Transfer { + inner: Option>, +} + +struct Inner { + buffer: core::pin::Pin, + i2s: I2S, +} + +impl Transfer { + /// Blocks until the transfer is done and returns the buffer. + pub fn wait(mut self) -> (core::pin::Pin, I2S) { + let inner = self + .inner + .take() + .unwrap_or_else(|| unsafe { core::hint::unreachable_unchecked() }); + while !(inner.i2s.is_event_triggered(I2SEvent::RxPtrUpdated) + || inner.i2s.is_event_triggered(I2SEvent::TxPtrUpdated)) + {} + compiler_fence(Ordering::Acquire); + (inner.buffer, inner.i2s) + } +} + +impl Drop for Transfer { + fn drop(&mut self) { + if let Some(inner) = self.inner.as_mut() { + inner.i2s.stop(); + compiler_fence(Ordering::Acquire); + } + } +} +/// A full duplex DMA transfer +pub struct TransferFullDuplex { + inner: Option>, +} + +struct InnerFullDuplex { + tx_buffer: core::pin::Pin, + rx_buffer: core::pin::Pin, + i2s: I2S, +} + +impl TransferFullDuplex { + /// Blocks until the transfer is done and returns the buffer. + pub fn wait(mut self) -> (core::pin::Pin, core::pin::Pin, I2S) { + let inner = self + .inner + .take() + .unwrap_or_else(|| unsafe { core::hint::unreachable_unchecked() }); + while !(inner.i2s.is_event_triggered(I2SEvent::RxPtrUpdated) + || inner.i2s.is_event_triggered(I2SEvent::TxPtrUpdated)) + {} + compiler_fence(Ordering::Acquire); + (inner.tx_buffer, inner.rx_buffer, inner.i2s) + } +} + +impl Drop for TransferFullDuplex { + fn drop(&mut self) { + if let Some(inner) = self.inner.as_mut() { + inner.i2s.stop(); + compiler_fence(Ordering::Acquire); + } + } +} + +pub trait SupportedWordSize: private::Sealed {} +impl private::Sealed for i8 {} +impl SupportedWordSize for i8 {} +impl private::Sealed for i16 {} +impl SupportedWordSize for i16 {} +impl private::Sealed for i32 {} +impl SupportedWordSize for i32 {} +impl private::Sealed for u8 {} +impl SupportedWordSize for u8 {} +impl private::Sealed for u16 {} +impl SupportedWordSize for u16 {} +impl private::Sealed for u32 {} +impl SupportedWordSize for u32 {} + +mod private { + /// Prevents code outside of the parent module from implementing traits. + pub trait Sealed {} +} From 069fee09721f63d461096bf91c05cbde1ff86021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Alse=CC=81r?= Date: Wed, 2 Sep 2020 23:56:31 +0200 Subject: [PATCH 2/4] Cleanup controller demo --- examples/i2s-controller-demo/src/main.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/i2s-controller-demo/src/main.rs b/examples/i2s-controller-demo/src/main.rs index f69604a0..13dcb88b 100644 --- a/examples/i2s-controller-demo/src/main.rs +++ b/examples/i2s-controller-demo/src/main.rs @@ -33,10 +33,7 @@ use { #[rtic::app(device = crate::hal::pac, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)] const APP: () = { struct Resources { - // i2s: hal::i2s::I2S, - // #[init([0; 32])] signal_buf: pin::Pin<&'static [i16]>, - // #[init([0; 32])] mute_buf: pin::Pin<&'static [i16]>, #[init(None)] queue: Option>, @@ -57,6 +54,7 @@ const APP: () = { fn init(mut ctx: init::Context) -> init::LateResources { static mut MUTE_BUF: [i16; 32] = [0i16; 32]; static mut SIGNAL_BUF: [i16; 32] = [0i16; 32]; + // Fill signal buffer with triangle waveform, 2 channels interleaved let len = SIGNAL_BUF.len() / 2; for x in 0..len { From e020ccc8a8828681ad236c4d96d1030e2e28c264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Alse=CC=81r?= Date: Fri, 4 Sep 2020 00:46:53 +0200 Subject: [PATCH 3/4] Replace Pin with StableDeref bounds for DMA buffers --- examples/i2s-controller-demo/src/main.rs | 13 +- examples/i2s-peripheral-demo/src/main.rs | 10 +- nrf-hal-common/Cargo.toml | 4 + nrf-hal-common/src/i2s.rs | 150 ++++++++++++++++------- 4 files changed, 118 insertions(+), 59 deletions(-) diff --git a/examples/i2s-controller-demo/src/main.rs b/examples/i2s-controller-demo/src/main.rs index 13dcb88b..4e223c39 100644 --- a/examples/i2s-controller-demo/src/main.rs +++ b/examples/i2s-controller-demo/src/main.rs @@ -14,7 +14,6 @@ use small_morse::{encode, State}; use { core::{ panic::PanicInfo, - pin, sync::atomic::{compiler_fence, Ordering}, }, hal::{ @@ -33,8 +32,8 @@ use { #[rtic::app(device = crate::hal::pac, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)] const APP: () = { struct Resources { - signal_buf: pin::Pin<&'static [i16]>, - mute_buf: pin::Pin<&'static [i16]>, + signal_buf: &'static [i16], + mute_buf: &'static [i16], #[init(None)] queue: Option>, producer: Producer<'static, State, U256>, @@ -47,7 +46,7 @@ const APP: () = { btn1: Pin>, btn2: Pin>, led: Pin>, - transfer: Option>, + transfer: Option>, } #[init(resources = [queue], spawn = [tick])] @@ -125,9 +124,9 @@ const APP: () = { led: p0.p0_13.into_push_pull_output(Level::High).degrade(), uarte, uarte_timer: Timer::new(ctx.device.TIMER0), - transfer: i2s.tx(pin::Pin::new(&MUTE_BUF[..])).ok(), - signal_buf: pin::Pin::new(&SIGNAL_BUF[..]), - mute_buf: pin::Pin::new(&MUTE_BUF[..]), + transfer: i2s.tx(&MUTE_BUF[..]).ok(), + signal_buf: &SIGNAL_BUF[..], + mute_buf: &MUTE_BUF[..], } } diff --git a/examples/i2s-peripheral-demo/src/main.rs b/examples/i2s-peripheral-demo/src/main.rs index 32a7176b..6a1e93fc 100644 --- a/examples/i2s-peripheral-demo/src/main.rs +++ b/examples/i2s-peripheral-demo/src/main.rs @@ -8,7 +8,6 @@ use embedded_hal::blocking::spi::Write; use { core::{ panic::PanicInfo, - pin, sync::atomic::{compiler_fence, Ordering}, }, hal::{ @@ -30,7 +29,7 @@ const RED: [u8; 9] = [0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x10, 0xFF]; const APP: () = { struct Resources { rgb: Spim, - transfer: Option>, + transfer: Option>, } #[init] @@ -57,8 +56,6 @@ const APP: () = { None, ); i2s.enable_interrupt(I2SEvent::RxPtrUpdated).start(); - let rx_buf = pin::Pin::new(&mut RX_BUF[..]); - let transfer = i2s.rx(rx_buf).ok(); // Configure APA102 RGB LED control let p1 = hal::gpio::p1::Parts::new(ctx.device.P1); @@ -79,7 +76,10 @@ const APP: () = { }, 0, ); - init::LateResources { rgb, transfer } + init::LateResources { + rgb, + transfer: i2s.rx(&mut RX_BUF[..]).ok(), + } } #[task(binds = I2S, resources = [rgb, transfer])] diff --git a/nrf-hal-common/Cargo.toml b/nrf-hal-common/Cargo.toml index 083b4b3b..f8f16702 100644 --- a/nrf-hal-common/Cargo.toml +++ b/nrf-hal-common/Cargo.toml @@ -25,6 +25,10 @@ fixed = "1.0.0" rand_core = "0.5.1" cfg-if = "0.1.10" +[dependencies.stable_deref_trait] +version = "1.2.0" +default-features = false + [dependencies.void] default-features = false version = "1.0.2" diff --git a/nrf-hal-common/src/i2s.rs b/nrf-hal-common/src/i2s.rs index 28e86ed8..328f73e4 100644 --- a/nrf-hal-common/src/i2s.rs +++ b/nrf-hal-common/src/i2s.rs @@ -14,6 +14,7 @@ use core::{ ops::{Deref, DerefMut}, sync::atomic::{compiler_fence, Ordering}, }; +pub use stable_deref_trait::StableDeref; use i2s::{_EVENTS_RXPTRUPD, _EVENTS_STOPPED, _EVENTS_TXPTRUPD, _TASKS_START, _TASKS_STOP}; @@ -261,27 +262,26 @@ impl I2S { _ => Channels::Right, } } - /// Receives data into the given `buffer` until it's filled. /// Returns a value that represents the in-progress DMA transfer. #[allow(unused_mut)] - pub fn rx(mut self, mut buffer: core::pin::Pin) -> Result, Error> + pub fn rx(mut self, mut buffer: B) -> Result, Error> where Word: SupportedWordSize, - B: DerefMut + 'static, - B::Target: AsMut<[Word]> + Unpin + I2SBuffer, + B: DerefMut + StableDeref + 'static + I2SBuffer, + B::Target: AsMut<[Word]>, { - if buffer.as_mut().maxcnt() > MAX_DMA_MAXCNT { + if buffer.maxcnt() > MAX_DMA_MAXCNT { return Err(Error::BufferTooLong); } self.i2s .rxd .ptr - .write(|w| unsafe { w.ptr().bits(buffer.as_mut().ptr()) }); + .write(|w| unsafe { w.ptr().bits(buffer.ptr()) }); self.i2s .rxtxd .maxcnt - .write(|w| unsafe { w.bits(buffer.as_mut().maxcnt()) }); + .write(|w| unsafe { w.bits(buffer.maxcnt()) }); Ok(Transfer { inner: Some(Inner { buffer, i2s: self }), }) @@ -294,40 +294,38 @@ impl I2S { #[allow(unused_mut)] pub fn transfer( mut self, - tx_buffer: core::pin::Pin, - mut rx_buffer: core::pin::Pin, + tx_buffer: TxB, + mut rx_buffer: RxB, ) -> Result, Error> where Word: SupportedWordSize, - TxB: Deref + 'static, - TxB::Target: AsRef<[Word]> + I2SBuffer, - RxB: DerefMut + 'static, - RxB::Target: AsMut<[Word]> + Unpin + I2SBuffer, + TxB: Deref + StableDeref + 'static + I2SBuffer, + TxB::Target: AsRef<[Word]>, + RxB: DerefMut + StableDeref + 'static + I2SBuffer, + RxB::Target: AsMut<[Word]>, { - if (tx_buffer.as_ref().ptr() as usize) < SRAM_LOWER - || (tx_buffer.as_ref().ptr() as usize) > SRAM_UPPER - { + if (tx_buffer.ptr() as usize) < SRAM_LOWER || (tx_buffer.ptr() as usize) > SRAM_UPPER { return Err(Error::DMABufferNotInDataMemory); } - if tx_buffer.as_ref().maxcnt() != rx_buffer.as_mut().maxcnt() { + if tx_buffer.maxcnt() != rx_buffer.maxcnt() { return Err(Error::BuffersDontMatch); } - if tx_buffer.as_ref().maxcnt() > MAX_DMA_MAXCNT { + if tx_buffer.maxcnt() > MAX_DMA_MAXCNT { return Err(Error::BufferTooLong); } self.i2s .txd .ptr - .write(|w| unsafe { w.ptr().bits(tx_buffer.as_ref().ptr()) }); + .write(|w| unsafe { w.ptr().bits(tx_buffer.ptr()) }); self.i2s .rxd .ptr - .write(|w| unsafe { w.ptr().bits(rx_buffer.as_mut().ptr()) }); + .write(|w| unsafe { w.ptr().bits(rx_buffer.ptr()) }); self.i2s .rxtxd .maxcnt - .write(|w| unsafe { w.bits(rx_buffer.as_mut().maxcnt()) }); + .write(|w| unsafe { w.bits(rx_buffer.maxcnt()) }); self.start(); @@ -343,30 +341,28 @@ impl I2S { /// Transmits the given `tx_buffer`. /// Returns a value that represents the in-progress DMA transfer. #[allow(unused_mut)] - pub fn tx(mut self, buffer: core::pin::Pin) -> Result, Error> + pub fn tx(mut self, buffer: B) -> Result, Error> where Word: SupportedWordSize, - B: Deref + 'static, - B::Target: AsRef<[Word]> + I2SBuffer, + B: Deref + StableDeref + 'static + I2SBuffer, + B::Target: AsRef<[Word]>, { - if (buffer.as_ref().ptr() as usize) < SRAM_LOWER - || (buffer.as_ref().ptr() as usize) > SRAM_UPPER - { + if (buffer.ptr() as usize) < SRAM_LOWER || (buffer.ptr() as usize) > SRAM_UPPER { return Err(Error::DMABufferNotInDataMemory); } - if buffer.as_ref().maxcnt() > MAX_DMA_MAXCNT { + if buffer.maxcnt() > MAX_DMA_MAXCNT { return Err(Error::BufferTooLong); } self.i2s .txd .ptr - .write(|w| unsafe { w.ptr().bits(buffer.as_ref().ptr()) }); + .write(|w| unsafe { w.ptr().bits(buffer.ptr()) }); self.i2s .rxtxd .maxcnt - .write(|w| unsafe { w.bits(buffer.as_ref().maxcnt()) }); + .write(|w| unsafe { w.bits(buffer.maxcnt()) }); Ok(Transfer { inner: Some(Inner { buffer, i2s: self }), @@ -608,8 +604,68 @@ pub trait I2SBuffer: private::Sealed { fn maxcnt(&self) -> u32; } -impl private::Sealed for [i8] {} -impl I2SBuffer for [i8] { +impl private::Sealed for &[i8] {} +impl I2SBuffer for &[i8] { + fn ptr(&self) -> u32 { + self.as_ptr() as u32 + } + fn maxcnt(&self) -> u32 { + self.len() as u32 / 4 + } +} + +impl private::Sealed for &[i16] {} +impl I2SBuffer for &[i16] { + fn ptr(&self) -> u32 { + self.as_ptr() as u32 + } + fn maxcnt(&self) -> u32 { + self.len() as u32 / 2 + } +} + +impl private::Sealed for &[i32] {} +impl I2SBuffer for &[i32] { + fn ptr(&self) -> u32 { + self.as_ptr() as u32 + } + fn maxcnt(&self) -> u32 { + self.len() as u32 + } +} + +impl private::Sealed for &[u8] {} +impl I2SBuffer for &[u8] { + fn ptr(&self) -> u32 { + self.as_ptr() as u32 + } + fn maxcnt(&self) -> u32 { + self.len() as u32 / 8 + } +} + +impl private::Sealed for &[u16] {} +impl I2SBuffer for &[u16] { + fn ptr(&self) -> u32 { + self.as_ptr() as u32 + } + fn maxcnt(&self) -> u32 { + self.len() as u32 / 4 + } +} + +impl private::Sealed for &[u32] {} +impl I2SBuffer for &[u32] { + fn ptr(&self) -> u32 { + self.as_ptr() as u32 + } + fn maxcnt(&self) -> u32 { + self.len() as u32 / 2 + } +} + +impl private::Sealed for &mut [i8] {} +impl I2SBuffer for &mut [i8] { fn ptr(&self) -> u32 { self.as_ptr() as u32 } @@ -618,8 +674,8 @@ impl I2SBuffer for [i8] { } } -impl private::Sealed for [i16] {} -impl I2SBuffer for [i16] { +impl private::Sealed for &mut [i16] {} +impl I2SBuffer for &mut [i16] { fn ptr(&self) -> u32 { self.as_ptr() as u32 } @@ -628,8 +684,8 @@ impl I2SBuffer for [i16] { } } -impl private::Sealed for [i32] {} -impl I2SBuffer for [i32] { +impl private::Sealed for &mut [i32] {} +impl I2SBuffer for &mut [i32] { fn ptr(&self) -> u32 { self.as_ptr() as u32 } @@ -638,8 +694,8 @@ impl I2SBuffer for [i32] { } } -impl private::Sealed for [u8] {} -impl I2SBuffer for [u8] { +impl private::Sealed for &mut [u8] {} +impl I2SBuffer for &mut [u8] { fn ptr(&self) -> u32 { self.as_ptr() as u32 } @@ -648,8 +704,8 @@ impl I2SBuffer for [u8] { } } -impl private::Sealed for [u16] {} -impl I2SBuffer for [u16] { +impl private::Sealed for &mut [u16] {} +impl I2SBuffer for &mut [u16] { fn ptr(&self) -> u32 { self.as_ptr() as u32 } @@ -658,8 +714,8 @@ impl I2SBuffer for [u16] { } } -impl private::Sealed for [u32] {} -impl I2SBuffer for [u32] { +impl private::Sealed for &mut [u32] {} +impl I2SBuffer for &mut [u32] { fn ptr(&self) -> u32 { self.as_ptr() as u32 } @@ -674,13 +730,13 @@ pub struct Transfer { } struct Inner { - buffer: core::pin::Pin, + buffer: B, i2s: I2S, } impl Transfer { /// Blocks until the transfer is done and returns the buffer. - pub fn wait(mut self) -> (core::pin::Pin, I2S) { + pub fn wait(mut self) -> (B, I2S) { let inner = self .inner .take() @@ -707,14 +763,14 @@ pub struct TransferFullDuplex { } struct InnerFullDuplex { - tx_buffer: core::pin::Pin, - rx_buffer: core::pin::Pin, + tx_buffer: TxB, + rx_buffer: RxB, i2s: I2S, } impl TransferFullDuplex { /// Blocks until the transfer is done and returns the buffer. - pub fn wait(mut self) -> (core::pin::Pin, core::pin::Pin, I2S) { + pub fn wait(mut self) -> (TxB, RxB, I2S) { let inner = self .inner .take() From 3b4cc4bc8f4d50cea451c79a2d75e9965516cb00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Alse=CC=81r?= Date: Fri, 4 Sep 2020 13:01:27 +0200 Subject: [PATCH 4/4] Use embedded-dma traits for DMA buffers --- examples/i2s-peripheral-demo/src/main.rs | 8 +- nrf-hal-common/Cargo.toml | 5 +- nrf-hal-common/src/i2s.rs | 228 ++++------------------- 3 files changed, 39 insertions(+), 202 deletions(-) diff --git a/examples/i2s-peripheral-demo/src/main.rs b/examples/i2s-peripheral-demo/src/main.rs index 6a1e93fc..f4205df7 100644 --- a/examples/i2s-peripheral-demo/src/main.rs +++ b/examples/i2s-peripheral-demo/src/main.rs @@ -29,12 +29,12 @@ const RED: [u8; 9] = [0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x10, 0xFF]; const APP: () = { struct Resources { rgb: Spim, - transfer: Option>, + transfer: Option>, } #[init] fn init(ctx: init::Context) -> init::LateResources { - static mut RX_BUF: [i16; 128] = [0i16; 128]; + static mut RX_BUF: [i16; 128] = [0; 128]; let _clocks = hal::clocks::Clocks::new(ctx.device.CLOCK).enable_ext_hfosc(); rtt_init_print!(); @@ -78,7 +78,7 @@ const APP: () = { ); init::LateResources { rgb, - transfer: i2s.rx(&mut RX_BUF[..]).ok(), + transfer: i2s.rx(RX_BUF).ok(), } } @@ -87,7 +87,7 @@ const APP: () = { let (rx_buf, i2s) = ctx.resources.transfer.take().unwrap().wait(); if i2s.is_event_triggered(I2SEvent::RxPtrUpdated) { i2s.reset_event(I2SEvent::RxPtrUpdated); - // Calculate mono summed average of received buffer + //Calculate mono summed average of received buffer let avg = (rx_buf.iter().map(|x| (*x).abs() as u32).sum::() / rx_buf.len() as u32) as u16; let color = match avg { diff --git a/nrf-hal-common/Cargo.toml b/nrf-hal-common/Cargo.toml index f8f16702..f6fbc950 100644 --- a/nrf-hal-common/Cargo.toml +++ b/nrf-hal-common/Cargo.toml @@ -24,10 +24,7 @@ nb = "1.0.0" fixed = "1.0.0" rand_core = "0.5.1" cfg-if = "0.1.10" - -[dependencies.stable_deref_trait] -version = "1.2.0" -default-features = false +embedded-dma = "0.1.1" [dependencies.void] default-features = false diff --git a/nrf-hal-common/src/i2s.rs b/nrf-hal-common/src/i2s.rs index 328f73e4..199d0af7 100644 --- a/nrf-hal-common/src/i2s.rs +++ b/nrf-hal-common/src/i2s.rs @@ -10,11 +10,8 @@ use crate::{ pac::generic::Reg, target_constants::{SRAM_LOWER, SRAM_UPPER}, }; -use core::{ - ops::{Deref, DerefMut}, - sync::atomic::{compiler_fence, Ordering}, -}; -pub use stable_deref_trait::StableDeref; +use core::sync::atomic::{compiler_fence, Ordering}; +use embedded_dma::*; use i2s::{_EVENTS_RXPTRUPD, _EVENTS_STOPPED, _EVENTS_TXPTRUPD, _TASKS_START, _TASKS_STOP}; @@ -23,7 +20,7 @@ pub struct I2S { } // I2S EasyDMA MAXCNT bit length = 14 -const MAX_DMA_MAXCNT: u32 = 16_384; +const MAX_DMA_MAXCNT: u32 = 1 << 14; impl I2S { /// Takes ownership of the raw I2S peripheral, returning a safe wrapper in controller mode. @@ -265,23 +262,20 @@ impl I2S { /// Receives data into the given `buffer` until it's filled. /// Returns a value that represents the in-progress DMA transfer. #[allow(unused_mut)] - pub fn rx(mut self, mut buffer: B) -> Result, Error> + pub fn rx(mut self, mut buffer: B) -> Result, Error> where - Word: SupportedWordSize, - B: DerefMut + StableDeref + 'static + I2SBuffer, - B::Target: AsMut<[Word]>, + B: WriteBuffer, { - if buffer.maxcnt() > MAX_DMA_MAXCNT { + let (ptr, len) = unsafe { buffer.write_buffer() }; + let maxcnt = (len / (core::mem::size_of::() / core::mem::size_of::())) as u32; + if maxcnt > MAX_DMA_MAXCNT { return Err(Error::BufferTooLong); } self.i2s .rxd .ptr - .write(|w| unsafe { w.ptr().bits(buffer.ptr()) }); - self.i2s - .rxtxd - .maxcnt - .write(|w| unsafe { w.bits(buffer.maxcnt()) }); + .write(|w| unsafe { w.ptr().bits(ptr as u32) }); + self.i2s.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) }); Ok(Transfer { inner: Some(Inner { buffer, i2s: self }), }) @@ -292,42 +286,37 @@ impl I2S { /// into the given `rx_buffer` until it is filled. The buffers must be of equal size. /// Returns a value that represents the in-progress DMA transfer. #[allow(unused_mut)] - pub fn transfer( + pub fn transfer( mut self, tx_buffer: TxB, mut rx_buffer: RxB, ) -> Result, Error> where - Word: SupportedWordSize, - TxB: Deref + StableDeref + 'static + I2SBuffer, - TxB::Target: AsRef<[Word]>, - RxB: DerefMut + StableDeref + 'static + I2SBuffer, - RxB::Target: AsMut<[Word]>, + TxB: ReadBuffer, + RxB: WriteBuffer, { - if (tx_buffer.ptr() as usize) < SRAM_LOWER || (tx_buffer.ptr() as usize) > SRAM_UPPER { - return Err(Error::DMABufferNotInDataMemory); - } - if tx_buffer.maxcnt() != rx_buffer.maxcnt() { + let (rx_ptr, rx_len) = unsafe { rx_buffer.write_buffer() }; + let (tx_ptr, tx_len) = unsafe { tx_buffer.read_buffer() }; + let maxcnt = (tx_len / (core::mem::size_of::() / core::mem::size_of::())) as u32; + if tx_len != rx_len { return Err(Error::BuffersDontMatch); } - if tx_buffer.maxcnt() > MAX_DMA_MAXCNT { + if maxcnt > MAX_DMA_MAXCNT { return Err(Error::BufferTooLong); } + if (tx_ptr as usize) < SRAM_LOWER || (tx_ptr as usize) > SRAM_UPPER { + return Err(Error::DMABufferNotInDataMemory); + } self.i2s .txd .ptr - .write(|w| unsafe { w.ptr().bits(tx_buffer.ptr()) }); + .write(|w| unsafe { w.ptr().bits(tx_ptr as u32) }); self.i2s .rxd .ptr - .write(|w| unsafe { w.ptr().bits(rx_buffer.ptr()) }); - self.i2s - .rxtxd - .maxcnt - .write(|w| unsafe { w.bits(rx_buffer.maxcnt()) }); - - self.start(); + .write(|w| unsafe { w.ptr().bits(rx_ptr as u32) }); + self.i2s.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) }); Ok(TransferFullDuplex { inner: Some(InnerFullDuplex { @@ -341,28 +330,24 @@ impl I2S { /// Transmits the given `tx_buffer`. /// Returns a value that represents the in-progress DMA transfer. #[allow(unused_mut)] - pub fn tx(mut self, buffer: B) -> Result, Error> + pub fn tx(mut self, buffer: B) -> Result, Error> where - Word: SupportedWordSize, - B: Deref + StableDeref + 'static + I2SBuffer, - B::Target: AsRef<[Word]>, + B: ReadBuffer, { - if (buffer.ptr() as usize) < SRAM_LOWER || (buffer.ptr() as usize) > SRAM_UPPER { - return Err(Error::DMABufferNotInDataMemory); - } - - if buffer.maxcnt() > MAX_DMA_MAXCNT { + let (ptr, len) = unsafe { buffer.read_buffer() }; + 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); + } self.i2s .txd .ptr - .write(|w| unsafe { w.ptr().bits(buffer.ptr()) }); - self.i2s - .rxtxd - .maxcnt - .write(|w| unsafe { w.bits(buffer.maxcnt()) }); + .write(|w| unsafe { w.ptr().bits(ptr as u32) }); + self.i2s.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) }); Ok(Transfer { inner: Some(Inner { buffer, i2s: self }), @@ -598,132 +583,6 @@ pub enum I2SEvent { Stopped, } -/// Trait to represent valid sample buffers. -pub trait I2SBuffer: private::Sealed { - fn ptr(&self) -> u32; - fn maxcnt(&self) -> u32; -} - -impl private::Sealed for &[i8] {} -impl I2SBuffer for &[i8] { - fn ptr(&self) -> u32 { - self.as_ptr() as u32 - } - fn maxcnt(&self) -> u32 { - self.len() as u32 / 4 - } -} - -impl private::Sealed for &[i16] {} -impl I2SBuffer for &[i16] { - fn ptr(&self) -> u32 { - self.as_ptr() as u32 - } - fn maxcnt(&self) -> u32 { - self.len() as u32 / 2 - } -} - -impl private::Sealed for &[i32] {} -impl I2SBuffer for &[i32] { - fn ptr(&self) -> u32 { - self.as_ptr() as u32 - } - fn maxcnt(&self) -> u32 { - self.len() as u32 - } -} - -impl private::Sealed for &[u8] {} -impl I2SBuffer for &[u8] { - fn ptr(&self) -> u32 { - self.as_ptr() as u32 - } - fn maxcnt(&self) -> u32 { - self.len() as u32 / 8 - } -} - -impl private::Sealed for &[u16] {} -impl I2SBuffer for &[u16] { - fn ptr(&self) -> u32 { - self.as_ptr() as u32 - } - fn maxcnt(&self) -> u32 { - self.len() as u32 / 4 - } -} - -impl private::Sealed for &[u32] {} -impl I2SBuffer for &[u32] { - fn ptr(&self) -> u32 { - self.as_ptr() as u32 - } - fn maxcnt(&self) -> u32 { - self.len() as u32 / 2 - } -} - -impl private::Sealed for &mut [i8] {} -impl I2SBuffer for &mut [i8] { - fn ptr(&self) -> u32 { - self.as_ptr() as u32 - } - fn maxcnt(&self) -> u32 { - self.len() as u32 / 4 - } -} - -impl private::Sealed for &mut [i16] {} -impl I2SBuffer for &mut [i16] { - fn ptr(&self) -> u32 { - self.as_ptr() as u32 - } - fn maxcnt(&self) -> u32 { - self.len() as u32 / 2 - } -} - -impl private::Sealed for &mut [i32] {} -impl I2SBuffer for &mut [i32] { - fn ptr(&self) -> u32 { - self.as_ptr() as u32 - } - fn maxcnt(&self) -> u32 { - self.len() as u32 - } -} - -impl private::Sealed for &mut [u8] {} -impl I2SBuffer for &mut [u8] { - fn ptr(&self) -> u32 { - self.as_ptr() as u32 - } - fn maxcnt(&self) -> u32 { - self.len() as u32 / 8 - } -} - -impl private::Sealed for &mut [u16] {} -impl I2SBuffer for &mut [u16] { - fn ptr(&self) -> u32 { - self.as_ptr() as u32 - } - fn maxcnt(&self) -> u32 { - self.len() as u32 / 4 - } -} - -impl private::Sealed for &mut [u32] {} -impl I2SBuffer for &mut [u32] { - fn ptr(&self) -> u32 { - self.as_ptr() as u32 - } - fn maxcnt(&self) -> u32 { - self.len() as u32 / 2 - } -} - /// A DMA transfer pub struct Transfer { inner: Option>, @@ -791,22 +650,3 @@ impl Drop for TransferFullDuplex { } } } - -pub trait SupportedWordSize: private::Sealed {} -impl private::Sealed for i8 {} -impl SupportedWordSize for i8 {} -impl private::Sealed for i16 {} -impl SupportedWordSize for i16 {} -impl private::Sealed for i32 {} -impl SupportedWordSize for i32 {} -impl private::Sealed for u8 {} -impl SupportedWordSize for u8 {} -impl private::Sealed for u16 {} -impl SupportedWordSize for u16 {} -impl private::Sealed for u32 {} -impl SupportedWordSize for u32 {} - -mod private { - /// Prevents code outside of the parent module from implementing traits. - pub trait Sealed {} -}