nrf/i2s: switch to new interrupt binding.

This commit is contained in:
Dario Nieuwenhuis 2023-03-05 20:40:13 +01:00
parent 63b75eaf64
commit 34563b74aa
4 changed files with 59 additions and 51 deletions

View File

@ -14,7 +14,7 @@ use embassy_hal_common::drop::OnDrop;
use embassy_hal_common::{into_ref, PeripheralRef}; use embassy_hal_common::{into_ref, PeripheralRef};
use crate::gpio::{AnyPin, Pin as GpioPin}; use crate::gpio::{AnyPin, Pin as GpioPin};
use crate::interrupt::Interrupt; use crate::interrupt::{self, Interrupt};
use crate::pac::i2s::RegisterBlock; use crate::pac::i2s::RegisterBlock;
use crate::util::{slice_in_ram_or, slice_ptr_parts}; use crate::util::{slice_in_ram_or, slice_ptr_parts};
use crate::{Peripheral, EASY_DMA_SIZE}; use crate::{Peripheral, EASY_DMA_SIZE};
@ -363,10 +363,39 @@ impl From<Channels> for u8 {
} }
} }
/// Interrupt handler.
pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
let device = Device::<T>::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. /// I2S driver.
pub struct I2S<'d, T: Instance> { pub struct I2S<'d, T: Instance> {
i2s: PeripheralRef<'d, T>, i2s: PeripheralRef<'d, T>,
irq: PeripheralRef<'d, T::Interrupt>,
mck: Option<PeripheralRef<'d, AnyPin>>, mck: Option<PeripheralRef<'d, AnyPin>>,
sck: PeripheralRef<'d, AnyPin>, sck: PeripheralRef<'d, AnyPin>,
lrck: PeripheralRef<'d, AnyPin>, lrck: PeripheralRef<'d, AnyPin>,
@ -378,19 +407,18 @@ pub struct I2S<'d, T: Instance> {
impl<'d, T: Instance> I2S<'d, T> { impl<'d, T: Instance> I2S<'d, T> {
/// Create a new I2S in master mode /// Create a new I2S in master mode
pub fn master( pub fn new_master(
i2s: impl Peripheral<P = T> + 'd, i2s: impl Peripheral<P = T> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd, _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
mck: impl Peripheral<P = impl GpioPin> + 'd, mck: impl Peripheral<P = impl GpioPin> + 'd,
sck: impl Peripheral<P = impl GpioPin> + 'd, sck: impl Peripheral<P = impl GpioPin> + 'd,
lrck: impl Peripheral<P = impl GpioPin> + 'd, lrck: impl Peripheral<P = impl GpioPin> + 'd,
master_clock: MasterClock, master_clock: MasterClock,
config: Config, config: Config,
) -> Self { ) -> Self {
into_ref!(i2s, irq, mck, sck, lrck); into_ref!(i2s, mck, sck, lrck);
Self { Self {
i2s, i2s,
irq,
mck: Some(mck.map_into()), mck: Some(mck.map_into()),
sck: sck.map_into(), sck: sck.map_into(),
lrck: lrck.map_into(), lrck: lrck.map_into(),
@ -402,17 +430,16 @@ impl<'d, T: Instance> I2S<'d, T> {
} }
/// Create a new I2S in slave mode /// Create a new I2S in slave mode
pub fn slave( pub fn new_slave(
i2s: impl Peripheral<P = T> + 'd, i2s: impl Peripheral<P = T> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd, _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
sck: impl Peripheral<P = impl GpioPin> + 'd, sck: impl Peripheral<P = impl GpioPin> + 'd,
lrck: impl Peripheral<P = impl GpioPin> + 'd, lrck: impl Peripheral<P = impl GpioPin> + 'd,
config: Config, config: Config,
) -> Self { ) -> Self {
into_ref!(i2s, irq, sck, lrck); into_ref!(i2s, sck, lrck);
Self { Self {
i2s, i2s,
irq,
mck: None, mck: None,
sck: sck.map_into(), sck: sck.map_into(),
lrck: lrck.map_into(), lrck: lrck.map_into(),
@ -537,9 +564,8 @@ impl<'d, T: Instance> I2S<'d, T> {
} }
fn setup_interrupt(&self) { fn setup_interrupt(&self) {
self.irq.set_handler(Self::on_interrupt); unsafe { T::Interrupt::steal() }.unpend();
self.irq.unpend(); unsafe { T::Interrupt::steal() }.enable();
self.irq.enable();
let device = Device::<T>::new(); let device = Device::<T>::new();
device.disable_tx_ptr_interrupt(); device.disable_tx_ptr_interrupt();
@ -555,29 +581,6 @@ impl<'d, T: Instance> I2S<'d, T> {
device.enable_stopped_interrupt(); device.enable_stopped_interrupt();
} }
fn on_interrupt(_: *mut ()) {
let device = Device::<T>::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() { async fn stop() {
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
@ -1168,7 +1171,7 @@ pub(crate) mod sealed {
} }
} }
/// I2S peripehral instance. /// I2S peripheral instance.
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
/// Interrupt for this peripheral. /// Interrupt for this peripheral.
type Interrupt: Interrupt; type Interrupt: Interrupt;

View File

@ -7,7 +7,7 @@ use core::f32::consts::PI;
use defmt::{error, info}; use defmt::{error, info};
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_nrf::i2s::{self, Channels, Config, MasterClock, MultiBuffering, Sample as _, SampleWidth, I2S}; 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 _}; use {defmt_rtt as _, panic_probe as _};
type Sample = i16; type Sample = i16;
@ -15,6 +15,10 @@ type Sample = i16;
const NUM_BUFFERS: usize = 2; const NUM_BUFFERS: usize = 2;
const NUM_SAMPLES: usize = 4; const NUM_SAMPLES: usize = 4;
bind_interrupts!(struct Irqs {
I2S => i2s::InterruptHandler<peripherals::I2S>;
});
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let p = embassy_nrf::init(Default::default()); let p = embassy_nrf::init(Default::default());
@ -28,15 +32,10 @@ async fn main(_spawner: Spawner) {
config.sample_width = SampleWidth::_16bit; config.sample_width = SampleWidth::_16bit;
config.channels = Channels::MonoLeft; config.channels = Channels::MonoLeft;
let irq = interrupt::take!(I2S);
let buffers_out = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new(); let buffers_out = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
let buffers_in = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new(); let buffers_in = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::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( let mut full_duplex_stream = I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config)
p.P0_29, .full_duplex(p.P0_29, p.P0_28, buffers_out, buffers_in);
p.P0_28,
buffers_out,
buffers_in,
);
let mut modulator = SineOsc::new(); let mut modulator = SineOsc::new();
modulator.set_frequency(8.0, 1.0 / sample_rate as f32); modulator.set_frequency(8.0, 1.0 / sample_rate as f32);

View File

@ -5,14 +5,18 @@
use defmt::{debug, error, info}; use defmt::{debug, error, info};
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; 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::pwm::{Prescaler, SimplePwm};
use embassy_nrf::{bind_interrupts, peripherals};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
type Sample = i16; type Sample = i16;
const NUM_SAMPLES: usize = 500; const NUM_SAMPLES: usize = 500;
bind_interrupts!(struct Irqs {
I2S => i2s::InterruptHandler<peripherals::I2S>;
});
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let p = embassy_nrf::init(Default::default()); let p = embassy_nrf::init(Default::default());
@ -26,10 +30,9 @@ async fn main(_spawner: Spawner) {
config.sample_width = SampleWidth::_16bit; config.sample_width = SampleWidth::_16bit;
config.channels = Channels::MonoLeft; config.channels = Channels::MonoLeft;
let irq = interrupt::take!(I2S);
let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new(); let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
let mut input_stream = 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 // 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); let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24);

View File

@ -7,13 +7,17 @@ use core::f32::consts::PI;
use defmt::{error, info}; use defmt::{error, info};
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; 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 _}; use {defmt_rtt as _, panic_probe as _};
type Sample = i16; type Sample = i16;
const NUM_SAMPLES: usize = 50; const NUM_SAMPLES: usize = 50;
bind_interrupts!(struct Irqs {
I2S => i2s::InterruptHandler<peripherals::I2S>;
});
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let p = embassy_nrf::init(Default::default()); let p = embassy_nrf::init(Default::default());
@ -27,10 +31,9 @@ async fn main(_spawner: Spawner) {
config.sample_width = SampleWidth::_16bit; config.sample_width = SampleWidth::_16bit;
config.channels = Channels::MonoLeft; config.channels = Channels::MonoLeft;
let irq = interrupt::take!(I2S);
let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new(); let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
let mut output_stream = 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); let mut waveform = Waveform::new(1.0 / sample_rate as f32);