Skip to main content

ra_hal/
spi.rs

1#![allow(missing_docs)]
2
3//! Serial Peripheral Interface (`SPI`).
4//!
5//! # TODO
6//! * Error handling
7//! * Implement `embedded-hal` traits (0.2 and 1.0)
8//! * Subnode mode
9//! * Hardware support for multiple chip select lines
10//! * Confirm DMAC transfers actually work at 24 MHz.
11
12use core::{future::poll_fn, marker::PhantomData, ops::RangeInclusive, task::Poll};
13
14use embassy_futures::join::join;
15use embassy_hal_internal::{Peri, PeripheralType, interrupt::InterruptExt as _};
16use embassy_sync::waitqueue::AtomicWaker;
17use embedded_hal_1::spi::{ErrorType, MODE_0, Mode};
18
19#[cfg(dmac)]
20use crate::dmac::{Channel as DmacChannel, DmacInterruptHandler};
21#[cfg(dtc)]
22use crate::dtc::{Channel as DtcChannel, DtcInterruptHandler, Instance as DtcInstance};
23use crate::{
24    event_link::IcuInterrupt as _,
25    gpio::{Basic, Flex, Pin, PortFunction},
26    interrupt::{
27        self,
28        typelevel::{Handler as InterruptHandler, Interrupt as InterruptType},
29    },
30    module_stop::ModuleStop,
31    pac::{
32        self,
33        spi::vals::{Brdv, Bysw, Cpha, Cpol, Lsbf, Moifv, Spb, Spbyt, Splw, Spms},
34    },
35};
36
37const VALID_CLOCK_DIVIDER: RangeInclusive<u32> = 2..=4096;
38
39pub struct ErrorInterruptHandler<I: Instance> {
40    _phantom: PhantomData<I>,
41}
42
43pub struct RxInterruptHandler<I: Instance> {
44    _phantom: PhantomData<I>,
45}
46
47pub struct TeInterruptHandler<I: Instance> {
48    _phantom: PhantomData<I>,
49}
50
51pub struct TxInterruptHandler<I: Instance> {
52    _phantom: PhantomData<I>,
53}
54
55impl<I: Instance, ErrInt: InterruptType> InterruptHandler<ErrInt> for ErrorInterruptHandler<I> {
56    unsafe fn on_interrupt() {
57        error!("{}ErrInt", I::PERIPHERAL);
58    }
59}
60
61impl<I: Instance, RxInt: InterruptType> InterruptHandler<RxInt> for RxInterruptHandler<I> {
62    unsafe fn on_interrupt() {
63        trace!("{}RxInt", I::PERIPHERAL);
64        RxInt::IRQ.icu_unpend();
65        I::rx_waker().wake();
66    }
67}
68
69impl<I: Instance, TeInt: InterruptType> InterruptHandler<TeInt> for TeInterruptHandler<I> {
70    unsafe fn on_interrupt() {
71        trace!("{}TeInt", I::PERIPHERAL);
72        TeInt::IRQ.icu_unpend();
73        I::te_waker().wake();
74    }
75}
76
77impl<I: Instance, TxInt: InterruptType> InterruptHandler<TxInt> for TxInterruptHandler<I> {
78    unsafe fn on_interrupt() {
79        trace!("{}TxInt", I::PERIPHERAL);
80        TxInt::IRQ.icu_unpend();
81        I::tx_waker().wake();
82    }
83}
84
85#[derive(Debug)]
86#[cfg_attr(feature = "defmt", derive(defmt::Format))]
87struct ClockConfig {
88    pub rate: u32,
89    pub error: u32,
90    pub spbr: u8,
91    pub brdv: u8,
92}
93
94#[allow(private_bounds)]
95pub trait TransferMode: SealedTransferMode {}
96trait SealedTransferMode {}
97
98#[cfg(dmac)]
99pub struct Dma<'d> {
100    rx_dma: DmacChannel<'d>,
101    tx_dma: DmacChannel<'d>,
102}
103
104#[cfg(dtc)]
105pub struct Dtc<D1: DtcInstance, D2: DtcInstance> {
106    rx_dtc: DtcChannel<D1>,
107    tx_dtc: DtcChannel<D2>,
108}
109
110pub struct Blocking {}
111
112/// SPI driver for the `SPI` peripheral.
113#[allow(private_bounds)]
114pub struct Spi<'d, I: Instance, W: Word, M: TransferMode> {
115    _instance: PhantomData<&'d I>,
116    _miso: Flex<'d, Basic>,
117    _mosi: Flex<'d, Basic>,
118    _sck: Flex<'d, Basic>,
119    _cs: Option<Flex<'d, Basic>>,
120    _word: PhantomData<W>,
121    bit_order: BitOrder,
122    io_mode: M,
123}
124
125/// Whether the `CS` line is low or high when a subnode is selected.
126///
127/// Only applicable when the `SPI` peripheral is controlling the `CS` line.
128/// Leave this at the default `ActiveLow` for most use cases.
129#[cfg_attr(feature = "defmt", derive(defmt::Format))]
130#[derive(Copy, Clone, PartialEq)]
131pub enum ChipSelectPolarity {
132    /// `CS` line is driven high for the selected subnode device.
133    ActiveHigh,
134
135    /// `CS` line is driven low for the selected subnode device.
136    ActiveLow,
137}
138
139/// Order in which the bits are sent out over the wire.
140///
141/// # Notes
142/// If `LsbFirst` is selected the bits are reversed upon reception.
143#[cfg_attr(feature = "defmt", derive(defmt::Format))]
144#[derive(Copy, Clone, PartialEq)]
145pub enum BitOrder {
146    #[allow(missing_docs)]
147    Lsb0,
148    #[allow(missing_docs)]
149    Msb0,
150}
151
152#[cfg_attr(feature = "defmt", derive(defmt::Format))]
153#[derive(Copy, Clone, PartialEq)]
154pub enum Endian {
155    #[allow(missing_docs)]
156    Big,
157    #[allow(missing_docs)]
158    Little,
159}
160
161#[cfg_attr(feature = "defmt", derive(defmt::Format))]
162#[derive(Copy, Clone, PartialEq)]
163/// `MOSI` pin state at idle
164pub enum MosiIdle {
165    /// `MOSI` remains at last value
166    Last,
167
168    /// `MOSI` is set low when bus is idle
169    Low,
170
171    /// `MOSI` is set high when bus is idle
172    High,
173}
174
175/// SPI configuration.
176#[non_exhaustive]
177#[derive(Copy, Clone)]
178pub struct Config {
179    #[allow(missing_docs)]
180    pub bit_order: BitOrder,
181
182    #[allow(missing_docs)]
183    pub endian: Endian,
184
185    /// SPI mode.
186    pub mode: Mode,
187
188    /// SPI bit rate in bits per second.
189    pub bit_rate: u32,
190
191    #[allow(missing_docs)]
192    pub cs_polarity: ChipSelectPolarity,
193
194    #[allow(missing_docs)]
195    pub mosi_idle: MosiIdle,
196}
197
198/// Trait that defines the size of an SPI "word".
199///
200/// Currently 8-, 16-, and 32- bit words are supported as they cleanly map to `u8`, `u16`, and `u32` types respectively.
201/// The `RA4M1` supports a variety of intermediate word sizes but that's an implementation detail for another day.
202#[allow(private_bounds)]
203#[cfg(feature = "defmt")]
204pub trait Word: SealedWord + Copy + defmt::Format {}
205
206/// Trait that defines the size of a "word".
207///
208/// Currently 8-, 16-, and 32- bit words are supported as they cleanly map to `u8`, `u16`, and `u32` types respectively.
209/// The `RA4M1` supports a variety of intermediate word sizes but that's an implementation detail for another day.
210#[allow(private_bounds)]
211#[cfg(not(feature = "defmt"))]
212pub trait Word: SealedWord + Copy {}
213
214pub(crate) trait SealedWord {
215    const BYTE_ACCESS: Spbyt;
216    const WORD_LENGTH: Splw;
217    const BIT_LENGTH: Spb;
218
219    fn read(peri: &mut crate::pac::spi::Spi, bit_order: BitOrder) -> Self;
220    fn write(peri: &mut crate::pac::spi::Spi, word: Self, bit_order: BitOrder);
221}
222
223impl Word for u8 {}
224impl SealedWord for u8 {
225    const BYTE_ACCESS: Spbyt = Spbyt::Byte;
226    const WORD_LENGTH: Splw = Splw::HalfWord;
227    const BIT_LENGTH: Spb = Spb::_8bits;
228
229    #[inline(always)]
230    fn read(peri: &mut crate::pac::spi::Spi, bit_order: BitOrder) -> Self {
231        let by = peri.spdr_by().read();
232        if bit_order == BitOrder::Lsb0 {
233            by.reverse_bits()
234        } else {
235            by
236        }
237    }
238
239    #[inline(always)]
240    fn write(peri: &mut crate::pac::spi::Spi, word: Self, bit_order: BitOrder) {
241        if bit_order == BitOrder::Lsb0 {
242            peri.spdr_by().write_value(word.reverse_bits());
243        } else {
244            peri.spdr_by().write_value(word);
245        }
246    }
247}
248
249impl Word for u16 {}
250impl SealedWord for u16 {
251    const BYTE_ACCESS: Spbyt = Spbyt::Word;
252    const WORD_LENGTH: Splw = Splw::HalfWord;
253    const BIT_LENGTH: Spb = Spb::_16bits;
254
255    #[inline(always)]
256    fn read(peri: &mut crate::pac::spi::Spi, bit_order: BitOrder) -> Self {
257        let ha = peri.spdr_ha().read();
258        if bit_order == BitOrder::Lsb0 {
259            ha.reverse_bits()
260        } else {
261            ha
262        }
263    }
264
265    #[inline(always)]
266    fn write(peri: &mut crate::pac::spi::Spi, word: Self, bit_order: BitOrder) {
267        if bit_order == BitOrder::Lsb0 {
268            let word = ((word & 0x00FF) as u8).reverse_bits() as u16
269                | ((((word & 0xFF00) >> 8) as u8).reverse_bits() as u16) << 8;
270            peri.spdr_ha().write_value(word);
271        } else {
272            peri.spdr().write_value(word as u32);
273        }
274    }
275}
276
277impl Word for u32 {}
278impl SealedWord for u32 {
279    const BYTE_ACCESS: Spbyt = Spbyt::Word;
280    const WORD_LENGTH: Splw = Splw::Word;
281    const BIT_LENGTH: Spb = Spb::_32bits;
282
283    #[inline(always)]
284    fn read(peri: &mut crate::pac::spi::Spi, bit_order: BitOrder) -> Self {
285        let word = peri.spdr().read();
286        if bit_order == BitOrder::Lsb0 {
287            word.reverse_bits()
288        } else {
289            word
290        }
291    }
292
293    #[inline(always)]
294    fn write(peri: &mut crate::pac::spi::Spi, word: Self, bit_order: BitOrder) {
295        if bit_order == BitOrder::Lsb0 {
296            peri.spdr().write_value(word.reverse_bits());
297        } else {
298            peri.spdr().write_value(word);
299        }
300    }
301}
302
303/// [`Spi`] driver instance.
304#[allow(private_bounds)]
305pub trait Instance: SealedInstance + ModuleStop + PeripheralType + 'static + Send {
306    const RX_EVENT: crate::event_link::InterruptEvent;
307    const TX_EVENT: crate::event_link::InterruptEvent;
308    const TE_EVENT: crate::event_link::InterruptEvent;
309    const ERROR_EVENT: crate::event_link::InterruptEvent;
310
311    /// Waker for transmit buffer empty events.
312    fn tx_waker() -> &'static AtomicWaker;
313    fn te_waker() -> &'static AtomicWaker;
314    fn rx_waker() -> &'static AtomicWaker;
315}
316
317pub(crate) trait SealedInstance {
318    #[cfg(feature = "defmt")]
319    const PERIPHERAL: &'static str;
320    #[cfg(not(feature = "defmt"))]
321    const PERIPHERAL: () = ();
322
323    fn regs() -> pac::spi::Spi;
324}
325
326/// GPIO pin connected to the `MISO` line of an [`Spi`] instance.
327#[allow(private_bounds)]
328pub trait MisoPin<I: Instance>: SealedMisoPin<I> {}
329
330pub(crate) trait SealedMisoPin<I: SealedInstance>: Pin + PeripheralType {
331    const PERIPHERAL_FUNC: PortFunction;
332
333    #[inline(always)]
334    fn set_pfunc(&self) {
335        self.set_as_pf(Self::PERIPHERAL_FUNC);
336    }
337}
338
339/// GPIO pin connected to the `MOSI` line of an [`Spi`] instance.
340#[allow(private_bounds)]
341pub trait MosiPin<I: Instance>: SealedMosiPin<I> {}
342
343pub(crate) trait SealedMosiPin<I: SealedInstance>: Pin + PeripheralType {
344    const PERIPHERAL_FUNC: PortFunction;
345
346    #[inline(always)]
347    fn set_pfunc(&self) {
348        self.set_as_pf(Self::PERIPHERAL_FUNC);
349    }
350}
351
352/// GPIO pin connected to the `SCK` line of an [`Spi`] instance.
353#[allow(private_bounds)]
354pub trait SckPin<I: Instance>: SealedSckPin<I> {}
355
356pub(crate) trait SealedSckPin<I: SealedInstance>: Pin + PeripheralType {
357    const PERIPHERAL_FUNC: PortFunction;
358
359    #[inline(always)]
360    fn set_pfunc(&self) {
361        self.set_as_pf(Self::PERIPHERAL_FUNC);
362    }
363}
364
365/// GPIO pin connected to the `SS0` line of an [`Spi`] instance.
366#[allow(private_bounds)]
367pub trait CsPin<I: Instance>: SealedCsPin<I> {}
368
369pub(crate) trait SealedCsPin<I: SealedInstance>: Pin + PeripheralType {
370    const PERIPHERAL_FUNC: PortFunction;
371
372    #[inline(always)]
373    fn set_pfunc(&self) {
374        self.set_as_pf(Self::PERIPHERAL_FUNC);
375    }
376}
377
378macro_rules! miso_pin {
379    ($instance:ident, $pin:ident, $pfunc:ident) => {
380        impl crate::spi::MisoPin<crate::peripherals::$instance> for crate::peripherals::$pin {}
381        impl crate::spi::SealedMisoPin<crate::peripherals::$instance> for crate::peripherals::$pin {
382            const PERIPHERAL_FUNC: crate::gpio::PortFunction = crate::gpio::PortFunction::$pfunc;
383        }
384    };
385}
386pub(crate) use miso_pin;
387
388macro_rules! mosi_pin {
389    ($instance:ident, $pin:ident, $pfunc:ident) => {
390        impl crate::spi::MosiPin<crate::peripherals::$instance> for crate::peripherals::$pin {}
391        impl crate::spi::SealedMosiPin<crate::peripherals::$instance> for crate::peripherals::$pin {
392            const PERIPHERAL_FUNC: crate::gpio::PortFunction = crate::gpio::PortFunction::$pfunc;
393        }
394    };
395}
396pub(crate) use mosi_pin;
397
398macro_rules! sck_pin {
399    ($instance:ident, $pin:ident, $pfunc:ident) => {
400        impl crate::spi::SckPin<crate::peripherals::$instance> for crate::peripherals::$pin {}
401        impl crate::spi::SealedSckPin<crate::peripherals::$instance> for crate::peripherals::$pin {
402            const PERIPHERAL_FUNC: crate::gpio::PortFunction = crate::gpio::PortFunction::$pfunc;
403        }
404    };
405}
406pub(crate) use sck_pin;
407
408macro_rules! cs_pin {
409    ($instance:ident, $pin:ident, $pfunc:ident) => {
410        impl crate::spi::CsPin<crate::peripherals::$instance> for crate::peripherals::$pin {}
411        impl crate::spi::SealedCsPin<crate::peripherals::$instance> for crate::peripherals::$pin {
412            const PERIPHERAL_FUNC: crate::gpio::PortFunction = crate::gpio::PortFunction::$pfunc;
413        }
414    };
415}
416pub(crate) use cs_pin;
417
418macro_rules! instance_impl {
419    ($instance:ident, $error_int:ident, $te_int:ident, $tx_int:ident, $rx_int:ident) => {
420        paste::paste! {
421            impl Instance for crate::peripherals::$instance {
422                const RX_EVENT: crate::event_link::InterruptEvent = crate::event_link::InterruptEvent::$rx_int;
423                const TX_EVENT: crate::event_link::InterruptEvent = crate::event_link::InterruptEvent::$tx_int;
424                const TE_EVENT: crate::event_link::InterruptEvent = crate::event_link::InterruptEvent::$te_int;
425                const ERROR_EVENT: crate::event_link::InterruptEvent = crate::event_link::InterruptEvent::$error_int;
426
427                /// Waker for transmit buffer empty events.
428                #[inline(always)]
429                fn tx_waker() -> &'static AtomicWaker{
430                    static TX_WAKER: AtomicWaker = AtomicWaker::new();
431                    &TX_WAKER
432                }
433
434                /// Waker for transmit end events.
435                #[inline(always)]
436                fn te_waker() -> &'static AtomicWaker{
437                    static TE_WAKER: AtomicWaker = AtomicWaker::new();
438                    &TE_WAKER
439                }
440
441                #[inline(always)]
442                fn rx_waker() -> &'static AtomicWaker{
443                    static RX_WAKER: AtomicWaker = AtomicWaker::new();
444                    &RX_WAKER
445                }
446            }
447
448            impl SealedInstance for crate::peripherals::$instance {
449
450                #[cfg(feature = "defmt")]
451                const PERIPHERAL: &'static str = concat!(stringify!($instance), ": ");
452
453                #[inline(always)]
454                fn regs() -> crate::pac::spi::Spi {
455                    crate::pac::$instance
456                }
457            }
458        }
459    };
460}
461
462instance_impl!(SPI0, Spi0Eri, Spi0Tei, Spi0Txi, Spi0Rxi);
463instance_impl!(SPI1, Spi1Eri, Spi1Tei, Spi1Txi, Spi1Rxi);
464
465fn calc_dividers(rate: u32) -> Result<ClockConfig, ()> {
466    let clocks = crate::clock::clock_status();
467    let clk = clocks.peripheral_a;
468
469    let target = rate;
470
471    // TODO UHHH check this
472
473    let mut divider = (clk / target).to_MHz();
474
475    if !VALID_CLOCK_DIVIDER.contains(&divider) {
476        return Err(());
477    }
478
479    divider -= 1;
480
481    let mut options: [Option<(u32, u32, u32, u32)>; 4] = [None; 4];
482
483    for n in 0..=3 {
484        let spbr = divider / (2 << n);
485        let act = (clk / (2 * (spbr + 1) * (2_u32.pow(n)))).to_Hz();
486        let diff = target.abs_diff(act);
487        if spbr <= 255 {
488            options[n as usize] = Some((n, spbr, diff, act));
489        }
490    }
491
492    if !options.iter().any(|o| o.is_some()) {
493        return Err(());
494    }
495
496    let best = options[0].unwrap();
497
498    Ok(ClockConfig {
499        error: best.2,
500        spbr: best.1 as u8,
501        brdv: best.0 as u8,
502        rate,
503    })
504}
505
506impl TransferMode for Blocking {}
507impl SealedTransferMode for Blocking {}
508
509#[cfg(dmac)]
510impl<'d> TransferMode for Dma<'d> {}
511#[cfg(dmac)]
512impl<'d> SealedTransferMode for Dma<'d> {}
513
514#[cfg(dtc)]
515impl<Rx: DtcInstance, Tx: DtcInstance> TransferMode for Dtc<Rx, Tx> {}
516#[cfg(dtc)]
517impl<Rx: DtcInstance, Tx: DtcInstance> SealedTransferMode for Dtc<Rx, Tx> {}
518
519impl<'d, I: Instance, W: Word> Spi<'d, I, W, Blocking> {
520    /// Creates a new `Spi` instance with hardware control of the chip select line.
521    pub fn new_blocking(
522        spi: Peri<'d, I>,
523        sck: Peri<'d, impl SckPin<I>>,
524        mosi: Peri<'d, impl MosiPin<I>>,
525        miso: Peri<'d, impl MisoPin<I>>,
526        cs: Peri<'d, impl CsPin<I>>,
527        config: Config,
528    ) -> Self {
529        cs.set_pfunc();
530        Self::new_inner(
531            spi,
532            sck,
533            mosi,
534            miso,
535            Some(Flex::new(cs)),
536            config,
537            Blocking {},
538        )
539    }
540
541    /// Writes one or more words to the SPI bus.
542    ///
543    /// # Notes
544    /// Calls to this function should be wrapped with [`blocking_setup`](Self::blocking_setup) and [`blocking_shutdown`](Self::blocking_shutdown) as required, the `SpiBus` impl does this automatically.
545    #[inline(always)]
546    pub fn blocking_write(&mut self, bytes: &[W]) -> Result<(), SpiError> {
547        let mut spi = I::regs();
548
549        for byte in bytes.iter() {
550            while !spi.spsr().read().sptef() {}
551            W::write(&mut spi, *byte, self.bit_order);
552        }
553
554        Ok(())
555    }
556
557    /// Sets up the peripheral for a read/write/transfer operation.
558    pub fn blocking_setup(&mut self) {
559        let spi = I::regs();
560        spi.spcr2().write(|r| r.set_spiie(false));
561        spi.spcr().modify(|r| {
562            r.set_sptie(false);
563            r.set_sprie(false);
564            r.set_speie(false);
565            r.set_spe(true);
566        });
567    }
568
569    /// Disables the peripheral and related interrupts.
570    pub fn blocking_shutdown(&mut self) {
571        let spi = I::regs();
572
573        // Okay that last part was a lie but we're not enabling any interrupts.
574        spi.spcr().modify(|r| r.set_spe(false));
575    }
576
577    /// Performs a concurrent read and write.
578    ///
579    /// # Notes
580    /// Calls to this function should be wrapped with [`blocking_setup`](Self::blocking_setup) and [`blocking_shutdown`](Self::blocking_shutdown) as required, the `SpiBus` impl does this automatically.
581    pub fn blocking_transfer(&mut self, input: &mut [W], output: &[W]) -> Result<(), SpiError> {
582        #[cfg(feature = "strict-assert")]
583        assert_eq!(input.len(), output.len());
584
585        let mut spi = I::regs();
586
587        for (obyte, ibyte) in output.iter().zip(input.iter_mut()) {
588            while !spi.spsr().read().sptef() {}
589            W::write(&mut spi, *obyte, self.bit_order);
590
591            while !spi.spsr().read().sprf() {}
592            let word = W::read(&mut spi, self.bit_order);
593            *ibyte = word;
594
595            if spi.spsr().read().ovrf() {
596                return Err(SpiError::Overrun);
597            }
598        }
599
600        Ok(())
601    }
602
603    /// Reads one or more words from the SPI bus.
604    ///
605    /// # Notes
606    /// Calls to this function should be wrapped with [`blocking_setup`](Self::blocking_setup) and [`blocking_shutdown`](Self::blocking_shutdown) as required, the `SpiBus` impl does this automatically.
607    #[inline(always)]
608    pub fn blocking_read(&mut self, buf: &mut [W]) -> Result<(), SpiError> {
609        let mut spi = I::regs();
610
611        let mut ret = Ok(());
612
613        for byte in buf.iter_mut() {
614            while !spi.spsr().read().sprf() {}
615            let datum = W::read(&mut spi, self.bit_order);
616            *byte = datum;
617            if spi.spsr().read().ovrf() {
618                ret = Err(SpiError::Overrun);
619                break;
620            }
621        }
622
623        ret
624    }
625}
626
627#[cfg(dmac)]
628impl<'d, I: Instance, W: Word + crate::dmac::Word> Spi<'d, I, W, Dma<'d>> {
629    /// Creates a new `Spi` instance with hardware control of the chip select line.
630    #[allow(clippy::too_many_arguments)]
631    pub fn new_dma<
632        TeInt: InterruptType,
633        RxInt: InterruptType,
634        TxInt: InterruptType,
635        RxDmaInstance: crate::dmac::Instance,
636        TxDmaInstance: crate::dmac::Instance,
637    >(
638        spi: Peri<'d, I>,
639        sck: Peri<'d, impl SckPin<I>>,
640        mosi: Peri<'d, impl MosiPin<I>>,
641        miso: Peri<'d, impl MisoPin<I>>,
642        cs: Peri<'d, impl CsPin<I>>,
643        config: Config,
644        rx_dmac: Peri<'d, RxDmaInstance>,
645        tx_dmac: Peri<'d, TxDmaInstance>,
646        irqs: impl interrupt::typelevel::Binding<TeInt, TeInterruptHandler<I>>
647        + interrupt::typelevel::Binding<TxInt, DmacInterruptHandler<TxDmaInstance>>
648        + interrupt::typelevel::Binding<RxInt, DmacInterruptHandler<RxDmaInstance>>
649        + Clone
650        + 'd,
651    ) -> Self {
652        // Enable in NVIC and ICU
653        // Safety: Interrupt handlers are defined by the irqs argument and thus the interrupts are safe to enable.
654        unsafe {
655            TeInt::IRQ.enable();
656            TeInt::IRQ.icu_enable(I::TE_EVENT);
657        }
658
659        let rx_dma = DmacChannel::new(rx_dmac, irqs);
660        let tx_dma = DmacChannel::new(tx_dmac, irqs);
661        let dma = Dma { rx_dma, tx_dma };
662
663        cs.set_pfunc();
664        Self::new_inner(spi, sck, mosi, miso, Some(Flex::new(cs)), config, dma)
665    }
666
667    pub async fn dma_write(&mut self, words: &[W]) -> Result<(), SpiError> {
668        let spi = I::regs();
669
670        spi.spcr().modify(|r| {
671            r.set_sptie(true);
672            r.set_sprie(false);
673            r.set_speie(false);
674        });
675        spi.spcr2().modify(|r| r.set_spiie(false));
676
677        let tx = self
678            .io_mode
679            .tx_dma
680            .write::<W>(words, spi.spdr().as_ptr() as *mut _, I::TX_EVENT);
681
682        spi.spcr().modify(|r| r.set_spe(true));
683
684        tx.await;
685
686        spi.spcr2().modify(|r| r.set_spiie(true));
687        poll_fn(|ctx| {
688            I::te_waker().register(ctx.waker());
689            if spi.spsr().read().sptef() {
690                Poll::Ready(())
691            } else {
692                Poll::Pending
693            }
694        })
695        .await;
696
697        spi.spcr().modify(|r| {
698            r.set_sptie(false);
699            r.set_spe(false);
700        });
701        spi.spcr2().modify(|r| r.set_spiie(false));
702
703        Ok(())
704    }
705
706    pub async fn dma_transfer(&mut self, input: &mut [W], output: &[W]) -> Result<(), SpiError> {
707        #[cfg(feature = "strict-assert")]
708        assert_eq!(input.len(), output.len());
709
710        let spi = I::regs();
711
712        spi.spcr().modify(|r| {
713            r.set_sptie(true);
714            r.set_sprie(true);
715            r.set_speie(false);
716        });
717        spi.spcr2().modify(|r| r.set_spiie(false));
718
719        let tx = self
720            .io_mode
721            .tx_dma
722            .write::<W>(output, spi.spdr().as_ptr() as *mut _, I::TX_EVENT);
723        let rx = self
724            .io_mode
725            .rx_dma
726            .read::<W>(spi.spdr().as_ptr() as *const _, input, I::RX_EVENT);
727
728        spi.spcr().modify(|r| r.set_spe(true));
729
730        join(tx, rx).await;
731
732        spi.spcr2().modify(|r| r.set_spiie(true));
733        poll_fn(|ctx| {
734            I::te_waker().register(ctx.waker());
735            if spi.spsr().read().sptef() {
736                Poll::Ready(())
737            } else {
738                Poll::Pending
739            }
740        })
741        .await;
742
743        spi.spcr().modify(|r| {
744            r.set_sptie(false);
745            r.set_sprie(false);
746            r.set_speie(false);
747            r.set_spe(false);
748        });
749        spi.spcr2().modify(|r| r.set_spiie(false));
750
751        spi.spcr().modify(|r| r.set_spe(false));
752
753        Ok(())
754    }
755}
756
757#[cfg(dtc)]
758impl<'d, I: Instance, W: Word + crate::dtc::Word, Rx: DtcInstance, Tx: DtcInstance>
759    Spi<'d, I, W, Dtc<Rx, Tx>>
760{
761    #[allow(clippy::too_many_arguments)]
762    pub fn new_dtc<TeInt: InterruptType>(
763        spi: Peri<'d, I>,
764        sck: Peri<'d, impl SckPin<I>>,
765        mosi: Peri<'d, impl MosiPin<I>>,
766        miso: Peri<'d, impl MisoPin<I>>,
767        cs: Peri<'d, impl CsPin<I>>,
768        config: Config,
769        rx_dtc: Peri<'d, Rx>,
770        tx_dtc: Peri<'d, Tx>,
771        irqs: impl interrupt::typelevel::Binding<TeInt, TeInterruptHandler<I>>
772        + interrupt::typelevel::Binding<Rx::Int, DtcInterruptHandler<Rx>>
773        + interrupt::typelevel::Binding<Tx::Int, DtcInterruptHandler<Tx>>
774        + Clone
775        + 'd,
776    ) -> Self {
777        // Safety: Interrupt handlers are defined by the irqs argument and thus the interrupts are safe to enable.
778        unsafe {
779            // Enable in NVIC and ICU
780            TeInt::IRQ.enable();
781            TeInt::IRQ.icu_enable(I::TE_EVENT);
782        };
783
784        let rx_dtc = DtcChannel::new(rx_dtc, irqs);
785        let tx_dtc = DtcChannel::new(tx_dtc, irqs);
786        let dtc = Dtc { rx_dtc, tx_dtc };
787
788        cs.set_pfunc();
789        Self::new_inner(spi, sck, mosi, miso, Some(Flex::new(cs)), config, dtc)
790    }
791
792    pub async fn dtc_write(&mut self, words: &[W]) -> Result<(), SpiError> {
793        let spi = I::regs();
794
795        spi.spcr().modify(|r| {
796            r.set_sptie(true);
797            r.set_sprie(false);
798            r.set_speie(false);
799        });
800        spi.spcr2().modify(|r| r.set_spiie(false));
801
802        let tx = unsafe {
803            self.io_mode
804                .tx_dtc
805                .write(words, spi.spdr().as_ptr() as *mut _, I::TX_EVENT, false)
806        };
807
808        spi.spcr().modify(|r| r.set_spe(true));
809
810        tx.await.or(Err(SpiError::Dma))?;
811
812        spi.spcr2().modify(|r| r.set_spiie(true));
813        poll_fn(|ctx| {
814            I::te_waker().register(ctx.waker());
815            if spi.spsr().read().sptef() {
816                Poll::Ready(())
817            } else {
818                Poll::Pending
819            }
820        })
821        .await;
822
823        spi.spcr().modify(|r| {
824            r.set_sptie(false);
825            r.set_spe(false);
826        });
827        spi.spcr2().modify(|r| r.set_spiie(false));
828
829        Ok(())
830    }
831
832    pub async fn dtc_transfer(&mut self, input: &mut [W], output: &[W]) -> Result<(), SpiError> {
833        #[cfg(feature = "strict-assert")]
834        assert_eq!(input.len(), output.len());
835
836        let spi = I::regs();
837
838        spi.spcr().modify(|r| {
839            r.set_sptie(true);
840            r.set_sprie(true);
841            r.set_speie(false);
842        });
843        spi.spcr2().modify(|r| r.set_spiie(false));
844
845        let tx = unsafe {
846            self.io_mode
847                .tx_dtc
848                .write(output, spi.spdr().as_ptr() as *mut _, I::TX_EVENT, false)
849        };
850        let rx = unsafe {
851            self.io_mode
852                .rx_dtc
853                .read(spi.spdr().as_ptr() as *mut _, input, I::RX_EVENT, false)
854        };
855
856        spi.spcr().modify(|r| r.set_spe(true));
857
858        let (tx_result, rx_result) = join(tx, rx).await;
859        tx_result.or(Err(SpiError::Dma))?;
860        rx_result.or(Err(SpiError::Dma))?;
861
862        spi.spcr2().modify(|r| r.set_spiie(true));
863        poll_fn(|ctx| {
864            I::te_waker().register(ctx.waker());
865            if spi.spsr().read().sptef() {
866                Poll::Ready(())
867            } else {
868                Poll::Pending
869            }
870        })
871        .await;
872
873        spi.spcr().modify(|r| {
874            r.set_sptie(false);
875            r.set_sprie(false);
876            r.set_speie(false);
877            r.set_spe(false);
878        });
879        spi.spcr2().modify(|r| r.set_spiie(false));
880
881        spi.spcr().modify(|r| r.set_spe(false));
882
883        Ok(())
884    }
885}
886
887impl<'d, I: Instance, W: Word, M: TransferMode> Spi<'d, I, W, M> {
888    fn new_inner(
889        spi: Peri<'d, I>,
890        sck: Peri<'d, impl SckPin<I>>,
891        mosi: Peri<'d, impl MosiPin<I>>,
892        miso: Peri<'d, impl MisoPin<I>>,
893        cs: Option<Flex<'d, Basic>>,
894        config: Config,
895        io_mode: M,
896    ) -> Self {
897        let _ = spi;
898
899        I::start_module();
900
901        sck.set_pfunc();
902        mosi.set_pfunc();
903        miso.set_pfunc();
904
905        let spi = I::regs();
906
907        spi.spcr().modify(|r| r.set_spe(false));
908
909        spi.spcr().modify(|r| {
910            r.set_txmd(false);
911            r.set_mstr(true);
912            r.set_modfen(false);
913            r.set_spms(Spms::Spi);
914        });
915
916        let polarity = match config.mode.polarity {
917            embedded_hal_1::spi::Polarity::IdleLow => Cpol::Low,
918            embedded_hal_1::spi::Polarity::IdleHigh => Cpol::High,
919        };
920
921        let phase = match config.mode.phase {
922            embedded_hal_1::spi::Phase::CaptureOnFirstTransition => Cpha::SampleShift,
923            embedded_hal_1::spi::Phase::CaptureOnSecondTransition => Cpha::ShiftSample,
924        };
925
926        let bit_order = match config.bit_order {
927            BitOrder::Lsb0 => Lsbf::Lsb0,
928            BitOrder::Msb0 => Lsbf::Msb0,
929        };
930
931        let endian = match config.endian {
932            Endian::Big => Bysw::Big,
933            Endian::Little => Bysw::Little,
934        };
935
936        let (moifv, moife) = match config.mosi_idle {
937            MosiIdle::Last => (Moifv::Low, true),
938            MosiIdle::Low => (Moifv::Low, false),
939            MosiIdle::High => (Moifv::High, false),
940        };
941
942        debug!(
943            "{}polarity={}, phase={}, bit_order={}, endian={}",
944            I::PERIPHERAL,
945            polarity,
946            phase,
947            bit_order,
948            endian,
949        );
950
951        spi.spcmd0().modify(|r| {
952            r.set_cpol(polarity);
953            r.set_cpha(phase);
954            r.set_lsbf(bit_order);
955        });
956
957        // We can get away with write because we're not enabling loopback
958        spi.sppcr().write(|r| {
959            r.set_moifv(moifv);
960            r.set_moife(moife);
961        });
962
963        // At 48 MHz:
964        //   The slowest clock is about 12 kHz
965        //   The fastest clock is about 24 MHz
966        let dividers = calc_dividers(config.bit_rate).unwrap();
967        debug!("{}{}", I::PERIPHERAL, dividers);
968        let spbr = dividers.spbr;
969        let brdv = Brdv::from_bits(dividers.brdv);
970
971        spi.spbr().write_value(spbr);
972        spi.spdcr().modify(|r| r.set_spbyt(W::BYTE_ACCESS));
973        spi.spdcr2().modify(|r| r.set_bysw(endian));
974        spi.spdcr().modify(|r| r.set_splw(W::WORD_LENGTH));
975        spi.spcmd0().modify(|r| {
976            r.set_brdv(brdv);
977            r.set_spb(W::BIT_LENGTH);
978        });
979
980        Self {
981            _instance: PhantomData,
982            _cs: cs,
983            _miso: Flex::new(miso),
984            _mosi: Flex::new(mosi),
985            _sck: Flex::new(sck),
986            _word: PhantomData,
987            bit_order: config.bit_order,
988            io_mode,
989        }
990    }
991}
992
993impl<'d, I: Instance, W: Word, M: TransferMode> Drop for Spi<'d, I, W, M> {
994    fn drop(&mut self) {
995        I::stop_module();
996    }
997}
998
999impl Default for Config {
1000    fn default() -> Self {
1001        Self {
1002            bit_order: BitOrder::Msb0,
1003            mode: MODE_0,
1004            bit_rate: 1_000_000,
1005            cs_polarity: ChipSelectPolarity::ActiveLow,
1006            endian: Endian::Big,
1007            mosi_idle: MosiIdle::High,
1008        }
1009    }
1010}
1011
1012/// SPI error.
1013#[derive(Debug, PartialEq, Eq, Copy, Clone)]
1014#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1015pub enum SpiError {
1016    Dma,
1017    Overrun,
1018    Unknown,
1019}
1020
1021impl core::fmt::Display for SpiError {
1022    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1023        match self {
1024            SpiError::Dma => write!(f, "DMAC/DTC"),
1025            SpiError::Overrun => write!(f, "Overrun"),
1026            SpiError::Unknown => write!(f, "Unknown"),
1027        }
1028    }
1029}
1030
1031impl core::error::Error for SpiError {}
1032
1033impl embedded_hal_1::spi::Error for SpiError {
1034    fn kind(&self) -> embedded_hal_1::spi::ErrorKind {
1035        match *self {
1036            SpiError::Dma => embedded_hal_1::spi::ErrorKind::Other,
1037            SpiError::Overrun => embedded_hal_1::spi::ErrorKind::Overrun,
1038            SpiError::Unknown => embedded_hal_1::spi::ErrorKind::Other,
1039        }
1040    }
1041}
1042
1043impl<'d, I: Instance, W: Word + 'static, M: TransferMode> ErrorType for Spi<'d, I, W, M> {
1044    type Error = SpiError;
1045}
1046
1047impl<'d, I: Instance, W: Word + 'static> embedded_hal_1::spi::SpiBus<W>
1048    for Spi<'d, I, W, Blocking>
1049{
1050    #[inline]
1051    fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
1052        self.blocking_setup();
1053        self.blocking_read(words)?;
1054        self.blocking_shutdown();
1055        Ok(())
1056    }
1057
1058    #[inline]
1059    fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
1060        self.blocking_setup();
1061        self.blocking_write(words)?;
1062        self.blocking_shutdown();
1063        Ok(())
1064    }
1065
1066    #[inline]
1067    fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error> {
1068        self.blocking_setup();
1069        self.blocking_transfer(read, write)?;
1070        self.blocking_shutdown();
1071        Ok(())
1072    }
1073
1074    fn transfer_in_place(&mut self, _words: &mut [W]) -> Result<(), Self::Error> {
1075        unimplemented!()
1076    }
1077
1078    fn flush(&mut self) -> Result<(), Self::Error> {
1079        Ok(())
1080    }
1081}
1082
1083#[cfg(dmac)]
1084impl<'d, I: Instance, W: Word + crate::dmac::Word + 'static> embedded_hal_async::spi::SpiBus<W>
1085    for Spi<'d, I, W, Dma<'d>>
1086{
1087    async fn read(&mut self, _words: &mut [W]) -> Result<(), Self::Error> {
1088        todo!()
1089    }
1090
1091    async fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
1092        self.dma_write(words).await
1093    }
1094
1095    async fn transfer(&mut self, input: &mut [W], output: &[W]) -> Result<(), Self::Error> {
1096        self.dma_transfer(input, output).await
1097    }
1098
1099    async fn transfer_in_place(&mut self, _words: &mut [W]) -> Result<(), Self::Error> {
1100        todo!()
1101    }
1102
1103    async fn flush(&mut self) -> Result<(), Self::Error> {
1104        Ok(())
1105    }
1106}