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