esp_hal/spi/
slave.rs

1//! # Serial Peripheral Interface - Slave Mode
2//!
3//! ## Overview
4//!
5//! In this mode, the SPI acts as slave and transfers data with its master when
6//! its CS is asserted.
7//!
8//! ## Configuration
9//!
10//! The SPI slave driver allows using full-duplex and can only be used with DMA.
11//!
12//! ## Examples
13//!
14//! ### SPI Slave with DMA
15//!
16//! ```rust, no_run
17#![doc = crate::before_snippet!()]
18//! # use esp_hal::dma_buffers;
19//! # use esp_hal::spi::Mode;
20//! # use esp_hal::spi::slave::Spi;
21#![cfg_attr(pdma, doc = "let dma_channel = peripherals.DMA_SPI2;")]
22#![cfg_attr(gdma, doc = "let dma_channel = peripherals.DMA_CH0;")]
23//! let sclk = peripherals.GPIO0;
24//! let miso = peripherals.GPIO1;
25//! let mosi = peripherals.GPIO2;
26//! let cs = peripherals.GPIO3;
27//!
28//! let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) =
29//! dma_buffers!(32000);
30//! let mut spi = Spi::new(
31//!     peripherals.SPI2,
32//!     Mode::_0,
33//! )
34//! .with_sck(sclk)
35//! .with_mosi(mosi)
36//! .with_miso(miso)
37//! .with_cs(cs)
38//! .with_dma(
39//!     dma_channel,
40//!     rx_descriptors,
41//!     tx_descriptors,
42//! );
43//!
44//! let mut receive = rx_buffer;
45//! let mut send = tx_buffer;
46//!
47//! let transfer = spi
48//!     .transfer(&mut receive, &mut send)?;
49//!
50//! transfer.wait()?;
51//! # Ok(())
52//! # }
53//! ```
54//! 
55//! ## Implementation State
56//!
57//! This driver is currently **unstable**.
58//!
59//! There are several options for working with the SPI peripheral in slave mode,
60//! but the code currently only supports:
61//! - Single transfers (not segmented transfers)
62//! - Full duplex, single bit (not dual or quad SPI)
63//! - DMA mode (not CPU mode).
64#![cfg_attr(esp32, doc = "- ESP32 only supports SPI mode 1 and 3.\n\n")]
65//! It also does not support blocking operations, as the actual
66//! transfer is controlled by the SPI master; if these are necessary,
67//! then the `DmaTransfer` object can be `wait()`ed on or polled for
68//! `is_done()`.
69//!
70//! See [tracking issue](https://github.com/esp-rs/esp-hal/issues/469) for more information.
71
72use core::marker::PhantomData;
73
74use super::{Error, Mode};
75use crate::{
76    dma::DmaEligible,
77    gpio::{
78        interconnect::{PeripheralInput, PeripheralOutput},
79        InputSignal,
80        NoPin,
81        OutputSignal,
82    },
83    pac::spi2::RegisterBlock,
84    peripheral::{Peripheral, PeripheralRef},
85    spi::AnySpi,
86    system::PeripheralGuard,
87    Blocking,
88    DriverMode,
89};
90
91const MAX_DMA_SIZE: usize = 32768 - 32;
92
93/// SPI peripheral driver.
94///
95/// See the [module-level documentation][self] for more details.
96#[instability::unstable]
97pub struct Spi<'d, Dm: DriverMode> {
98    spi: PeripheralRef<'d, AnySpi>,
99    #[allow(dead_code)]
100    data_mode: Mode,
101    _mode: PhantomData<Dm>,
102    _guard: PeripheralGuard,
103}
104impl<'d> Spi<'d, Blocking> {
105    /// Constructs an SPI instance in 8bit dataframe mode.
106    #[instability::unstable]
107    pub fn new(spi: impl Peripheral<P = impl Instance> + 'd, mode: Mode) -> Spi<'d, Blocking> {
108        crate::into_mapped_ref!(spi);
109
110        let guard = PeripheralGuard::new(spi.info().peripheral);
111
112        let this = Spi {
113            spi,
114            data_mode: mode,
115            _mode: PhantomData,
116            _guard: guard,
117        };
118
119        this.spi.info().init();
120        this.spi.info().set_data_mode(mode, false);
121
122        this.with_mosi(NoPin)
123            .with_miso(NoPin)
124            .with_sck(NoPin)
125            .with_cs(NoPin)
126    }
127
128    /// Assign the SCK (Serial Clock) pin for the SPI instance.
129    #[instability::unstable]
130    pub fn with_sck(self, sclk: impl Peripheral<P = impl PeripheralInput> + 'd) -> Self {
131        crate::into_mapped_ref!(sclk);
132        sclk.enable_input(true);
133        self.spi.info().sclk.connect_to(sclk);
134        self
135    }
136
137    /// Assign the MOSI (Master Out Slave In) pin for the SPI instance.
138    #[instability::unstable]
139    pub fn with_mosi(self, mosi: impl Peripheral<P = impl PeripheralInput> + 'd) -> Self {
140        crate::into_mapped_ref!(mosi);
141        mosi.enable_input(true);
142        self.spi.info().mosi.connect_to(mosi);
143        self
144    }
145
146    /// Assign the MISO (Master In Slave Out) pin for the SPI instance.
147    #[instability::unstable]
148    pub fn with_miso(self, miso: impl Peripheral<P = impl PeripheralOutput> + 'd) -> Self {
149        crate::into_mapped_ref!(miso);
150        miso.set_to_push_pull_output();
151        self.spi.info().miso.connect_to(miso);
152        self
153    }
154
155    /// Assign the CS (Chip Select) pin for the SPI instance.
156    #[instability::unstable]
157    pub fn with_cs(self, cs: impl Peripheral<P = impl PeripheralInput> + 'd) -> Self {
158        crate::into_mapped_ref!(cs);
159        cs.enable_input(true);
160        self.spi.info().cs.connect_to(cs);
161        self
162    }
163}
164
165/// DMA (Direct Memory Access) functionality (Slave).
166#[instability::unstable]
167pub mod dma {
168    use super::*;
169    use crate::{
170        dma::{
171            dma_private::{DmaSupport, DmaSupportRx, DmaSupportTx},
172            Channel,
173            ChannelRx,
174            ChannelTx,
175            DescriptorChain,
176            DmaChannelFor,
177            DmaDescriptor,
178            DmaTransferRx,
179            DmaTransferRxTx,
180            DmaTransferTx,
181            PeripheralDmaChannel,
182            PeripheralRxChannel,
183            PeripheralTxChannel,
184            ReadBuffer,
185            Rx,
186            Tx,
187            WriteBuffer,
188        },
189        DriverMode,
190    };
191
192    impl<'d> Spi<'d, Blocking> {
193        /// Configures the SPI peripheral with the provided DMA channel and
194        /// descriptors.
195        #[cfg_attr(esp32, doc = "\n\n**Note**: ESP32 only supports Mode 1 and 3.")]
196        #[instability::unstable]
197        pub fn with_dma<CH>(
198            self,
199            channel: impl Peripheral<P = CH> + 'd,
200            rx_descriptors: &'static mut [DmaDescriptor],
201            tx_descriptors: &'static mut [DmaDescriptor],
202        ) -> SpiDma<'d, Blocking>
203        where
204            CH: DmaChannelFor<AnySpi>,
205        {
206            self.spi.info().set_data_mode(self.data_mode, true);
207            SpiDma::new(
208                self.spi,
209                channel.map(|ch| ch.degrade()).into_ref(),
210                rx_descriptors,
211                tx_descriptors,
212            )
213        }
214    }
215
216    /// A DMA capable SPI instance.
217    #[instability::unstable]
218    pub struct SpiDma<'d, Dm>
219    where
220        Dm: DriverMode,
221    {
222        pub(crate) spi: PeripheralRef<'d, AnySpi>,
223        pub(crate) channel: Channel<'d, Dm, PeripheralDmaChannel<AnySpi>>,
224        rx_chain: DescriptorChain,
225        tx_chain: DescriptorChain,
226        _guard: PeripheralGuard,
227    }
228
229    impl<Dm> core::fmt::Debug for SpiDma<'_, Dm>
230    where
231        Dm: DriverMode,
232    {
233        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
234            f.debug_struct("SpiDma").finish()
235        }
236    }
237
238    impl<Dm> DmaSupport for SpiDma<'_, Dm>
239    where
240        Dm: DriverMode,
241    {
242        fn peripheral_wait_dma(&mut self, is_rx: bool, is_tx: bool) {
243            while !((!is_tx || self.channel.tx.is_done())
244                && (!is_rx || self.channel.rx.is_done())
245                && !self.spi.info().is_bus_busy())
246            {}
247
248            self.spi.info().flush().ok();
249        }
250
251        fn peripheral_dma_stop(&mut self) {
252            unreachable!("unsupported")
253        }
254    }
255
256    impl<'d, Dm> DmaSupportTx for SpiDma<'d, Dm>
257    where
258        Dm: DriverMode,
259    {
260        type TX = ChannelTx<'d, Dm, PeripheralTxChannel<AnySpi>>;
261
262        fn tx(&mut self) -> &mut Self::TX {
263            &mut self.channel.tx
264        }
265
266        fn chain(&mut self) -> &mut DescriptorChain {
267            &mut self.tx_chain
268        }
269    }
270
271    impl<'d, Dm> DmaSupportRx for SpiDma<'d, Dm>
272    where
273        Dm: DriverMode,
274    {
275        type RX = ChannelRx<'d, Dm, PeripheralRxChannel<AnySpi>>;
276
277        fn rx(&mut self) -> &mut Self::RX {
278            &mut self.channel.rx
279        }
280
281        fn chain(&mut self) -> &mut DescriptorChain {
282            &mut self.rx_chain
283        }
284    }
285
286    impl<'d> SpiDma<'d, Blocking> {
287        fn new(
288            spi: PeripheralRef<'d, AnySpi>,
289            channel: PeripheralRef<'d, PeripheralDmaChannel<AnySpi>>,
290            rx_descriptors: &'static mut [DmaDescriptor],
291            tx_descriptors: &'static mut [DmaDescriptor],
292        ) -> Self {
293            let channel = Channel::new(channel);
294            channel.runtime_ensure_compatible(&spi);
295            let guard = PeripheralGuard::new(spi.info().peripheral);
296
297            Self {
298                spi,
299                channel,
300                rx_chain: DescriptorChain::new(rx_descriptors),
301                tx_chain: DescriptorChain::new(tx_descriptors),
302                _guard: guard,
303            }
304        }
305    }
306
307    impl<Dm> SpiDma<'_, Dm>
308    where
309        Dm: DriverMode,
310    {
311        fn driver(&self) -> DmaDriver {
312            DmaDriver {
313                info: self.spi.info(),
314                dma_peripheral: self.spi.dma_peripheral(),
315            }
316        }
317
318        /// Register a buffer for a DMA write.
319        ///
320        /// This will return a [DmaTransferTx]. The maximum amount of data to be
321        /// sent is 32736 bytes.
322        ///
323        /// The write is driven by the SPI master's sclk signal and cs line.
324        #[instability::unstable]
325        pub fn write<'t, TXBUF>(
326            &'t mut self,
327            words: &'t TXBUF,
328        ) -> Result<DmaTransferTx<'t, Self>, Error>
329        where
330            TXBUF: ReadBuffer,
331        {
332            let (ptr, len) = unsafe { words.read_buffer() };
333
334            if len > MAX_DMA_SIZE {
335                return Err(Error::MaxDmaTransferSizeExceeded);
336            }
337
338            unsafe {
339                self.driver()
340                    .start_transfer_dma(
341                        &mut self.rx_chain,
342                        &mut self.tx_chain,
343                        core::ptr::null_mut(),
344                        0,
345                        ptr,
346                        len,
347                        &mut self.channel.rx,
348                        &mut self.channel.tx,
349                    )
350                    .map(move |_| DmaTransferTx::new(self))
351            }
352        }
353
354        /// Register a buffer for a DMA read.
355        ///
356        /// This will return a [DmaTransferRx]. The maximum amount of data to be
357        /// received is 32736 bytes.
358        ///
359        /// The read is driven by the SPI master's sclk signal and cs line.
360        #[instability::unstable]
361        pub fn read<'t, RXBUF>(
362            &'t mut self,
363            words: &'t mut RXBUF,
364        ) -> Result<DmaTransferRx<'t, Self>, Error>
365        where
366            RXBUF: WriteBuffer,
367        {
368            let (ptr, len) = unsafe { words.write_buffer() };
369
370            if len > MAX_DMA_SIZE {
371                return Err(Error::MaxDmaTransferSizeExceeded);
372            }
373
374            unsafe {
375                self.driver()
376                    .start_transfer_dma(
377                        &mut self.rx_chain,
378                        &mut self.tx_chain,
379                        ptr,
380                        len,
381                        core::ptr::null(),
382                        0,
383                        &mut self.channel.rx,
384                        &mut self.channel.tx,
385                    )
386                    .map(move |_| DmaTransferRx::new(self))
387            }
388        }
389
390        /// Register buffers for a DMA transfer.
391        ///
392        /// This will return a [DmaTransferRxTx]. The maximum amount of data to
393        /// be sent/received is 32736 bytes.
394        ///
395        /// The data transfer is driven by the SPI master's sclk signal and cs
396        /// line.
397        #[instability::unstable]
398        pub fn transfer<'t, RXBUF, TXBUF>(
399            &'t mut self,
400            read_buffer: &'t mut RXBUF,
401            words: &'t TXBUF,
402        ) -> Result<DmaTransferRxTx<'t, Self>, Error>
403        where
404            RXBUF: WriteBuffer,
405            TXBUF: ReadBuffer,
406        {
407            let (write_ptr, write_len) = unsafe { words.read_buffer() };
408            let (read_ptr, read_len) = unsafe { read_buffer.write_buffer() };
409
410            if write_len > MAX_DMA_SIZE || read_len > MAX_DMA_SIZE {
411                return Err(Error::MaxDmaTransferSizeExceeded);
412            }
413
414            unsafe {
415                self.driver()
416                    .start_transfer_dma(
417                        &mut self.rx_chain,
418                        &mut self.tx_chain,
419                        read_ptr,
420                        read_len,
421                        write_ptr,
422                        write_len,
423                        &mut self.channel.rx,
424                        &mut self.channel.tx,
425                    )
426                    .map(move |_| DmaTransferRxTx::new(self))
427            }
428        }
429    }
430
431    struct DmaDriver {
432        info: &'static Info,
433        dma_peripheral: crate::dma::DmaPeripheral,
434    }
435
436    impl DmaDriver {
437        fn regs(&self) -> &RegisterBlock {
438            self.info.regs()
439        }
440
441        #[allow(clippy::too_many_arguments)]
442        unsafe fn start_transfer_dma<RX, TX>(
443            &self,
444            rx_chain: &mut DescriptorChain,
445            tx_chain: &mut DescriptorChain,
446            read_buffer_ptr: *mut u8,
447            read_buffer_len: usize,
448            write_buffer_ptr: *const u8,
449            write_buffer_len: usize,
450            rx: &mut RX,
451            tx: &mut TX,
452        ) -> Result<(), Error>
453        where
454            RX: Rx,
455            TX: Tx,
456        {
457            self.enable_dma();
458
459            self.info.reset_spi();
460
461            if read_buffer_len > 0 {
462                rx_chain.fill_for_rx(false, read_buffer_ptr, read_buffer_len)?;
463                rx.prepare_transfer_without_start(self.dma_peripheral, rx_chain)?;
464            }
465
466            if write_buffer_len > 0 {
467                tx_chain.fill_for_tx(false, write_buffer_ptr, write_buffer_len)?;
468                tx.prepare_transfer_without_start(self.dma_peripheral, tx_chain)?;
469            }
470
471            #[cfg(esp32)]
472            self.info
473                .prepare_length_and_lines(read_buffer_len, write_buffer_len);
474
475            self.reset_dma_before_usr_cmd();
476
477            #[cfg(not(esp32))]
478            self.regs()
479                .dma_conf()
480                .modify(|_, w| w.dma_slv_seg_trans_en().clear_bit());
481
482            self.clear_dma_interrupts();
483            self.info.setup_for_flush();
484            self.regs().cmd().modify(|_, w| w.usr().set_bit());
485
486            if read_buffer_len > 0 {
487                rx.start_transfer()?;
488            }
489
490            if write_buffer_len > 0 {
491                tx.start_transfer()?;
492            }
493
494            Ok(())
495        }
496
497        fn reset_dma_before_usr_cmd(&self) {
498            #[cfg(gdma)]
499            self.regs().dma_conf().modify(|_, w| {
500                w.rx_afifo_rst().set_bit();
501                w.buf_afifo_rst().set_bit();
502                w.dma_afifo_rst().set_bit()
503            });
504        }
505
506        fn enable_dma(&self) {
507            #[cfg(gdma)]
508            self.regs().dma_conf().modify(|_, w| {
509                w.dma_tx_ena().set_bit();
510                w.dma_rx_ena().set_bit();
511                w.rx_eof_en().clear_bit()
512            });
513
514            #[cfg(pdma)]
515            {
516                fn set_rst_bit(reg_block: &RegisterBlock, bit: bool) {
517                    reg_block.dma_conf().modify(|_, w| {
518                        w.in_rst().bit(bit);
519                        w.out_rst().bit(bit);
520                        w.ahbm_fifo_rst().bit(bit);
521                        w.ahbm_rst().bit(bit)
522                    });
523
524                    #[cfg(esp32s2)]
525                    reg_block
526                        .dma_conf()
527                        .modify(|_, w| w.dma_infifo_full_clr().bit(bit));
528                }
529                set_rst_bit(self.regs(), true);
530                set_rst_bit(self.regs(), false);
531            }
532        }
533
534        fn clear_dma_interrupts(&self) {
535            #[cfg(gdma)]
536            self.regs().dma_int_clr().write(|w| {
537                w.dma_infifo_full_err().clear_bit_by_one();
538                w.dma_outfifo_empty_err().clear_bit_by_one();
539                w.trans_done().clear_bit_by_one();
540                w.mst_rx_afifo_wfull_err().clear_bit_by_one();
541                w.mst_tx_afifo_rempty_err().clear_bit_by_one()
542            });
543
544            #[cfg(pdma)]
545            self.regs().dma_int_clr().write(|w| {
546                w.inlink_dscr_empty().clear_bit_by_one();
547                w.outlink_dscr_error().clear_bit_by_one();
548                w.inlink_dscr_error().clear_bit_by_one();
549                w.in_done().clear_bit_by_one();
550                w.in_err_eof().clear_bit_by_one();
551                w.in_suc_eof().clear_bit_by_one();
552                w.out_done().clear_bit_by_one();
553                w.out_eof().clear_bit_by_one();
554                w.out_total_eof().clear_bit_by_one()
555            });
556        }
557    }
558}
559
560/// SPI peripheral instance.
561#[doc(hidden)]
562pub trait Instance: Peripheral<P = Self> + Into<AnySpi> + 'static {
563    /// Returns the peripheral data describing this SPI instance.
564    fn info(&self) -> &'static Info;
565}
566
567/// A marker for DMA-capable SPI peripheral instances.
568#[doc(hidden)]
569pub trait InstanceDma: Instance + DmaEligible {}
570
571impl InstanceDma for crate::peripherals::SPI2 {}
572#[cfg(spi3)]
573impl InstanceDma for crate::peripherals::SPI3 {}
574
575/// Peripheral data describing a particular SPI instance.
576#[non_exhaustive]
577#[doc(hidden)]
578pub struct Info {
579    /// Pointer to the register block for this SPI instance.
580    ///
581    /// Use [Self::register_block] to access the register block.
582    pub register_block: *const RegisterBlock,
583
584    /// System peripheral marker.
585    pub peripheral: crate::system::Peripheral,
586
587    /// SCLK signal.
588    pub sclk: InputSignal,
589
590    /// MOSI signal.
591    pub mosi: InputSignal,
592
593    /// MISO signal.
594    pub miso: OutputSignal,
595
596    /// Chip select signal.
597    pub cs: InputSignal,
598}
599
600impl Info {
601    /// Returns the register block for this SPI instance.
602    #[instability::unstable]
603    pub fn regs(&self) -> &RegisterBlock {
604        unsafe { &*self.register_block }
605    }
606
607    fn reset_spi(&self) {
608        #[cfg(esp32)]
609        {
610            self.regs().slave().modify(|_, w| w.sync_reset().set_bit());
611            self.regs()
612                .slave()
613                .modify(|_, w| w.sync_reset().clear_bit());
614        }
615
616        #[cfg(not(esp32))]
617        {
618            self.regs().slave().modify(|_, w| w.soft_reset().set_bit());
619            self.regs()
620                .slave()
621                .modify(|_, w| w.soft_reset().clear_bit());
622        }
623    }
624
625    #[cfg(esp32)]
626    fn prepare_length_and_lines(&self, rx_len: usize, tx_len: usize) {
627        self.regs()
628            .slv_rdbuf_dlen()
629            .write(|w| unsafe { w.bits((rx_len as u32 * 8).saturating_sub(1)) });
630        self.regs()
631            .slv_wrbuf_dlen()
632            .write(|w| unsafe { w.bits((tx_len as u32 * 8).saturating_sub(1)) });
633
634        // SPI Slave mode on ESP32 requires MOSI/MISO enable
635        self.regs().user().modify(|_, w| {
636            w.usr_mosi().bit(rx_len > 0);
637            w.usr_miso().bit(tx_len > 0)
638        });
639    }
640
641    /// Initialize for full-duplex 1 bit mode
642    fn init(&self) {
643        self.regs().clock().write(|w| unsafe { w.bits(0) });
644        self.regs().user().write(|w| unsafe { w.bits(0) });
645        self.regs().ctrl().write(|w| unsafe { w.bits(0) });
646
647        self.regs().slave().write(|w| {
648            #[cfg(esp32)]
649            w.slv_wr_rd_buf_en().set_bit();
650
651            w.mode().set_bit()
652        });
653        self.reset_spi();
654
655        self.regs().user().modify(|_, w| {
656            w.doutdin().set_bit();
657            w.sio().clear_bit()
658        });
659
660        #[cfg(not(esp32))]
661        self.regs().misc().write(|w| unsafe { w.bits(0) });
662    }
663
664    fn set_data_mode(&self, data_mode: Mode, dma: bool) {
665        #[cfg(esp32)]
666        {
667            self.regs().pin().modify(|_, w| {
668                w.ck_idle_edge()
669                    .bit(matches!(data_mode, Mode::_0 | Mode::_1))
670            });
671            self.regs()
672                .user()
673                .modify(|_, w| w.ck_i_edge().bit(matches!(data_mode, Mode::_1 | Mode::_2)));
674            self.regs().ctrl2().modify(|_, w| unsafe {
675                match data_mode {
676                    Mode::_0 => {
677                        w.miso_delay_mode().bits(0);
678                        w.miso_delay_num().bits(0);
679                        w.mosi_delay_mode().bits(2);
680                        w.mosi_delay_num().bits(2)
681                    }
682                    Mode::_1 => {
683                        w.miso_delay_mode().bits(2);
684                        w.miso_delay_num().bits(0);
685                        w.mosi_delay_mode().bits(0);
686                        w.mosi_delay_num().bits(0)
687                    }
688                    Mode::_2 => {
689                        w.miso_delay_mode().bits(0);
690                        w.miso_delay_num().bits(0);
691                        w.mosi_delay_mode().bits(1);
692                        w.mosi_delay_num().bits(2)
693                    }
694                    Mode::_3 => {
695                        w.miso_delay_mode().bits(1);
696                        w.miso_delay_num().bits(0);
697                        w.mosi_delay_mode().bits(0);
698                        w.mosi_delay_num().bits(0)
699                    }
700                }
701            });
702
703            if dma {
704                assert!(
705                    matches!(data_mode, Mode::_1 | Mode::_3),
706                    "Mode {:?} is not supported with DMA",
707                    data_mode
708                );
709            }
710        }
711
712        #[cfg(not(esp32))]
713        {
714            _ = dma;
715            self.regs().user().modify(|_, w| {
716                w.tsck_i_edge()
717                    .bit(matches!(data_mode, Mode::_1 | Mode::_2));
718                w.rsck_i_edge()
719                    .bit(matches!(data_mode, Mode::_1 | Mode::_2))
720            });
721            cfg_if::cfg_if! {
722                if #[cfg(esp32s2)] {
723                    let ctrl1_reg = self.regs().ctrl1();
724                } else {
725                    let ctrl1_reg = self.regs().slave();
726                }
727            }
728            ctrl1_reg.modify(|_, w| {
729                w.clk_mode_13()
730                    .bit(matches!(data_mode, Mode::_1 | Mode::_3))
731            });
732        }
733    }
734
735    fn is_bus_busy(&self) -> bool {
736        #[cfg(pdma)]
737        {
738            self.regs().slave().read().trans_done().bit_is_clear()
739        }
740        #[cfg(gdma)]
741        {
742            self.regs().dma_int_raw().read().trans_done().bit_is_clear()
743        }
744    }
745
746    // Check if the bus is busy and if it is wait for it to be idle
747    fn flush(&self) -> Result<(), Error> {
748        while self.is_bus_busy() {
749            // Wait for bus to be clear
750        }
751        Ok(())
752    }
753
754    // Clear the transaction-done interrupt flag so flush() can work properly. Not
755    // used in DMA mode.
756    fn setup_for_flush(&self) {
757        #[cfg(pdma)]
758        self.regs()
759            .slave()
760            .modify(|_, w| w.trans_done().clear_bit());
761        #[cfg(gdma)]
762        self.regs()
763            .dma_int_clr()
764            .write(|w| w.trans_done().clear_bit_by_one());
765    }
766}
767
768impl PartialEq for Info {
769    fn eq(&self, other: &Self) -> bool {
770        self.register_block == other.register_block
771    }
772}
773
774unsafe impl Sync for Info {}
775
776macro_rules! spi_instance {
777    ($num:literal, $sclk:ident, $mosi:ident, $miso:ident, $cs:ident) => {
778        paste::paste! {
779            impl Instance for crate::peripherals::[<SPI $num>] {
780                #[inline(always)]
781                fn info(&self) -> &'static Info {
782                    static INFO: Info = Info {
783                        register_block: crate::peripherals::[<SPI $num>]::regs(),
784                        peripheral: crate::system::Peripheral::[<Spi $num>],
785                        sclk: InputSignal::$sclk,
786                        mosi: InputSignal::$mosi,
787                        miso: OutputSignal::$miso,
788                        cs: InputSignal::$cs,
789                    };
790
791                    &INFO
792                }
793            }
794        }
795    };
796}
797
798cfg_if::cfg_if! {
799    if #[cfg(esp32)] {
800        #[cfg(spi2)]
801        spi_instance!(2, HSPICLK, HSPID, HSPIQ, HSPICS0);
802        #[cfg(spi3)]
803        spi_instance!(3, VSPICLK, VSPID, VSPIQ, VSPICS0);
804    } else {
805        #[cfg(spi2)]
806        spi_instance!(2, FSPICLK, FSPID, FSPIQ, FSPICS0);
807        #[cfg(spi3)]
808        spi_instance!(3, SPI3_CLK, SPI3_D, SPI3_Q, SPI3_CS0);
809    }
810}
811
812impl Instance for super::AnySpi {
813    delegate::delegate! {
814        to match &self.0 {
815            super::AnySpiInner::Spi2(spi) => spi,
816            #[cfg(spi3)]
817            super::AnySpiInner::Spi3(spi) => spi,
818        } {
819            fn info(&self) -> &'static Info;
820        }
821    }
822}
823
824impl InstanceDma for super::AnySpi {}