diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs index 770df7c89..8a1188ce4 100644 --- a/embassy-nrf/src/i2s.rs +++ b/embassy-nrf/src/i2s.rs @@ -14,7 +14,7 @@ use embassy_hal_common::drop::OnDrop; use embassy_hal_common::{into_ref, PeripheralRef}; use crate::gpio::{AnyPin, Pin as GpioPin}; -use crate::interrupt::Interrupt; +use crate::interrupt::{self, Interrupt}; use crate::pac::i2s::RegisterBlock; use crate::util::{slice_in_ram_or, slice_ptr_parts}; use crate::{Peripheral, EASY_DMA_SIZE}; @@ -363,10 +363,39 @@ impl From for u8 { } } +/// Interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::Handler for InterruptHandler { + unsafe fn on_interrupt() { + let device = Device::::new(); + let s = T::state(); + + if device.is_tx_ptr_updated() { + trace!("TX INT"); + s.tx_waker.wake(); + device.disable_tx_ptr_interrupt(); + } + + if device.is_rx_ptr_updated() { + trace!("RX INT"); + s.rx_waker.wake(); + device.disable_rx_ptr_interrupt(); + } + + if device.is_stopped() { + trace!("STOPPED INT"); + s.stop_waker.wake(); + device.disable_stopped_interrupt(); + } + } +} + /// I2S driver. pub struct I2S<'d, T: Instance> { i2s: PeripheralRef<'d, T>, - irq: PeripheralRef<'d, T::Interrupt>, mck: Option>, sck: PeripheralRef<'d, AnyPin>, lrck: PeripheralRef<'d, AnyPin>, @@ -378,19 +407,18 @@ pub struct I2S<'d, T: Instance> { impl<'d, T: Instance> I2S<'d, T> { /// Create a new I2S in master mode - pub fn master( + pub fn new_master( i2s: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, mck: impl Peripheral

+ 'd, sck: impl Peripheral

+ 'd, lrck: impl Peripheral

+ 'd, master_clock: MasterClock, config: Config, ) -> Self { - into_ref!(i2s, irq, mck, sck, lrck); + into_ref!(i2s, mck, sck, lrck); Self { i2s, - irq, mck: Some(mck.map_into()), sck: sck.map_into(), lrck: lrck.map_into(), @@ -402,17 +430,16 @@ impl<'d, T: Instance> I2S<'d, T> { } /// Create a new I2S in slave mode - pub fn slave( + pub fn new_slave( i2s: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, sck: impl Peripheral

+ 'd, lrck: impl Peripheral

+ 'd, config: Config, ) -> Self { - into_ref!(i2s, irq, sck, lrck); + into_ref!(i2s, sck, lrck); Self { i2s, - irq, mck: None, sck: sck.map_into(), lrck: lrck.map_into(), @@ -537,9 +564,8 @@ impl<'d, T: Instance> I2S<'d, T> { } fn setup_interrupt(&self) { - self.irq.set_handler(Self::on_interrupt); - self.irq.unpend(); - self.irq.enable(); + unsafe { T::Interrupt::steal() }.unpend(); + unsafe { T::Interrupt::steal() }.enable(); let device = Device::::new(); device.disable_tx_ptr_interrupt(); @@ -555,29 +581,6 @@ impl<'d, T: Instance> I2S<'d, T> { device.enable_stopped_interrupt(); } - fn on_interrupt(_: *mut ()) { - let device = Device::::new(); - let s = T::state(); - - if device.is_tx_ptr_updated() { - trace!("TX INT"); - s.tx_waker.wake(); - device.disable_tx_ptr_interrupt(); - } - - if device.is_rx_ptr_updated() { - trace!("RX INT"); - s.rx_waker.wake(); - device.disable_rx_ptr_interrupt(); - } - - if device.is_stopped() { - trace!("STOPPED INT"); - s.stop_waker.wake(); - device.disable_stopped_interrupt(); - } - } - async fn stop() { compiler_fence(Ordering::SeqCst); @@ -1168,7 +1171,7 @@ pub(crate) mod sealed { } } -/// I2S peripehral instance. +/// I2S peripheral instance. pub trait Instance: Peripheral

+ sealed::Instance + 'static + Send { /// Interrupt for this peripheral. type Interrupt: Interrupt; diff --git a/examples/nrf52840/src/bin/i2s_effect.rs b/examples/nrf52840/src/bin/i2s_effect.rs index 52d46e4f9..391514d93 100644 --- a/examples/nrf52840/src/bin/i2s_effect.rs +++ b/examples/nrf52840/src/bin/i2s_effect.rs @@ -7,7 +7,7 @@ use core::f32::consts::PI; use defmt::{error, info}; use embassy_executor::Spawner; use embassy_nrf::i2s::{self, Channels, Config, MasterClock, MultiBuffering, Sample as _, SampleWidth, I2S}; -use embassy_nrf::interrupt; +use embassy_nrf::{bind_interrupts, peripherals}; use {defmt_rtt as _, panic_probe as _}; type Sample = i16; @@ -15,6 +15,10 @@ type Sample = i16; const NUM_BUFFERS: usize = 2; const NUM_SAMPLES: usize = 4; +bind_interrupts!(struct Irqs { + I2S => i2s::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); @@ -28,15 +32,10 @@ async fn main(_spawner: Spawner) { config.sample_width = SampleWidth::_16bit; config.channels = Channels::MonoLeft; - let irq = interrupt::take!(I2S); let buffers_out = MultiBuffering::::new(); let buffers_in = MultiBuffering::::new(); - let mut full_duplex_stream = I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).full_duplex( - p.P0_29, - p.P0_28, - buffers_out, - buffers_in, - ); + let mut full_duplex_stream = I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config) + .full_duplex(p.P0_29, p.P0_28, buffers_out, buffers_in); let mut modulator = SineOsc::new(); modulator.set_frequency(8.0, 1.0 / sample_rate as f32); diff --git a/examples/nrf52840/src/bin/i2s_monitor.rs b/examples/nrf52840/src/bin/i2s_monitor.rs index 5ebfd9542..4ed597c0d 100644 --- a/examples/nrf52840/src/bin/i2s_monitor.rs +++ b/examples/nrf52840/src/bin/i2s_monitor.rs @@ -5,14 +5,18 @@ use defmt::{debug, error, info}; use embassy_executor::Spawner; use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; -use embassy_nrf::interrupt; use embassy_nrf::pwm::{Prescaler, SimplePwm}; +use embassy_nrf::{bind_interrupts, peripherals}; use {defmt_rtt as _, panic_probe as _}; type Sample = i16; const NUM_SAMPLES: usize = 500; +bind_interrupts!(struct Irqs { + I2S => i2s::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); @@ -26,10 +30,9 @@ async fn main(_spawner: Spawner) { config.sample_width = SampleWidth::_16bit; config.channels = Channels::MonoLeft; - let irq = interrupt::take!(I2S); let buffers = DoubleBuffering::::new(); let mut input_stream = - I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers); + I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers); // Configure the PWM to use the pins corresponding to the RGB leds let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24); diff --git a/examples/nrf52840/src/bin/i2s_waveform.rs b/examples/nrf52840/src/bin/i2s_waveform.rs index eda930677..f2c1166b1 100644 --- a/examples/nrf52840/src/bin/i2s_waveform.rs +++ b/examples/nrf52840/src/bin/i2s_waveform.rs @@ -7,13 +7,17 @@ use core::f32::consts::PI; use defmt::{error, info}; use embassy_executor::Spawner; use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; -use embassy_nrf::interrupt; +use embassy_nrf::{bind_interrupts, peripherals}; use {defmt_rtt as _, panic_probe as _}; type Sample = i16; const NUM_SAMPLES: usize = 50; +bind_interrupts!(struct Irqs { + I2S => i2s::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); @@ -27,10 +31,9 @@ async fn main(_spawner: Spawner) { config.sample_width = SampleWidth::_16bit; config.channels = Channels::MonoLeft; - let irq = interrupt::take!(I2S); let buffers = DoubleBuffering::::new(); let mut output_stream = - I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).output(p.P0_28, buffers); + I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).output(p.P0_28, buffers); let mut waveform = Waveform::new(1.0 / sample_rate as f32);