aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf/src/spim.rs
diff options
context:
space:
mode:
authorRaul Alimbekov <[email protected]>2025-12-16 09:05:22 +0300
committerGitHub <[email protected]>2025-12-16 09:05:22 +0300
commitc9a04b4b732b7a3b696eb8223664c1a7942b1875 (patch)
tree6dbe5c02e66eed8d8762f13f95afd24f8db2b38c /embassy-nrf/src/spim.rs
parentcde24a3ef1117653ba5ed4184102b33f745782fb (diff)
parent5ae6e060ec1c90561719aabdc29d5b6e7b8b0a82 (diff)
Merge branch 'main' into main
Diffstat (limited to 'embassy-nrf/src/spim.rs')
-rw-r--r--embassy-nrf/src/spim.rs169
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;
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7#[cfg(feature = "_nrf52832_anomaly_109")] 7#[cfg(feature = "_nrf52832_anomaly_109")]
8use core::sync::atomic::AtomicU8; 8use core::sync::atomic::AtomicU8;
9use core::sync::atomic::{compiler_fence, Ordering}; 9use core::sync::atomic::{Ordering, compiler_fence};
10use core::task::Poll; 10use core::task::Poll;
11 11
12use embassy_embedded_hal::SetConfig; 12use embassy_embedded_hal::SetConfig;
13use embassy_hal_internal::{Peri, PeripheralType}; 13use embassy_hal_internal::{Peri, PeripheralType};
14use embassy_sync::waitqueue::AtomicWaker; 14use embassy_sync::waitqueue::AtomicWaker;
15pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 15pub use embedded_hal_02::spi::{MODE_0, MODE_1, MODE_2, MODE_3, Mode, Phase, Polarity};
16pub use pac::spim::vals::{Frequency, Order as BitOrder}; 16pub use pac::spim::vals::Order as BitOrder;
17 17
18use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; 18use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
19use crate::gpio::{self, convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _}; 19use crate::gpio::{self, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, convert_drive};
20use crate::interrupt::typelevel::Interrupt; 20use crate::interrupt::typelevel::Interrupt;
21use crate::pac::gpio::vals as gpiovals; 21use crate::pac::gpio::vals as gpiovals;
22use crate::pac::spim::vals; 22use crate::pac::spim::vals;
23use crate::util::slice_in_ram_or; 23use crate::util::slice_in_ram_or;
24use crate::{interrupt, pac}; 24use crate::{interrupt, pac};
25 25
26/// SPI frequencies.
27#[repr(transparent)]
28#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
29pub struct Frequency(u32);
30impl 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
53impl 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}
74impl 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")]
92impl 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"))]
110impl 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 {
503pub(crate) trait SealedInstance { 617pub(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")]
632macro_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"))]
515macro_rules! impl_spim { 653macro_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;