embassy_nrf/
spim.rs

1//! Serial Peripheral Instance in master mode (SPIM) driver.
2
3#![macro_use]
4
5use core::future::poll_fn;
6use core::marker::PhantomData;
7#[cfg(feature = "_nrf52832_anomaly_109")]
8use core::sync::atomic::AtomicU8;
9use core::sync::atomic::{Ordering, compiler_fence};
10use core::task::Poll;
11
12use embassy_embedded_hal::SetConfig;
13use embassy_hal_internal::{Peri, PeripheralType};
14use embassy_sync::waitqueue::AtomicWaker;
15pub use embedded_hal_02::spi::{MODE_0, MODE_1, MODE_2, MODE_3, Mode, Phase, Polarity};
16pub use pac::spim::vals::Order as BitOrder;
17
18use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
19use crate::gpio::{self, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, convert_drive};
20use crate::interrupt::typelevel::Interrupt;
21use crate::pac::gpio::vals as gpiovals;
22use crate::pac::spim::vals;
23use crate::util::slice_in_ram_or;
24use crate::{interrupt, pac};
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
130/// SPIM error
131#[derive(Debug, Clone, Copy, PartialEq, Eq)]
132#[cfg_attr(feature = "defmt", derive(defmt::Format))]
133#[non_exhaustive]
134pub enum Error {
135    /// EasyDMA can only read from data memory, read only buffers in flash will fail.
136    BufferNotInRAM,
137}
138
139/// SPIM configuration.
140#[non_exhaustive]
141#[derive(Clone)]
142pub struct Config {
143    /// Frequency
144    pub frequency: Frequency,
145
146    /// SPI mode
147    pub mode: Mode,
148
149    /// Bit order
150    pub bit_order: BitOrder,
151
152    /// Overread character.
153    ///
154    /// When doing bidirectional transfers, if the TX buffer is shorter than the RX buffer,
155    /// this byte will be transmitted in the MOSI line for the left-over bytes.
156    pub orc: u8,
157
158    /// Drive strength for the SCK line.
159    pub sck_drive: OutputDrive,
160
161    /// Drive strength for the MOSI line.
162    pub mosi_drive: OutputDrive,
163}
164
165impl Default for Config {
166    fn default() -> Self {
167        Self {
168            frequency: Frequency::M1,
169            mode: MODE_0,
170            bit_order: BitOrder::MSB_FIRST,
171            orc: 0x00,
172            sck_drive: OutputDrive::HighDrive,
173            mosi_drive: OutputDrive::HighDrive,
174        }
175    }
176}
177
178/// Interrupt handler.
179pub struct InterruptHandler<T: Instance> {
180    _phantom: PhantomData<T>,
181}
182
183impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
184    unsafe fn on_interrupt() {
185        let r = T::regs();
186        let s = T::state();
187
188        #[cfg(feature = "_nrf52832_anomaly_109")]
189        {
190            // Ideally we should call this only during the first chunk transfer,
191            // but so far calling this every time doesn't seem to be causing any issues.
192            if r.events_started().read() != 0 {
193                s.waker.wake();
194                r.intenclr().write(|w| w.set_started(true));
195            }
196        }
197
198        if r.events_end().read() != 0 {
199            s.waker.wake();
200            r.intenclr().write(|w| w.set_end(true));
201        }
202    }
203}
204
205/// SPIM driver.
206pub struct Spim<'d> {
207    r: pac::spim::Spim,
208    irq: interrupt::Interrupt,
209    state: &'static State,
210    #[cfg(feature = "_nrf54l")]
211    clk: u32,
212    _p: PhantomData<&'d ()>,
213}
214
215impl<'d> Spim<'d> {
216    /// Create a new SPIM driver.
217    pub fn new<T: Instance>(
218        spim: Peri<'d, T>,
219        _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
220        sck: Peri<'d, impl GpioPin>,
221        miso: Peri<'d, impl GpioPin>,
222        mosi: Peri<'d, impl GpioPin>,
223        config: Config,
224    ) -> Self {
225        Self::new_inner(spim, Some(sck.into()), Some(miso.into()), Some(mosi.into()), config)
226    }
227
228    /// Create a new SPIM driver, capable of TX only (MOSI only).
229    pub fn new_txonly<T: Instance>(
230        spim: Peri<'d, T>,
231        _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
232        sck: Peri<'d, impl GpioPin>,
233        mosi: Peri<'d, impl GpioPin>,
234        config: Config,
235    ) -> Self {
236        Self::new_inner(spim, Some(sck.into()), None, Some(mosi.into()), config)
237    }
238
239    /// Create a new SPIM driver, capable of RX only (MISO only).
240    pub fn new_rxonly<T: Instance>(
241        spim: Peri<'d, T>,
242        _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
243        sck: Peri<'d, impl GpioPin>,
244        miso: Peri<'d, impl GpioPin>,
245        config: Config,
246    ) -> Self {
247        Self::new_inner(spim, Some(sck.into()), Some(miso.into()), None, config)
248    }
249
250    /// Create a new SPIM driver, capable of TX only (MOSI only), without SCK pin.
251    pub fn new_txonly_nosck<T: Instance>(
252        spim: Peri<'d, T>,
253        _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
254        mosi: Peri<'d, impl GpioPin>,
255        config: Config,
256    ) -> Self {
257        Self::new_inner(spim, None, None, Some(mosi.into()), config)
258    }
259
260    fn new_inner<T: Instance>(
261        _spim: Peri<'d, T>,
262        sck: Option<Peri<'d, AnyPin>>,
263        miso: Option<Peri<'d, AnyPin>>,
264        mosi: Option<Peri<'d, AnyPin>>,
265        config: Config,
266    ) -> Self {
267        let r = T::regs();
268
269        // Configure pins
270        if let Some(sck) = &sck {
271            sck.conf().write(|w| {
272                w.set_dir(gpiovals::Dir::OUTPUT);
273                convert_drive(w, config.sck_drive);
274            });
275        }
276        if let Some(mosi) = &mosi {
277            mosi.conf().write(|w| {
278                w.set_dir(gpiovals::Dir::OUTPUT);
279                convert_drive(w, config.mosi_drive);
280            });
281        }
282        if let Some(miso) = &miso {
283            miso.conf().write(|w| w.set_input(gpiovals::Input::CONNECT));
284        }
285
286        match config.mode.polarity {
287            Polarity::IdleHigh => {
288                if let Some(sck) = &sck {
289                    sck.set_high();
290                }
291                if let Some(mosi) = &mosi {
292                    mosi.set_high();
293                }
294            }
295            Polarity::IdleLow => {
296                if let Some(sck) = &sck {
297                    sck.set_low();
298                }
299                if let Some(mosi) = &mosi {
300                    mosi.set_low();
301                }
302            }
303        }
304
305        // Select pins.
306        r.psel().sck().write_value(sck.psel_bits());
307        r.psel().mosi().write_value(mosi.psel_bits());
308        r.psel().miso().write_value(miso.psel_bits());
309
310        // Enable SPIM instance.
311        r.enable().write(|w| w.set_enable(vals::Enable::ENABLED));
312
313        let mut spim = Self {
314            r: T::regs(),
315            irq: T::Interrupt::IRQ,
316            state: T::state(),
317            #[cfg(feature = "_nrf54l")]
318            clk: T::clk(),
319            _p: PhantomData {},
320        };
321
322        // Apply runtime peripheral configuration
323        Self::set_config(&mut spim, &config).unwrap();
324
325        // Disable all events interrupts
326        r.intenclr().write(|w| w.0 = 0xFFFF_FFFF);
327
328        T::Interrupt::unpend();
329        unsafe { T::Interrupt::enable() };
330
331        spim
332    }
333
334    fn prepare_dma_transfer(&mut self, rx: *mut [u8], tx: *const [u8], offset: usize, length: usize) {
335        compiler_fence(Ordering::SeqCst);
336
337        let r = self.r;
338
339        fn xfer_params(ptr: u32, total: usize, offset: usize, length: usize) -> (u32, usize) {
340            if total > offset {
341                (ptr.wrapping_add(offset as _), core::cmp::min(total - offset, length))
342            } else {
343                (ptr, 0)
344            }
345        }
346
347        // Set up the DMA read.
348        let (rx_ptr, rx_len) = xfer_params(rx as *mut u8 as _, rx.len() as _, offset, length);
349        r.dma().rx().ptr().write_value(rx_ptr);
350        r.dma().rx().maxcnt().write(|w| w.set_maxcnt(rx_len as _));
351
352        // Set up the DMA write.
353        let (tx_ptr, tx_len) = xfer_params(tx as *const u8 as _, tx.len() as _, offset, length);
354        r.dma().tx().ptr().write_value(tx_ptr);
355        r.dma().tx().maxcnt().write(|w| w.set_maxcnt(tx_len as _));
356
357        /*
358        trace!("XFER: offset: {}, length: {}", offset, length);
359        trace!("RX(len: {}, ptr: {=u32:02x})", rx_len, rx_ptr as u32);
360        trace!("TX(len: {}, ptr: {=u32:02x})", tx_len, tx_ptr as u32);
361        */
362
363        #[cfg(feature = "_nrf52832_anomaly_109")]
364        if offset == 0 {
365            let s = self.state;
366
367            r.events_started().write_value(0);
368
369            // Set rx/tx buffer lengths to 0...
370            r.dma().tx().maxcnt().write(|_| ());
371            r.dma().rx().maxcnt().write(|_| ());
372
373            // ...and keep track of original buffer lengths...
374            s.tx.store(tx_len as _, Ordering::Relaxed);
375            s.rx.store(rx_len as _, Ordering::Relaxed);
376
377            // ...signalling the start of the fake transfer.
378            r.intenset().write(|w| w.set_started(true));
379        }
380
381        // Reset and enable the event
382        r.events_end().write_value(0);
383        r.intenset().write(|w| w.set_end(true));
384
385        // Start SPI transaction.
386        r.tasks_start().write_value(1);
387    }
388
389    fn blocking_inner_from_ram_chunk(&mut self, rx: *mut [u8], tx: *const [u8], offset: usize, length: usize) {
390        self.prepare_dma_transfer(rx, tx, offset, length);
391
392        #[cfg(feature = "_nrf52832_anomaly_109")]
393        if offset == 0 {
394            while self.nrf52832_dma_workaround_status().is_pending() {}
395        }
396
397        // Wait for 'end' event.
398        while self.r.events_end().read() == 0 {}
399
400        compiler_fence(Ordering::SeqCst);
401    }
402
403    fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
404        slice_in_ram_or(tx, Error::BufferNotInRAM)?;
405        // NOTE: RAM slice check for rx is not necessary, as a mutable
406        // slice can only be built from data located in RAM.
407
408        let xfer_len = core::cmp::max(rx.len(), tx.len());
409        for offset in (0..xfer_len).step_by(EASY_DMA_SIZE) {
410            let length = core::cmp::min(xfer_len - offset, EASY_DMA_SIZE);
411            self.blocking_inner_from_ram_chunk(rx, tx, offset, length);
412        }
413        Ok(())
414    }
415
416    fn blocking_inner(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(), Error> {
417        match self.blocking_inner_from_ram(rx, tx) {
418            Ok(_) => Ok(()),
419            Err(Error::BufferNotInRAM) => {
420                // trace!("Copying SPIM tx buffer into RAM for DMA");
421                let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()];
422                tx_ram_buf.copy_from_slice(tx);
423                self.blocking_inner_from_ram(rx, tx_ram_buf)
424            }
425        }
426    }
427
428    async fn async_inner_from_ram_chunk(&mut self, rx: *mut [u8], tx: *const [u8], offset: usize, length: usize) {
429        self.prepare_dma_transfer(rx, tx, offset, length);
430
431        #[cfg(feature = "_nrf52832_anomaly_109")]
432        if offset == 0 {
433            poll_fn(|cx| {
434                let s = self.state;
435
436                s.waker.register(cx.waker());
437
438                self.nrf52832_dma_workaround_status()
439            })
440            .await;
441        }
442
443        // Wait for 'end' event.
444        poll_fn(|cx| {
445            self.state.waker.register(cx.waker());
446            if self.r.events_end().read() != 0 {
447                return Poll::Ready(());
448            }
449
450            Poll::Pending
451        })
452        .await;
453
454        compiler_fence(Ordering::SeqCst);
455    }
456
457    async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
458        slice_in_ram_or(tx, Error::BufferNotInRAM)?;
459        // NOTE: RAM slice check for rx is not necessary, as a mutable
460        // slice can only be built from data located in RAM.
461
462        let xfer_len = core::cmp::max(rx.len(), tx.len());
463        for offset in (0..xfer_len).step_by(EASY_DMA_SIZE) {
464            let length = core::cmp::min(xfer_len - offset, EASY_DMA_SIZE);
465            self.async_inner_from_ram_chunk(rx, tx, offset, length).await;
466        }
467        Ok(())
468    }
469
470    async fn async_inner(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(), Error> {
471        match self.async_inner_from_ram(rx, tx).await {
472            Ok(_) => Ok(()),
473            Err(Error::BufferNotInRAM) => {
474                // trace!("Copying SPIM tx buffer into RAM for DMA");
475                let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()];
476                tx_ram_buf.copy_from_slice(tx);
477                self.async_inner_from_ram(rx, tx_ram_buf).await
478            }
479        }
480    }
481
482    /// Reads data from the SPI bus without sending anything. Blocks until the buffer has been filled.
483    pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> {
484        self.blocking_inner(data, &[])
485    }
486
487    /// Simultaneously sends and receives data. Blocks until the transmission is completed.
488    /// If necessary, the write buffer will be copied into RAM (see struct description for detail).
489    pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
490        self.blocking_inner(read, write)
491    }
492
493    /// Same as [`blocking_transfer`](Spim::blocking_transfer) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
494    pub fn blocking_transfer_from_ram(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
495        self.blocking_inner(read, write)
496    }
497
498    /// Simultaneously sends and receives data.
499    /// Places the received data into the same buffer and blocks until the transmission is completed.
500    pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> {
501        self.blocking_inner_from_ram(data, data)
502    }
503
504    /// Sends data, discarding any received data. Blocks  until the transmission is completed.
505    /// If necessary, the write buffer will be copied into RAM (see struct description for detail).
506    pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> {
507        self.blocking_inner(&mut [], data)
508    }
509
510    /// Same as [`blocking_write`](Spim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
511    pub fn blocking_write_from_ram(&mut self, data: &[u8]) -> Result<(), Error> {
512        self.blocking_inner(&mut [], data)
513    }
514
515    /// Reads data from the SPI bus without sending anything.
516    pub async fn read(&mut self, data: &mut [u8]) -> Result<(), Error> {
517        self.async_inner(data, &[]).await
518    }
519
520    /// Simultaneously sends and receives data.
521    /// If necessary, the write buffer will be copied into RAM (see struct description for detail).
522    pub async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
523        self.async_inner(read, write).await
524    }
525
526    /// Same as [`transfer`](Spim::transfer) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
527    pub async fn transfer_from_ram(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
528        self.async_inner_from_ram(read, write).await
529    }
530
531    /// Simultaneously sends and receives data. Places the received data into the same buffer.
532    pub async fn transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> {
533        self.async_inner_from_ram(data, data).await
534    }
535
536    /// Sends data, discarding any received data.
537    /// If necessary, the write buffer will be copied into RAM (see struct description for detail).
538    pub async fn write(&mut self, data: &[u8]) -> Result<(), Error> {
539        self.async_inner(&mut [], data).await
540    }
541
542    /// Same as [`write`](Spim::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
543    pub async fn write_from_ram(&mut self, data: &[u8]) -> Result<(), Error> {
544        self.async_inner_from_ram(&mut [], data).await
545    }
546
547    #[cfg(feature = "_nrf52832_anomaly_109")]
548    fn nrf52832_dma_workaround_status(&mut self) -> Poll<()> {
549        let r = self.r;
550        if r.events_started().read() != 0 {
551            let s = self.state;
552
553            // Handle the first "fake" transmission
554            r.events_started().write_value(0);
555            r.events_end().write_value(0);
556
557            // Update DMA registers with correct rx/tx buffer sizes
558            r.dma()
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)));
566
567            r.intenset().write(|w| w.set_end(true));
568            // ... and start actual, hopefully glitch-free transmission
569            r.tasks_start().write_value(1);
570            return Poll::Ready(());
571        }
572        Poll::Pending
573    }
574}
575
576impl<'d> Drop for Spim<'d> {
577    fn drop(&mut self) {
578        trace!("spim drop");
579
580        // TODO check for abort, wait for xxxstopped
581
582        // disable!
583        let r = self.r;
584        r.enable().write(|w| w.set_enable(vals::Enable::DISABLED));
585
586        gpio::deconfigure_pin(r.psel().sck().read());
587        gpio::deconfigure_pin(r.psel().miso().read());
588        gpio::deconfigure_pin(r.psel().mosi().read());
589
590        // Disable all events interrupts
591        cortex_m::peripheral::NVIC::mask(self.irq);
592
593        trace!("spim drop: done");
594    }
595}
596
597pub(crate) struct State {
598    waker: AtomicWaker,
599    #[cfg(feature = "_nrf52832_anomaly_109")]
600    rx: AtomicU8,
601    #[cfg(feature = "_nrf52832_anomaly_109")]
602    tx: AtomicU8,
603}
604
605impl State {
606    pub(crate) const fn new() -> Self {
607        Self {
608            waker: AtomicWaker::new(),
609            #[cfg(feature = "_nrf52832_anomaly_109")]
610            rx: AtomicU8::new(0),
611            #[cfg(feature = "_nrf52832_anomaly_109")]
612            tx: AtomicU8::new(0),
613        }
614    }
615}
616
617pub(crate) trait SealedInstance {
618    fn regs() -> pac::spim::Spim;
619    fn state() -> &'static State;
620    #[cfg(feature = "_nrf54l")]
621    fn clk() -> u32;
622}
623
624/// SPIM peripheral instance
625#[allow(private_bounds)]
626pub trait Instance: SealedInstance + PeripheralType + 'static {
627    /// Interrupt for this peripheral.
628    type Interrupt: interrupt::typelevel::Interrupt;
629}
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"))]
653macro_rules! impl_spim {
654    ($type:ident, $pac_type:ident, $irq:ident) => {
655        impl crate::spim::SealedInstance for peripherals::$type {
656            fn regs() -> pac::spim::Spim {
657                pac::$pac_type
658            }
659            fn state() -> &'static crate::spim::State {
660                static STATE: crate::spim::State = crate::spim::State::new();
661                &STATE
662            }
663        }
664        impl crate::spim::Instance for peripherals::$type {
665            type Interrupt = crate::interrupt::typelevel::$irq;
666        }
667    };
668}
669
670// ====================
671
672mod eh02 {
673    use super::*;
674
675    impl<'d> embedded_hal_02::blocking::spi::Transfer<u8> for Spim<'d> {
676        type Error = Error;
677        fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
678            self.blocking_transfer_in_place(words)?;
679            Ok(words)
680        }
681    }
682
683    impl<'d> embedded_hal_02::blocking::spi::Write<u8> for Spim<'d> {
684        type Error = Error;
685
686        fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
687            self.blocking_write(words)
688        }
689    }
690}
691
692impl embedded_hal_1::spi::Error for Error {
693    fn kind(&self) -> embedded_hal_1::spi::ErrorKind {
694        match *self {
695            Self::BufferNotInRAM => embedded_hal_1::spi::ErrorKind::Other,
696        }
697    }
698}
699
700impl<'d> embedded_hal_1::spi::ErrorType for Spim<'d> {
701    type Error = Error;
702}
703
704impl<'d> embedded_hal_1::spi::SpiBus<u8> for Spim<'d> {
705    fn flush(&mut self) -> Result<(), Self::Error> {
706        Ok(())
707    }
708
709    fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
710        self.blocking_transfer(words, &[])
711    }
712
713    fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
714        self.blocking_write(words)
715    }
716
717    fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
718        self.blocking_transfer(read, write)
719    }
720
721    fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
722        self.blocking_transfer_in_place(words)
723    }
724}
725
726impl<'d> embedded_hal_async::spi::SpiBus<u8> for Spim<'d> {
727    async fn flush(&mut self) -> Result<(), Error> {
728        Ok(())
729    }
730
731    async fn read(&mut self, words: &mut [u8]) -> Result<(), Error> {
732        self.read(words).await
733    }
734
735    async fn write(&mut self, data: &[u8]) -> Result<(), Error> {
736        self.write(data).await
737    }
738
739    async fn transfer(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(), Error> {
740        self.transfer(rx, tx).await
741    }
742
743    async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Error> {
744        self.transfer_in_place(words).await
745    }
746}
747
748impl<'d> SetConfig for Spim<'d> {
749    type Config = Config;
750    type ConfigError = ();
751    fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
752        let r = self.r;
753        // Configure mode.
754        let mode = config.mode;
755        r.config().write(|w| {
756            w.set_order(config.bit_order);
757            match mode {
758                MODE_0 => {
759                    w.set_cpol(vals::Cpol::ACTIVE_HIGH);
760                    w.set_cpha(vals::Cpha::LEADING);
761                }
762                MODE_1 => {
763                    w.set_cpol(vals::Cpol::ACTIVE_HIGH);
764                    w.set_cpha(vals::Cpha::TRAILING);
765                }
766                MODE_2 => {
767                    w.set_cpol(vals::Cpol::ACTIVE_LOW);
768                    w.set_cpha(vals::Cpha::LEADING);
769                }
770                MODE_3 => {
771                    w.set_cpol(vals::Cpol::ACTIVE_LOW);
772                    w.set_cpha(vals::Cpha::TRAILING);
773                }
774            }
775        });
776
777        // Configure frequency.
778        let frequency = config.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        }
785
786        // Set over-read character
787        let orc = config.orc;
788        r.orc().write(|w| w.set_orc(orc));
789
790        Ok(())
791    }
792}