From 6d9bf03a3becbb2ffd35a6f42a03da4e383dc46e Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 28 Sep 2025 22:11:27 +0200 Subject: nrf/i2s: erase instance generic --- embassy-nrf/src/i2s.rs | 176 +++++++++++++++++++++++++++---------------------- 1 file changed, 98 insertions(+), 78 deletions(-) (limited to 'embassy-nrf/src') diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs index 53de8deee..1bfa18491 100644 --- a/embassy-nrf/src/i2s.rs +++ b/embassy-nrf/src/i2s.rs @@ -381,7 +381,7 @@ pub struct InterruptHandler { impl interrupt::typelevel::Handler for InterruptHandler { unsafe fn on_interrupt() { - let device = Device::::new(); + let device = Device::new(T::regs()); let s = T::state(); if device.is_tx_ptr_updated() { @@ -405,8 +405,9 @@ impl interrupt::typelevel::Handler for InterruptHandl } /// I2S driver. -pub struct I2S<'d, T: Instance> { - i2s: Peri<'d, T>, +pub struct I2S<'d> { + r: pac::i2s::I2s, + state: &'static State, mck: Option>, sck: Peri<'d, AnyPin>, lrck: Peri<'d, AnyPin>, @@ -416,10 +417,10 @@ pub struct I2S<'d, T: Instance> { config: Config, } -impl<'d, T: Instance> I2S<'d, T> { +impl<'d> I2S<'d> { /// Create a new I2S in master mode - pub fn new_master( - i2s: Peri<'d, T>, + pub fn new_master( + _i2s: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, mck: Peri<'d, impl GpioPin>, sck: Peri<'d, impl GpioPin>, @@ -427,8 +428,12 @@ impl<'d, T: Instance> I2S<'d, T> { master_clock: MasterClock, config: Config, ) -> Self { + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + Self { - i2s, + r: T::regs(), + state: T::state(), mck: Some(mck.into()), sck: sck.into(), lrck: lrck.into(), @@ -440,15 +445,19 @@ impl<'d, T: Instance> I2S<'d, T> { } /// Create a new I2S in slave mode - pub fn new_slave( - i2s: Peri<'d, T>, + pub fn new_slave( + _i2s: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, sck: Peri<'d, impl GpioPin>, lrck: Peri<'d, impl GpioPin>, config: Config, ) -> Self { + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + Self { - i2s, + r: T::regs(), + state: T::state(), mck: None, sck: sck.into(), lrck: lrck.into(), @@ -464,10 +473,13 @@ impl<'d, T: Instance> I2S<'d, T> { mut self, sdout: Peri<'d, impl GpioPin>, buffers: MultiBuffering, - ) -> OutputStream<'d, T, S, NB, NS> { + ) -> OutputStream<'d, S, NB, NS> { self.sdout = Some(sdout.into()); + let p = self.build(); OutputStream { - _p: self.build(), + r: p.0, + state: p.1, + _phantom: PhantomData, buffers, } } @@ -477,11 +489,14 @@ impl<'d, T: Instance> I2S<'d, T> { mut self, sdin: Peri<'d, impl GpioPin>, buffers: MultiBuffering, - ) -> InputStream<'d, T, S, NB, NS> { + ) -> InputStream<'d, S, NB, NS> { self.sdin = Some(sdin.into()); + let p = self.build(); InputStream { - _p: self.build(), + r: p.0, + state: p.1, buffers, + _phantom: PhantomData, } } @@ -492,30 +507,33 @@ impl<'d, T: Instance> I2S<'d, T> { sdout: Peri<'d, impl GpioPin>, buffers_out: MultiBuffering, buffers_in: MultiBuffering, - ) -> FullDuplexStream<'d, T, S, NB, NS> { + ) -> FullDuplexStream<'d, S, NB, NS> { self.sdout = Some(sdout.into()); self.sdin = Some(sdin.into()); + let p = self.build(); FullDuplexStream { - _p: self.build(), + r: p.0, + state: p.1, + _phantom: PhantomData, buffers_out, buffers_in, } } - fn build(self) -> Peri<'d, T> { + fn build(self) -> (pac::i2s::I2s, &'static State) { self.apply_config(); self.select_pins(); self.setup_interrupt(); - let device = Device::::new(); + let device = Device::new(self.r); device.enable(); - self.i2s + (self.r, self.state) } fn apply_config(&self) { - let c = T::regs().config(); + let c = self.r.config(); match &self.master_clock { Some(MasterClock { freq, ratio }) => { c.mode().write(|w| w.set_mode(vals::Mode::MASTER)); @@ -535,7 +553,7 @@ impl<'d, T: Instance> I2S<'d, T> { } fn select_pins(&self) { - let psel = T::regs().psel(); + let psel = self.r.psel(); psel.mck().write_value(self.mck.psel_bits()); psel.sck().write_value(self.sck.psel_bits()); psel.lrck().write_value(self.lrck.psel_bits()); @@ -544,10 +562,9 @@ impl<'d, T: Instance> I2S<'d, T> { } fn setup_interrupt(&self) { - T::Interrupt::unpend(); - unsafe { T::Interrupt::enable() }; + // Interrupt is already set up in constructor - let device = Device::::new(); + let device = Device::new(self.r); device.disable_tx_ptr_interrupt(); device.disable_rx_ptr_interrupt(); device.disable_stopped_interrupt(); @@ -561,16 +578,16 @@ impl<'d, T: Instance> I2S<'d, T> { device.enable_stopped_interrupt(); } - async fn stop() { + async fn stop(r: pac::i2s::I2s, state: &State) { compiler_fence(Ordering::SeqCst); - let device = Device::::new(); + let device = Device::new(r); device.stop(); - T::state().started.store(false, Ordering::Relaxed); + state.started.store(false, Ordering::Relaxed); poll_fn(|cx| { - T::state().stop_waker.register(cx.waker()); + state.stop_waker.register(cx.waker()); if device.is_stopped() { trace!("STOP: Ready"); @@ -586,7 +603,7 @@ impl<'d, T: Instance> I2S<'d, T> { device.disable(); } - async fn send_from_ram(buffer_ptr: *const [S]) -> Result<(), Error> + async fn send_from_ram(r: pac::i2s::I2s, state: &State, buffer_ptr: *const [S]) -> Result<(), Error> where S: Sample, { @@ -596,22 +613,22 @@ impl<'d, T: Instance> I2S<'d, T> { compiler_fence(Ordering::SeqCst); - let device = Device::::new(); + let device = Device::new(r); device.update_tx(buffer_ptr)?; - Self::wait_tx_ptr_update().await; + Self::wait_tx_ptr_update(r, state).await; compiler_fence(Ordering::SeqCst); Ok(()) } - async fn wait_tx_ptr_update() { + async fn wait_tx_ptr_update(r: pac::i2s::I2s, state: &State) { let drop = OnDrop::new(move || { trace!("TX DROP: Stopping"); - let device = Device::::new(); + let device = Device::new(r); device.disable_tx_ptr_interrupt(); device.reset_tx_ptr_event(); device.disable_tx(); @@ -623,9 +640,9 @@ impl<'d, T: Instance> I2S<'d, T> { }); poll_fn(|cx| { - T::state().tx_waker.register(cx.waker()); + state.tx_waker.register(cx.waker()); - let device = Device::::new(); + let device = Device::new(r); if device.is_tx_ptr_updated() { trace!("TX POLL: Ready"); device.reset_tx_ptr_event(); @@ -641,7 +658,7 @@ impl<'d, T: Instance> I2S<'d, T> { drop.defuse(); } - async fn receive_from_ram(buffer_ptr: *mut [S]) -> Result<(), Error> + async fn receive_from_ram(r: pac::i2s::I2s, state: &State, buffer_ptr: *mut [S]) -> Result<(), Error> where S: Sample, { @@ -652,22 +669,22 @@ impl<'d, T: Instance> I2S<'d, T> { compiler_fence(Ordering::SeqCst); - let device = Device::::new(); + let device = Device::new(r); device.update_rx(buffer_ptr)?; - Self::wait_rx_ptr_update().await; + Self::wait_rx_ptr_update(r, state).await; compiler_fence(Ordering::SeqCst); Ok(()) } - async fn wait_rx_ptr_update() { + async fn wait_rx_ptr_update(r: pac::i2s::I2s, state: &State) { let drop = OnDrop::new(move || { trace!("RX DROP: Stopping"); - let device = Device::::new(); + let device = Device::new(r); device.disable_rx_ptr_interrupt(); device.reset_rx_ptr_event(); device.disable_rx(); @@ -679,9 +696,9 @@ impl<'d, T: Instance> I2S<'d, T> { }); poll_fn(|cx| { - T::state().rx_waker.register(cx.waker()); + state.rx_waker.register(cx.waker()); - let device = Device::::new(); + let device = Device::new(r); if device.is_rx_ptr_updated() { trace!("RX POLL: Ready"); device.reset_rx_ptr_event(); @@ -699,12 +716,14 @@ impl<'d, T: Instance> I2S<'d, T> { } /// I2S output -pub struct OutputStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> { - _p: Peri<'d, T>, +pub struct OutputStream<'d, S: Sample, const NB: usize, const NS: usize> { + r: pac::i2s::I2s, + state: &'static State, buffers: MultiBuffering, + _phantom: PhantomData<&'d ()>, } -impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> OutputStream<'d, T, S, NB, NS> { +impl<'d, S: Sample, const NB: usize, const NS: usize> OutputStream<'d, S, NB, NS> { /// Get a mutable reference to the current buffer. pub fn buffer(&mut self) -> &mut [S] { self.buffers.get_mut() @@ -715,10 +734,9 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> OutputStream< where S: Sample, { - let device = Device::::new(); + let device = Device::new(self.r); - let s = T::state(); - if s.started.load(Ordering::Relaxed) { + if self.state.started.load(Ordering::Relaxed) { self.stop().await; } @@ -727,11 +745,11 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> OutputStream< device.update_tx(self.buffers.switch())?; - s.started.store(true, Ordering::Relaxed); + self.state.started.store(true, Ordering::Relaxed); device.start(); - I2S::::wait_tx_ptr_update().await; + I2S::wait_tx_ptr_update(self.r, self.state).await; Ok(()) } @@ -739,7 +757,7 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> OutputStream< /// Stops the I2S transfer and waits until it has stopped. #[inline(always)] pub async fn stop(&self) { - I2S::::stop().await + I2S::stop(self.r, self.state).await } /// Sends the current buffer for transmission in the DMA. @@ -748,17 +766,19 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> OutputStream< where S: Sample, { - I2S::::send_from_ram(self.buffers.switch()).await + I2S::send_from_ram(self.r, self.state, self.buffers.switch()).await } } /// I2S input -pub struct InputStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> { - _p: Peri<'d, T>, +pub struct InputStream<'d, S: Sample, const NB: usize, const NS: usize> { + r: pac::i2s::I2s, + state: &'static State, buffers: MultiBuffering, + _phantom: PhantomData<&'d ()>, } -impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> InputStream<'d, T, S, NB, NS> { +impl<'d, S: Sample, const NB: usize, const NS: usize> InputStream<'d, S, NB, NS> { /// Get a mutable reference to the current buffer. pub fn buffer(&mut self) -> &mut [S] { self.buffers.get_mut() @@ -769,10 +789,9 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> InputStream<' where S: Sample, { - let device = Device::::new(); + let device = Device::new(self.r); - let s = T::state(); - if s.started.load(Ordering::Relaxed) { + if self.state.started.load(Ordering::Relaxed) { self.stop().await; } @@ -781,11 +800,11 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> InputStream<' device.update_rx(self.buffers.switch())?; - s.started.store(true, Ordering::Relaxed); + self.state.started.store(true, Ordering::Relaxed); device.start(); - I2S::::wait_rx_ptr_update().await; + I2S::wait_rx_ptr_update(self.r, self.state).await; Ok(()) } @@ -793,7 +812,7 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> InputStream<' /// Stops the I2S transfer and waits until it has stopped. #[inline(always)] pub async fn stop(&self) { - I2S::::stop().await + I2S::stop(self.r, self.state).await } /// Sets the current buffer for reception from the DMA. @@ -803,18 +822,20 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> InputStream<' where S: Sample, { - I2S::::receive_from_ram(self.buffers.switch_mut()).await + I2S::receive_from_ram(self.r, self.state, self.buffers.switch_mut()).await } } /// I2S full duplex stream (input & output) -pub struct FullDuplexStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> { - _p: Peri<'d, T>, +pub struct FullDuplexStream<'d, S: Sample, const NB: usize, const NS: usize> { + r: pac::i2s::I2s, + state: &'static State, buffers_out: MultiBuffering, buffers_in: MultiBuffering, + _phantom: PhantomData<&'d ()>, } -impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStream<'d, T, S, NB, NS> { +impl<'d, S: Sample, const NB: usize, const NS: usize> FullDuplexStream<'d, S, NB, NS> { /// Get the current output and input buffers. pub fn buffers(&mut self) -> (&mut [S], &[S]) { (self.buffers_out.get_mut(), self.buffers_in.get()) @@ -825,10 +846,9 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStr where S: Sample, { - let device = Device::::new(); + let device = Device::new(self.r); - let s = T::state(); - if s.started.load(Ordering::Relaxed) { + if self.state.started.load(Ordering::Relaxed) { self.stop().await; } @@ -839,12 +859,12 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStr device.update_tx(self.buffers_out.switch())?; device.update_rx(self.buffers_in.switch_mut())?; - s.started.store(true, Ordering::Relaxed); + self.state.started.store(true, Ordering::Relaxed); device.start(); - I2S::::wait_tx_ptr_update().await; - I2S::::wait_rx_ptr_update().await; + I2S::wait_tx_ptr_update(self.r, self.state).await; + I2S::wait_rx_ptr_update(self.r, self.state).await; Ok(()) } @@ -852,7 +872,7 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStr /// Stops the I2S transfer and waits until it has stopped. #[inline(always)] pub async fn stop(&self) { - I2S::::stop().await + I2S::stop(self.r, self.state).await } /// Sets the current buffers for output and input for transmission/reception from the DMA. @@ -861,18 +881,18 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStr where S: Sample, { - I2S::::send_from_ram(self.buffers_out.switch()).await?; - I2S::::receive_from_ram(self.buffers_in.switch_mut()).await?; + I2S::send_from_ram(self.r, self.state, self.buffers_out.switch()).await?; + I2S::receive_from_ram(self.r, self.state, self.buffers_in.switch_mut()).await?; Ok(()) } } /// Helper encapsulating common I2S device operations. -struct Device(pac::i2s::I2s, PhantomData); +struct Device(pac::i2s::I2s); -impl Device { - fn new() -> Self { - Self(T::regs(), PhantomData) +impl Device { + fn new(r: pac::i2s::I2s) -> Self { + Self(r) } #[inline(always)] -- cgit