diff options
Diffstat (limited to 'embassy-nrf/src/spim.rs')
| -rw-r--r-- | embassy-nrf/src/spim.rs | 169 |
1 files changed, 156 insertions, 13 deletions
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index c410e49fd..34485609b 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs | |||
| @@ -6,23 +6,127 @@ use core::future::poll_fn; | |||
| 6 | use core::marker::PhantomData; | 6 | use core::marker::PhantomData; |
| 7 | #[cfg(feature = "_nrf52832_anomaly_109")] | 7 | #[cfg(feature = "_nrf52832_anomaly_109")] |
| 8 | use core::sync::atomic::AtomicU8; | 8 | use core::sync::atomic::AtomicU8; |
| 9 | use core::sync::atomic::{compiler_fence, Ordering}; | 9 | use core::sync::atomic::{Ordering, compiler_fence}; |
| 10 | use core::task::Poll; | 10 | use core::task::Poll; |
| 11 | 11 | ||
| 12 | use embassy_embedded_hal::SetConfig; | 12 | use embassy_embedded_hal::SetConfig; |
| 13 | use embassy_hal_internal::{Peri, PeripheralType}; | 13 | use embassy_hal_internal::{Peri, PeripheralType}; |
| 14 | use embassy_sync::waitqueue::AtomicWaker; | 14 | use embassy_sync::waitqueue::AtomicWaker; |
| 15 | pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; | 15 | pub use embedded_hal_02::spi::{MODE_0, MODE_1, MODE_2, MODE_3, Mode, Phase, Polarity}; |
| 16 | pub use pac::spim::vals::{Frequency, Order as BitOrder}; | 16 | pub use pac::spim::vals::Order as BitOrder; |
| 17 | 17 | ||
| 18 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | 18 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; |
| 19 | use crate::gpio::{self, convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _}; | 19 | use crate::gpio::{self, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, convert_drive}; |
| 20 | use crate::interrupt::typelevel::Interrupt; | 20 | use crate::interrupt::typelevel::Interrupt; |
| 21 | use crate::pac::gpio::vals as gpiovals; | 21 | use crate::pac::gpio::vals as gpiovals; |
| 22 | use crate::pac::spim::vals; | 22 | use crate::pac::spim::vals; |
| 23 | use crate::util::slice_in_ram_or; | 23 | use crate::util::slice_in_ram_or; |
| 24 | use crate::{interrupt, pac}; | 24 | use crate::{interrupt, pac}; |
| 25 | 25 | ||
| 26 | /// SPI frequencies. | ||
| 27 | #[repr(transparent)] | ||
| 28 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] | ||
| 29 | pub struct Frequency(u32); | ||
| 30 | impl Frequency { | ||
| 31 | #[doc = "125 kbps"] | ||
| 32 | pub const K125: Self = Self(0x0200_0000); | ||
| 33 | #[doc = "250 kbps"] | ||
| 34 | pub const K250: Self = Self(0x0400_0000); | ||
| 35 | #[doc = "500 kbps"] | ||
| 36 | pub const K500: Self = Self(0x0800_0000); | ||
| 37 | #[doc = "1 Mbps"] | ||
| 38 | pub const M1: Self = Self(0x1000_0000); | ||
| 39 | #[doc = "2 Mbps"] | ||
| 40 | pub const M2: Self = Self(0x2000_0000); | ||
| 41 | #[doc = "4 Mbps"] | ||
| 42 | pub const M4: Self = Self(0x4000_0000); | ||
| 43 | #[doc = "8 Mbps"] | ||
| 44 | pub const M8: Self = Self(0x8000_0000); | ||
| 45 | #[cfg(not(feature = "_spi-v1"))] | ||
| 46 | #[doc = "16 Mbps"] | ||
| 47 | pub const M16: Self = Self(0x0a00_0000); | ||
| 48 | #[cfg(not(feature = "_spi-v1"))] | ||
| 49 | #[doc = "32 Mbps"] | ||
| 50 | pub const M32: Self = Self(0x1400_0000); | ||
| 51 | } | ||
| 52 | |||
| 53 | impl Frequency { | ||
| 54 | #[cfg(feature = "_nrf54l")] | ||
| 55 | fn to_divisor(&self, clk: u32) -> u8 { | ||
| 56 | let frequency = match *self { | ||
| 57 | #[cfg(not(feature = "_spi-v1"))] | ||
| 58 | Self::M32 => 32_000_000, | ||
| 59 | #[cfg(not(feature = "_spi-v1"))] | ||
| 60 | Self::M16 => 16_000_000, | ||
| 61 | Self::M8 => 8_000_000, | ||
| 62 | Self::M4 => 4_000_000, | ||
| 63 | Self::M2 => 2_000_000, | ||
| 64 | Self::M1 => 1_000_000, | ||
| 65 | Self::K500 => 500_000, | ||
| 66 | Self::K250 => 250_000, | ||
| 67 | Self::K125 => 125_000, | ||
| 68 | _ => unreachable!(), | ||
| 69 | }; | ||
| 70 | let divisor = (clk / frequency) as u8; | ||
| 71 | divisor | ||
| 72 | } | ||
| 73 | } | ||
| 74 | impl core::fmt::Debug for Frequency { | ||
| 75 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { | ||
| 76 | match self.0 { | ||
| 77 | 0x0200_0000 => f.write_str("K125"), | ||
| 78 | 0x0400_0000 => f.write_str("K250"), | ||
| 79 | 0x0800_0000 => f.write_str("K500"), | ||
| 80 | 0x0a00_0000 => f.write_str("M16"), | ||
| 81 | 0x1000_0000 => f.write_str("M1"), | ||
| 82 | 0x1400_0000 => f.write_str("M32"), | ||
| 83 | 0x2000_0000 => f.write_str("M2"), | ||
| 84 | 0x4000_0000 => f.write_str("M4"), | ||
| 85 | 0x8000_0000 => f.write_str("M8"), | ||
| 86 | other => core::write!(f, "0x{:02X}", other), | ||
| 87 | } | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | #[cfg(feature = "defmt")] | ||
| 92 | impl defmt::Format for Frequency { | ||
| 93 | fn format(&self, f: defmt::Formatter) { | ||
| 94 | match self.0 { | ||
| 95 | 0x0200_0000 => defmt::write!(f, "K125"), | ||
| 96 | 0x0400_0000 => defmt::write!(f, "K250"), | ||
| 97 | 0x0800_0000 => defmt::write!(f, "K500"), | ||
| 98 | 0x0a00_0000 => defmt::write!(f, "M16"), | ||
| 99 | 0x1000_0000 => defmt::write!(f, "M1"), | ||
| 100 | 0x1400_0000 => defmt::write!(f, "M32"), | ||
| 101 | 0x2000_0000 => defmt::write!(f, "M2"), | ||
| 102 | 0x4000_0000 => defmt::write!(f, "M4"), | ||
| 103 | 0x8000_0000 => defmt::write!(f, "M8"), | ||
| 104 | other => defmt::write!(f, "0x{:02X}", other), | ||
| 105 | } | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | #[cfg(not(feature = "_nrf54l"))] | ||
| 110 | impl Into<pac::spim::vals::Frequency> for Frequency { | ||
| 111 | fn into(self) -> pac::spim::vals::Frequency { | ||
| 112 | use pac::spim::vals::Frequency as Freq; | ||
| 113 | match self { | ||
| 114 | #[cfg(not(feature = "_spi-v1"))] | ||
| 115 | Self::M32 => Freq::M32, | ||
| 116 | #[cfg(not(feature = "_spi-v1"))] | ||
| 117 | Self::M16 => Freq::M16, | ||
| 118 | Self::M8 => Freq::M8, | ||
| 119 | Self::M4 => Freq::M4, | ||
| 120 | Self::M2 => Freq::M2, | ||
| 121 | Self::M1 => Freq::M1, | ||
| 122 | Self::K500 => Freq::K500, | ||
| 123 | Self::K250 => Freq::K250, | ||
| 124 | Self::K125 => Freq::K125, | ||
| 125 | _ => unreachable!(), | ||
| 126 | } | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 26 | /// SPIM error | 130 | /// SPIM error |
| 27 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 131 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 28 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 132 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| @@ -103,6 +207,8 @@ pub struct Spim<'d> { | |||
| 103 | r: pac::spim::Spim, | 207 | r: pac::spim::Spim, |
| 104 | irq: interrupt::Interrupt, | 208 | irq: interrupt::Interrupt, |
| 105 | state: &'static State, | 209 | state: &'static State, |
| 210 | #[cfg(feature = "_nrf54l")] | ||
| 211 | clk: u32, | ||
| 106 | _p: PhantomData<&'d ()>, | 212 | _p: PhantomData<&'d ()>, |
| 107 | } | 213 | } |
| 108 | 214 | ||
| @@ -208,6 +314,8 @@ impl<'d> Spim<'d> { | |||
| 208 | r: T::regs(), | 314 | r: T::regs(), |
| 209 | irq: T::Interrupt::IRQ, | 315 | irq: T::Interrupt::IRQ, |
| 210 | state: T::state(), | 316 | state: T::state(), |
| 317 | #[cfg(feature = "_nrf54l")] | ||
| 318 | clk: T::clk(), | ||
| 211 | _p: PhantomData {}, | 319 | _p: PhantomData {}, |
| 212 | }; | 320 | }; |
| 213 | 321 | ||
| @@ -238,13 +346,13 @@ impl<'d> Spim<'d> { | |||
| 238 | 346 | ||
| 239 | // Set up the DMA read. | 347 | // Set up the DMA read. |
| 240 | let (rx_ptr, rx_len) = xfer_params(rx as *mut u8 as _, rx.len() as _, offset, length); | 348 | let (rx_ptr, rx_len) = xfer_params(rx as *mut u8 as _, rx.len() as _, offset, length); |
| 241 | r.rxd().ptr().write_value(rx_ptr); | 349 | r.dma().rx().ptr().write_value(rx_ptr); |
| 242 | r.rxd().maxcnt().write(|w| w.set_maxcnt(rx_len as _)); | 350 | r.dma().rx().maxcnt().write(|w| w.set_maxcnt(rx_len as _)); |
| 243 | 351 | ||
| 244 | // Set up the DMA write. | 352 | // Set up the DMA write. |
| 245 | let (tx_ptr, tx_len) = xfer_params(tx as *const u8 as _, tx.len() as _, offset, length); | 353 | let (tx_ptr, tx_len) = xfer_params(tx as *const u8 as _, tx.len() as _, offset, length); |
| 246 | r.txd().ptr().write_value(tx_ptr); | 354 | r.dma().tx().ptr().write_value(tx_ptr); |
| 247 | r.txd().maxcnt().write(|w| w.set_maxcnt(tx_len as _)); | 355 | r.dma().tx().maxcnt().write(|w| w.set_maxcnt(tx_len as _)); |
| 248 | 356 | ||
| 249 | /* | 357 | /* |
| 250 | trace!("XFER: offset: {}, length: {}", offset, length); | 358 | trace!("XFER: offset: {}, length: {}", offset, length); |
| @@ -259,8 +367,8 @@ impl<'d> Spim<'d> { | |||
| 259 | r.events_started().write_value(0); | 367 | r.events_started().write_value(0); |
| 260 | 368 | ||
| 261 | // Set rx/tx buffer lengths to 0... | 369 | // Set rx/tx buffer lengths to 0... |
| 262 | r.txd().maxcnt().write(|_| ()); | 370 | r.dma().tx().maxcnt().write(|_| ()); |
| 263 | r.rxd().maxcnt().write(|_| ()); | 371 | r.dma().rx().maxcnt().write(|_| ()); |
| 264 | 372 | ||
| 265 | // ...and keep track of original buffer lengths... | 373 | // ...and keep track of original buffer lengths... |
| 266 | s.tx.store(tx_len as _, Ordering::Relaxed); | 374 | s.tx.store(tx_len as _, Ordering::Relaxed); |
| @@ -447,8 +555,14 @@ impl<'d> Spim<'d> { | |||
| 447 | r.events_end().write_value(0); | 555 | r.events_end().write_value(0); |
| 448 | 556 | ||
| 449 | // Update DMA registers with correct rx/tx buffer sizes | 557 | // Update DMA registers with correct rx/tx buffer sizes |
| 450 | r.rxd().maxcnt().write(|w| w.set_maxcnt(s.rx.load(Ordering::Relaxed))); | 558 | r.dma() |
| 451 | r.txd().maxcnt().write(|w| w.set_maxcnt(s.tx.load(Ordering::Relaxed))); | 559 | .rx() |
| 560 | .maxcnt() | ||
| 561 | .write(|w| w.set_maxcnt(s.rx.load(Ordering::Relaxed))); | ||
| 562 | r.dma() | ||
| 563 | .tx() | ||
| 564 | .maxcnt() | ||
| 565 | .write(|w| w.set_maxcnt(s.tx.load(Ordering::Relaxed))); | ||
| 452 | 566 | ||
| 453 | r.intenset().write(|w| w.set_end(true)); | 567 | r.intenset().write(|w| w.set_end(true)); |
| 454 | // ... and start actual, hopefully glitch-free transmission | 568 | // ... and start actual, hopefully glitch-free transmission |
| @@ -503,6 +617,8 @@ impl State { | |||
| 503 | pub(crate) trait SealedInstance { | 617 | pub(crate) trait SealedInstance { |
| 504 | fn regs() -> pac::spim::Spim; | 618 | fn regs() -> pac::spim::Spim; |
| 505 | fn state() -> &'static State; | 619 | fn state() -> &'static State; |
| 620 | #[cfg(feature = "_nrf54l")] | ||
| 621 | fn clk() -> u32; | ||
| 506 | } | 622 | } |
| 507 | 623 | ||
| 508 | /// SPIM peripheral instance | 624 | /// SPIM peripheral instance |
| @@ -512,6 +628,28 @@ pub trait Instance: SealedInstance + PeripheralType + 'static { | |||
| 512 | type Interrupt: interrupt::typelevel::Interrupt; | 628 | type Interrupt: interrupt::typelevel::Interrupt; |
| 513 | } | 629 | } |
| 514 | 630 | ||
| 631 | #[cfg(feature = "_nrf54l")] | ||
| 632 | macro_rules! impl_spim { | ||
| 633 | ($type:ident, $pac_type:ident, $irq:ident, $clk:expr) => { | ||
| 634 | impl crate::spim::SealedInstance for peripherals::$type { | ||
| 635 | fn regs() -> pac::spim::Spim { | ||
| 636 | pac::$pac_type | ||
| 637 | } | ||
| 638 | fn state() -> &'static crate::spim::State { | ||
| 639 | static STATE: crate::spim::State = crate::spim::State::new(); | ||
| 640 | &STATE | ||
| 641 | } | ||
| 642 | fn clk() -> u32 { | ||
| 643 | $clk | ||
| 644 | } | ||
| 645 | } | ||
| 646 | impl crate::spim::Instance for peripherals::$type { | ||
| 647 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 648 | } | ||
| 649 | }; | ||
| 650 | } | ||
| 651 | |||
| 652 | #[cfg(not(feature = "_nrf54l"))] | ||
| 515 | macro_rules! impl_spim { | 653 | macro_rules! impl_spim { |
| 516 | ($type:ident, $pac_type:ident, $irq:ident) => { | 654 | ($type:ident, $pac_type:ident, $irq:ident) => { |
| 517 | impl crate::spim::SealedInstance for peripherals::$type { | 655 | impl crate::spim::SealedInstance for peripherals::$type { |
| @@ -638,7 +776,12 @@ impl<'d> SetConfig for Spim<'d> { | |||
| 638 | 776 | ||
| 639 | // Configure frequency. | 777 | // Configure frequency. |
| 640 | let frequency = config.frequency; | 778 | let frequency = config.frequency; |
| 641 | r.frequency().write(|w| w.set_frequency(frequency)); | 779 | #[cfg(not(feature = "_nrf54l"))] |
| 780 | r.frequency().write(|w| w.set_frequency(frequency.into())); | ||
| 781 | #[cfg(feature = "_nrf54l")] | ||
| 782 | { | ||
| 783 | r.prescaler().write(|w| w.set_divisor(frequency.to_divisor(self.clk))); | ||
| 784 | } | ||
| 642 | 785 | ||
| 643 | // Set over-read character | 786 | // Set over-read character |
| 644 | let orc = config.orc; | 787 | let orc = config.orc; |
