embassy_rp/
spi.rs

1//! Serial Peripheral Interface
2use core::marker::PhantomData;
3
4use embassy_embedded_hal::SetConfig;
5use embassy_futures::join::join;
6use embassy_hal_internal::{Peri, PeripheralType};
7pub use embedded_hal_02::spi::{Phase, Polarity};
8
9use crate::dma::{AnyChannel, Channel};
10use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin as _};
11use crate::{pac, peripherals};
12
13/// SPI errors.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16#[non_exhaustive]
17pub enum Error {
18    // No errors for now
19}
20
21/// SPI configuration.
22#[non_exhaustive]
23#[derive(Clone)]
24pub struct Config {
25    /// Frequency.
26    pub frequency: u32,
27    /// Phase.
28    pub phase: Phase,
29    /// Polarity.
30    pub polarity: Polarity,
31}
32
33impl Default for Config {
34    fn default() -> Self {
35        Self {
36            frequency: 1_000_000,
37            phase: Phase::CaptureOnFirstTransition,
38            polarity: Polarity::IdleLow,
39        }
40    }
41}
42
43/// SPI driver.
44pub struct Spi<'d, T: Instance, M: Mode> {
45    inner: Peri<'d, T>,
46    tx_dma: Option<Peri<'d, AnyChannel>>,
47    rx_dma: Option<Peri<'d, AnyChannel>>,
48    phantom: PhantomData<(&'d mut T, M)>,
49}
50
51fn div_roundup(a: u32, b: u32) -> u32 {
52    (a + b - 1) / b
53}
54
55fn calc_prescs(freq: u32) -> (u8, u8) {
56    let clk_peri = crate::clocks::clk_peri_freq();
57
58    // final SPI frequency: spi_freq = clk_peri / presc / postdiv
59    // presc must be in 2..=254, and must be even
60    // postdiv must be in 1..=256
61
62    // divide extra by 2, so we get rid of the "presc must be even" requirement
63    let ratio = div_roundup(clk_peri, freq * 2);
64    if ratio > 127 * 256 {
65        panic!("Requested too low SPI frequency");
66    }
67
68    let presc = div_roundup(ratio, 256);
69    let postdiv = if presc == 1 { ratio } else { div_roundup(ratio, presc) };
70
71    ((presc * 2) as u8, (postdiv - 1) as u8)
72}
73
74impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
75    fn new_inner(
76        inner: Peri<'d, T>,
77        clk: Option<Peri<'d, AnyPin>>,
78        mosi: Option<Peri<'d, AnyPin>>,
79        miso: Option<Peri<'d, AnyPin>>,
80        cs: Option<Peri<'d, AnyPin>>,
81        tx_dma: Option<Peri<'d, AnyChannel>>,
82        rx_dma: Option<Peri<'d, AnyChannel>>,
83        config: Config,
84    ) -> Self {
85        Self::apply_config(&inner, &config);
86
87        let p = inner.regs();
88
89        // Always enable DREQ signals -- harmless if DMA is not listening
90        p.dmacr().write(|reg| {
91            reg.set_rxdmae(true);
92            reg.set_txdmae(true);
93        });
94
95        // finally, enable.
96        p.cr1().write(|w| w.set_sse(true));
97
98        if let Some(pin) = &clk {
99            pin.gpio().ctrl().write(|w| w.set_funcsel(1));
100            pin.pad_ctrl().write(|w| {
101                #[cfg(feature = "_rp235x")]
102                w.set_iso(false);
103                w.set_schmitt(true);
104                w.set_slewfast(false);
105                w.set_ie(true);
106                w.set_od(false);
107                w.set_pue(false);
108                w.set_pde(false);
109            });
110        }
111        if let Some(pin) = &mosi {
112            pin.gpio().ctrl().write(|w| w.set_funcsel(1));
113            pin.pad_ctrl().write(|w| {
114                #[cfg(feature = "_rp235x")]
115                w.set_iso(false);
116                w.set_schmitt(true);
117                w.set_slewfast(false);
118                w.set_ie(true);
119                w.set_od(false);
120                w.set_pue(false);
121                w.set_pde(false);
122            });
123        }
124        if let Some(pin) = &miso {
125            pin.gpio().ctrl().write(|w| w.set_funcsel(1));
126            pin.pad_ctrl().write(|w| {
127                #[cfg(feature = "_rp235x")]
128                w.set_iso(false);
129                w.set_schmitt(true);
130                w.set_slewfast(false);
131                w.set_ie(true);
132                w.set_od(false);
133                w.set_pue(false);
134                w.set_pde(false);
135            });
136        }
137        if let Some(pin) = &cs {
138            pin.gpio().ctrl().write(|w| w.set_funcsel(1));
139            pin.pad_ctrl().write(|w| {
140                #[cfg(feature = "_rp235x")]
141                w.set_iso(false);
142                w.set_schmitt(true);
143                w.set_slewfast(false);
144                w.set_ie(true);
145                w.set_od(false);
146                w.set_pue(false);
147                w.set_pde(false);
148            });
149        }
150        Self {
151            inner,
152            tx_dma,
153            rx_dma,
154            phantom: PhantomData,
155        }
156    }
157
158    /// Private function to apply SPI configuration (phase, polarity, frequency) settings.
159    ///
160    /// Driver should be disabled before making changes and reenabled after the modifications
161    /// are applied.
162    fn apply_config(inner: &Peri<'d, T>, config: &Config) {
163        let p = inner.regs();
164        let (presc, postdiv) = calc_prescs(config.frequency);
165
166        p.cpsr().write(|w| w.set_cpsdvsr(presc));
167        p.cr0().write(|w| {
168            w.set_dss(0b0111); // 8bit
169            w.set_spo(config.polarity == Polarity::IdleHigh);
170            w.set_sph(config.phase == Phase::CaptureOnSecondTransition);
171            w.set_scr(postdiv);
172        });
173    }
174
175    /// Write data to SPI blocking execution until done.
176    pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> {
177        let p = self.inner.regs();
178        for &b in data {
179            while !p.sr().read().tnf() {}
180            p.dr().write(|w| w.set_data(b as _));
181            while !p.sr().read().rne() {}
182            let _ = p.dr().read();
183        }
184        self.flush()?;
185        Ok(())
186    }
187
188    /// Transfer data in place to SPI blocking execution until done.
189    pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> {
190        let p = self.inner.regs();
191        for b in data {
192            while !p.sr().read().tnf() {}
193            p.dr().write(|w| w.set_data(*b as _));
194            while !p.sr().read().rne() {}
195            *b = p.dr().read().data() as u8;
196        }
197        self.flush()?;
198        Ok(())
199    }
200
201    /// Read data from SPI blocking execution until done.
202    pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> {
203        let p = self.inner.regs();
204        for b in data {
205            while !p.sr().read().tnf() {}
206            p.dr().write(|w| w.set_data(0));
207            while !p.sr().read().rne() {}
208            *b = p.dr().read().data() as u8;
209        }
210        self.flush()?;
211        Ok(())
212    }
213
214    /// Transfer data to SPI blocking execution until done.
215    pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
216        let p = self.inner.regs();
217        let len = read.len().max(write.len());
218        for i in 0..len {
219            let wb = write.get(i).copied().unwrap_or(0);
220            while !p.sr().read().tnf() {}
221            p.dr().write(|w| w.set_data(wb as _));
222            while !p.sr().read().rne() {}
223            let rb = p.dr().read().data() as u8;
224            if let Some(r) = read.get_mut(i) {
225                *r = rb;
226            }
227        }
228        self.flush()?;
229        Ok(())
230    }
231
232    /// Block execution until SPI is done.
233    pub fn flush(&mut self) -> Result<(), Error> {
234        let p = self.inner.regs();
235        while p.sr().read().bsy() {}
236        Ok(())
237    }
238
239    /// Set SPI frequency.
240    pub fn set_frequency(&mut self, freq: u32) {
241        let (presc, postdiv) = calc_prescs(freq);
242        let p = self.inner.regs();
243        // disable
244        p.cr1().write(|w| w.set_sse(false));
245
246        // change stuff
247        p.cpsr().write(|w| w.set_cpsdvsr(presc));
248        p.cr0().modify(|w| {
249            w.set_scr(postdiv);
250        });
251
252        // enable
253        p.cr1().write(|w| w.set_sse(true));
254    }
255
256    /// Set SPI config.
257    pub fn set_config(&mut self, config: &Config) {
258        let p = self.inner.regs();
259
260        // disable
261        p.cr1().write(|w| w.set_sse(false));
262
263        // change stuff
264        Self::apply_config(&self.inner, config);
265
266        // enable
267        p.cr1().write(|w| w.set_sse(true));
268    }
269}
270
271impl<'d, T: Instance> Spi<'d, T, Blocking> {
272    /// Create an SPI driver in blocking mode.
273    pub fn new_blocking(
274        inner: Peri<'d, T>,
275        clk: Peri<'d, impl ClkPin<T> + 'd>,
276        mosi: Peri<'d, impl MosiPin<T> + 'd>,
277        miso: Peri<'d, impl MisoPin<T> + 'd>,
278        config: Config,
279    ) -> Self {
280        Self::new_inner(
281            inner,
282            Some(clk.into()),
283            Some(mosi.into()),
284            Some(miso.into()),
285            None,
286            None,
287            None,
288            config,
289        )
290    }
291
292    /// Create an SPI driver in blocking mode supporting writes only.
293    pub fn new_blocking_txonly(
294        inner: Peri<'d, T>,
295        clk: Peri<'d, impl ClkPin<T> + 'd>,
296        mosi: Peri<'d, impl MosiPin<T> + 'd>,
297        config: Config,
298    ) -> Self {
299        Self::new_inner(
300            inner,
301            Some(clk.into()),
302            Some(mosi.into()),
303            None,
304            None,
305            None,
306            None,
307            config,
308        )
309    }
310
311    /// Create an SPI driver in blocking mode supporting reads only.
312    pub fn new_blocking_rxonly(
313        inner: Peri<'d, T>,
314        clk: Peri<'d, impl ClkPin<T> + 'd>,
315        miso: Peri<'d, impl MisoPin<T> + 'd>,
316        config: Config,
317    ) -> Self {
318        Self::new_inner(
319            inner,
320            Some(clk.into()),
321            None,
322            Some(miso.into()),
323            None,
324            None,
325            None,
326            config,
327        )
328    }
329}
330
331impl<'d, T: Instance> Spi<'d, T, Async> {
332    /// Create an SPI driver in async mode supporting DMA operations.
333    pub fn new(
334        inner: Peri<'d, T>,
335        clk: Peri<'d, impl ClkPin<T> + 'd>,
336        mosi: Peri<'d, impl MosiPin<T> + 'd>,
337        miso: Peri<'d, impl MisoPin<T> + 'd>,
338        tx_dma: Peri<'d, impl Channel>,
339        rx_dma: Peri<'d, impl Channel>,
340        config: Config,
341    ) -> Self {
342        Self::new_inner(
343            inner,
344            Some(clk.into()),
345            Some(mosi.into()),
346            Some(miso.into()),
347            None,
348            Some(tx_dma.into()),
349            Some(rx_dma.into()),
350            config,
351        )
352    }
353
354    /// Create an SPI driver in async mode supporting DMA write operations only.
355    pub fn new_txonly(
356        inner: Peri<'d, T>,
357        clk: Peri<'d, impl ClkPin<T> + 'd>,
358        mosi: Peri<'d, impl MosiPin<T> + 'd>,
359        tx_dma: Peri<'d, impl Channel>,
360        config: Config,
361    ) -> Self {
362        Self::new_inner(
363            inner,
364            Some(clk.into()),
365            Some(mosi.into()),
366            None,
367            None,
368            Some(tx_dma.into()),
369            None,
370            config,
371        )
372    }
373
374    /// Create an SPI driver in async mode supporting DMA read operations only.
375    pub fn new_rxonly(
376        inner: Peri<'d, T>,
377        clk: Peri<'d, impl ClkPin<T> + 'd>,
378        miso: Peri<'d, impl MisoPin<T> + 'd>,
379        tx_dma: Peri<'d, impl Channel>,
380        rx_dma: Peri<'d, impl Channel>,
381        config: Config,
382    ) -> Self {
383        Self::new_inner(
384            inner,
385            Some(clk.into()),
386            None,
387            Some(miso.into()),
388            None,
389            Some(tx_dma.into()),
390            Some(rx_dma.into()),
391            config,
392        )
393    }
394
395    /// Write data to SPI using DMA.
396    pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
397        let tx_ch = self.tx_dma.as_mut().unwrap().reborrow();
398        let tx_transfer = unsafe {
399            // If we don't assign future to a variable, the data register pointer
400            // is held across an await and makes the future non-Send.
401            crate::dma::write(tx_ch, buffer, self.inner.regs().dr().as_ptr() as *mut _, T::TX_DREQ)
402        };
403        tx_transfer.await;
404
405        let p = self.inner.regs();
406        while p.sr().read().bsy() {}
407
408        // clear RX FIFO contents to prevent stale reads
409        while p.sr().read().rne() {
410            let _: u16 = p.dr().read().data();
411        }
412        // clear RX overrun interrupt
413        p.icr().write(|w| w.set_roric(true));
414
415        Ok(())
416    }
417
418    /// Read data from SPI using DMA.
419    pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
420        // Start RX first. Transfer starts when TX starts, if RX
421        // is not started yet we might lose bytes.
422        let rx_ch = self.rx_dma.as_mut().unwrap().reborrow();
423        let rx_transfer = unsafe {
424            // If we don't assign future to a variable, the data register pointer
425            // is held across an await and makes the future non-Send.
426            crate::dma::read(rx_ch, self.inner.regs().dr().as_ptr() as *const _, buffer, T::RX_DREQ)
427        };
428
429        let tx_ch = self.tx_dma.as_mut().unwrap().reborrow();
430        let tx_transfer = unsafe {
431            // If we don't assign future to a variable, the data register pointer
432            // is held across an await and makes the future non-Send.
433            crate::dma::write_repeated(
434                tx_ch,
435                self.inner.regs().dr().as_ptr() as *mut u8,
436                buffer.len(),
437                T::TX_DREQ,
438            )
439        };
440        join(tx_transfer, rx_transfer).await;
441        Ok(())
442    }
443
444    /// Transfer data to SPI using DMA.
445    pub async fn transfer(&mut self, rx_buffer: &mut [u8], tx_buffer: &[u8]) -> Result<(), Error> {
446        self.transfer_inner(rx_buffer, tx_buffer).await
447    }
448
449    /// Transfer data in place to SPI using DMA.
450    pub async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Error> {
451        self.transfer_inner(words, words).await
452    }
453
454    async fn transfer_inner(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
455        // Start RX first. Transfer starts when TX starts, if RX
456        // is not started yet we might lose bytes.
457        let rx_ch = self.rx_dma.as_mut().unwrap().reborrow();
458        let rx_transfer = unsafe {
459            // If we don't assign future to a variable, the data register pointer
460            // is held across an await and makes the future non-Send.
461            crate::dma::read(rx_ch, self.inner.regs().dr().as_ptr() as *const _, rx, T::RX_DREQ)
462        };
463
464        let mut tx_ch = self.tx_dma.as_mut().unwrap().reborrow();
465        // If we don't assign future to a variable, the data register pointer
466        // is held across an await and makes the future non-Send.
467        let tx_transfer = async {
468            let p = self.inner.regs();
469            unsafe {
470                crate::dma::write(tx_ch.reborrow(), tx, p.dr().as_ptr() as *mut _, T::TX_DREQ).await;
471
472                if rx.len() > tx.len() {
473                    let write_bytes_len = rx.len() - tx.len();
474                    // write dummy data
475                    // this will disable incrementation of the buffers
476                    crate::dma::write_repeated(tx_ch, p.dr().as_ptr() as *mut u8, write_bytes_len, T::TX_DREQ).await
477                }
478            }
479        };
480        join(tx_transfer, rx_transfer).await;
481
482        // if tx > rx we should clear any overflow of the FIFO SPI buffer
483        if tx.len() > rx.len() {
484            let p = self.inner.regs();
485            while p.sr().read().bsy() {}
486
487            // clear RX FIFO contents to prevent stale reads
488            while p.sr().read().rne() {
489                let _: u16 = p.dr().read().data();
490            }
491            // clear RX overrun interrupt
492            p.icr().write(|w| w.set_roric(true));
493        }
494
495        Ok(())
496    }
497}
498
499trait SealedMode {}
500
501trait SealedInstance {
502    const TX_DREQ: pac::dma::vals::TreqSel;
503    const RX_DREQ: pac::dma::vals::TreqSel;
504
505    fn regs(&self) -> pac::spi::Spi;
506}
507
508/// Mode.
509#[allow(private_bounds)]
510pub trait Mode: SealedMode {}
511
512/// SPI instance trait.
513#[allow(private_bounds)]
514pub trait Instance: SealedInstance + PeripheralType {}
515
516macro_rules! impl_instance {
517    ($type:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => {
518        impl SealedInstance for peripherals::$type {
519            const TX_DREQ: pac::dma::vals::TreqSel = $tx_dreq;
520            const RX_DREQ: pac::dma::vals::TreqSel = $rx_dreq;
521
522            fn regs(&self) -> pac::spi::Spi {
523                pac::$type
524            }
525        }
526        impl Instance for peripherals::$type {}
527    };
528}
529
530impl_instance!(
531    SPI0,
532    Spi0,
533    pac::dma::vals::TreqSel::SPI0_TX,
534    pac::dma::vals::TreqSel::SPI0_RX
535);
536impl_instance!(
537    SPI1,
538    Spi1,
539    pac::dma::vals::TreqSel::SPI1_TX,
540    pac::dma::vals::TreqSel::SPI1_RX
541);
542
543/// CLK pin.
544pub trait ClkPin<T: Instance>: GpioPin {}
545/// CS pin.
546pub trait CsPin<T: Instance>: GpioPin {}
547/// MOSI pin.
548pub trait MosiPin<T: Instance>: GpioPin {}
549/// MISO pin.
550pub trait MisoPin<T: Instance>: GpioPin {}
551
552macro_rules! impl_pin {
553    ($pin:ident, $instance:ident, $function:ident) => {
554        impl $function<peripherals::$instance> for peripherals::$pin {}
555    };
556}
557
558impl_pin!(PIN_0, SPI0, MisoPin);
559impl_pin!(PIN_1, SPI0, CsPin);
560impl_pin!(PIN_2, SPI0, ClkPin);
561impl_pin!(PIN_3, SPI0, MosiPin);
562impl_pin!(PIN_4, SPI0, MisoPin);
563impl_pin!(PIN_5, SPI0, CsPin);
564impl_pin!(PIN_6, SPI0, ClkPin);
565impl_pin!(PIN_7, SPI0, MosiPin);
566impl_pin!(PIN_8, SPI1, MisoPin);
567impl_pin!(PIN_9, SPI1, CsPin);
568impl_pin!(PIN_10, SPI1, ClkPin);
569impl_pin!(PIN_11, SPI1, MosiPin);
570impl_pin!(PIN_12, SPI1, MisoPin);
571impl_pin!(PIN_13, SPI1, CsPin);
572impl_pin!(PIN_14, SPI1, ClkPin);
573impl_pin!(PIN_15, SPI1, MosiPin);
574impl_pin!(PIN_16, SPI0, MisoPin);
575impl_pin!(PIN_17, SPI0, CsPin);
576impl_pin!(PIN_18, SPI0, ClkPin);
577impl_pin!(PIN_19, SPI0, MosiPin);
578impl_pin!(PIN_20, SPI0, MisoPin);
579impl_pin!(PIN_21, SPI0, CsPin);
580impl_pin!(PIN_22, SPI0, ClkPin);
581impl_pin!(PIN_23, SPI0, MosiPin);
582impl_pin!(PIN_24, SPI1, MisoPin);
583impl_pin!(PIN_25, SPI1, CsPin);
584impl_pin!(PIN_26, SPI1, ClkPin);
585impl_pin!(PIN_27, SPI1, MosiPin);
586impl_pin!(PIN_28, SPI1, MisoPin);
587impl_pin!(PIN_29, SPI1, CsPin);
588#[cfg(feature = "rp235xb")]
589impl_pin!(PIN_30, SPI1, ClkPin);
590#[cfg(feature = "rp235xb")]
591impl_pin!(PIN_31, SPI1, MosiPin);
592#[cfg(feature = "rp235xb")]
593impl_pin!(PIN_32, SPI0, MisoPin);
594#[cfg(feature = "rp235xb")]
595impl_pin!(PIN_33, SPI0, CsPin);
596#[cfg(feature = "rp235xb")]
597impl_pin!(PIN_34, SPI0, ClkPin);
598#[cfg(feature = "rp235xb")]
599impl_pin!(PIN_35, SPI0, MosiPin);
600#[cfg(feature = "rp235xb")]
601impl_pin!(PIN_36, SPI0, MisoPin);
602#[cfg(feature = "rp235xb")]
603impl_pin!(PIN_37, SPI0, CsPin);
604#[cfg(feature = "rp235xb")]
605impl_pin!(PIN_38, SPI0, ClkPin);
606#[cfg(feature = "rp235xb")]
607impl_pin!(PIN_39, SPI0, MosiPin);
608#[cfg(feature = "rp235xb")]
609impl_pin!(PIN_40, SPI1, MisoPin);
610#[cfg(feature = "rp235xb")]
611impl_pin!(PIN_41, SPI1, CsPin);
612#[cfg(feature = "rp235xb")]
613impl_pin!(PIN_42, SPI1, ClkPin);
614#[cfg(feature = "rp235xb")]
615impl_pin!(PIN_43, SPI1, MosiPin);
616#[cfg(feature = "rp235xb")]
617impl_pin!(PIN_44, SPI1, MisoPin);
618#[cfg(feature = "rp235xb")]
619impl_pin!(PIN_45, SPI1, CsPin);
620#[cfg(feature = "rp235xb")]
621impl_pin!(PIN_46, SPI1, ClkPin);
622#[cfg(feature = "rp235xb")]
623impl_pin!(PIN_47, SPI1, MosiPin);
624
625macro_rules! impl_mode {
626    ($name:ident) => {
627        impl SealedMode for $name {}
628        impl Mode for $name {}
629    };
630}
631
632/// Blocking mode.
633pub struct Blocking;
634/// Async mode.
635pub struct Async;
636
637impl_mode!(Blocking);
638impl_mode!(Async);
639
640// ====================
641
642impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::spi::Transfer<u8> for Spi<'d, T, M> {
643    type Error = Error;
644    fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
645        self.blocking_transfer_in_place(words)?;
646        Ok(words)
647    }
648}
649
650impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::spi::Write<u8> for Spi<'d, T, M> {
651    type Error = Error;
652
653    fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
654        self.blocking_write(words)
655    }
656}
657
658impl embedded_hal_1::spi::Error for Error {
659    fn kind(&self) -> embedded_hal_1::spi::ErrorKind {
660        match *self {}
661    }
662}
663
664impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::ErrorType for Spi<'d, T, M> {
665    type Error = Error;
666}
667
668impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::SpiBus<u8> for Spi<'d, T, M> {
669    fn flush(&mut self) -> Result<(), Self::Error> {
670        Ok(())
671    }
672
673    fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
674        self.blocking_transfer(words, &[])
675    }
676
677    fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
678        self.blocking_write(words)
679    }
680
681    fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
682        self.blocking_transfer(read, write)
683    }
684
685    fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
686        self.blocking_transfer_in_place(words)
687    }
688}
689
690impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spi<'d, T, Async> {
691    async fn flush(&mut self) -> Result<(), Self::Error> {
692        Ok(())
693    }
694
695    async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
696        self.write(words).await
697    }
698
699    async fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
700        self.read(words).await
701    }
702
703    async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
704        self.transfer(read, write).await
705    }
706
707    async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
708        self.transfer_in_place(words).await
709    }
710}
711
712impl<'d, T: Instance, M: Mode> SetConfig for Spi<'d, T, M> {
713    type Config = Config;
714    type ConfigError = ();
715    fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
716        self.set_config(config);
717
718        Ok(())
719    }
720}