nrf/spim: switch to new interrupt binding.

This commit is contained in:
Dario Nieuwenhuis
2023-03-05 22:00:52 +01:00
parent 2dc5608203
commit a32e82029a
4 changed files with 50 additions and 36 deletions

View File

@ -3,6 +3,7 @@
#![macro_use]
use core::future::poll_fn;
use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll;
@ -14,7 +15,7 @@ pub use pac::spim0::frequency::FREQUENCY_A as Frequency;
use crate::chip::FORCE_COPY_BUFFER_SIZE;
use crate::gpio::sealed::Pin as _;
use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
use crate::interrupt::{Interrupt, InterruptExt};
use crate::interrupt::{self, Interrupt, InterruptExt};
use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
use crate::{pac, Peripheral};
@ -31,11 +32,6 @@ pub enum Error {
BufferNotInRAM,
}
/// SPIM driver.
pub struct Spim<'d, T: Instance> {
_p: PeripheralRef<'d, T>,
}
/// SPIM configuration.
#[non_exhaustive]
pub struct Config {
@ -62,11 +58,33 @@ impl Default for Config {
}
}
/// 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 r = T::regs();
let s = T::state();
if r.events_end.read().bits() != 0 {
s.end_waker.wake();
r.intenclr.write(|w| w.end().clear());
}
}
}
/// SPIM driver.
pub struct Spim<'d, T: Instance> {
_p: PeripheralRef<'d, T>,
}
impl<'d, T: Instance> Spim<'d, T> {
/// Create a new SPIM driver.
pub fn new(
spim: 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,
miso: impl Peripheral<P = impl GpioPin> + 'd,
mosi: impl Peripheral<P = impl GpioPin> + 'd,
@ -75,7 +93,6 @@ impl<'d, T: Instance> Spim<'d, T> {
into_ref!(sck, miso, mosi);
Self::new_inner(
spim,
irq,
sck.map_into(),
Some(miso.map_into()),
Some(mosi.map_into()),
@ -86,36 +103,35 @@ impl<'d, T: Instance> Spim<'d, T> {
/// Create a new SPIM driver, capable of TX only (MOSI only).
pub fn new_txonly(
spim: 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,
mosi: impl Peripheral<P = impl GpioPin> + 'd,
config: Config,
) -> Self {
into_ref!(sck, mosi);
Self::new_inner(spim, irq, sck.map_into(), None, Some(mosi.map_into()), config)
Self::new_inner(spim, sck.map_into(), None, Some(mosi.map_into()), config)
}
/// Create a new SPIM driver, capable of RX only (MISO only).
pub fn new_rxonly(
spim: 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,
miso: impl Peripheral<P = impl GpioPin> + 'd,
config: Config,
) -> Self {
into_ref!(sck, miso);
Self::new_inner(spim, irq, sck.map_into(), Some(miso.map_into()), None, config)
Self::new_inner(spim, sck.map_into(), Some(miso.map_into()), None, config)
}
fn new_inner(
spim: impl Peripheral<P = T> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd,
sck: PeripheralRef<'d, AnyPin>,
miso: Option<PeripheralRef<'d, AnyPin>>,
mosi: Option<PeripheralRef<'d, AnyPin>>,
config: Config,
) -> Self {
into_ref!(spim, irq);
into_ref!(spim);
let r = T::regs();
@ -191,23 +207,12 @@ impl<'d, T: Instance> Spim<'d, T> {
// Disable all events interrupts
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
irq.set_handler(Self::on_interrupt);
irq.unpend();
irq.enable();
unsafe { T::Interrupt::steal() }.unpend();
unsafe { T::Interrupt::steal() }.enable();
Self { _p: spim }
}
fn on_interrupt(_: *mut ()) {
let r = T::regs();
let s = T::state();
if r.events_end.read().bits() != 0 {
s.end_waker.wake();
r.intenclr.write(|w| w.end().clear());
}
}
fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
slice_in_ram_or(tx, Error::BufferNotInRAM)?;
// NOTE: RAM slice check for rx is not necessary, as a mutable