Skip to main content

esp_idf_hal/
spi.rs

1//! SPI peripheral control
2//!
3//! SPI0 is reserved for accessing flash and sram and therefore not usable for other purposes.
4//! SPI1 shares its external pins with SPI0 and therefore has severe restrictions in use.
5//!
6//! SPI2 & 3 can be used freely.
7//!
8//! The CS pin can be controlled by hardware on esp32 variants (contrary to the description of embedded_hal).
9//!
10//! Look at the following table to determine which driver best suits your requirements:
11//!
12//! |   |                  | SpiDeviceDriver::new | SpiDeviceDriver::new (no CS) | SpiSoftCsDeviceDriver::new | SpiBusDriver::new |
13//! |---|------------------|----------------------|------------------------------|----------------------------|-------------------|
14//! |   | Managed CS       |       Hardware       |              N               |     Software triggered     |         N         |
15//! |   | 1 device         |           Y          |              Y               |              Y             |         Y         |
16//! |   | 1-3 devices      |           Y          |              N               |              Y             |         N         |
17//! |   | 4-6 devices      |    Only on esp32CX   |              N               |              Y             |         N         |
18//! |   | More than 6      |           N          |              N               |              Y             |         N         |
19//! |   | DMA              |           Y          |              Y               |              Y             |         Y         |
20//! |   | Polling transmit |           Y          |              Y               |              Y             |         Y         |
21//! |   | ISR transmit     |           Y          |              Y               |              Y             |         Y         |
22//! |   | Async support*   |           Y          |              Y               |              Y             |         Y         |
23//!
24//! * True non-blocking async possible only when all devices attached to the SPI bus are used in async mode (i.e. calling methods `xxx_async()`
25//!   instead of their blocking `xxx()` counterparts)
26//!
27//! The [Transfer::transfer], [Write::write] and [WriteIter::write_iter] functions lock the
28//! APB frequency and therefore the requests are always run at the requested baudrate.
29//! The primitive [FullDuplex::read] and [FullDuplex::send] do not lock the APB frequency and
30//! therefore may run at a different frequency.
31//!
32//! # TODO
33//! - Slave SPI
34
35use core::borrow::{Borrow, BorrowMut};
36use core::cell::Cell;
37use core::cell::UnsafeCell;
38use core::cmp::{max, min, Ordering};
39use core::future::Future;
40use core::iter::once;
41use core::marker::PhantomData;
42use core::ptr;
43
44use embassy_sync::mutex::Mutex;
45use embedded_hal::spi::{SpiBus, SpiDevice};
46
47use esp_idf_sys::*;
48use heapless::Deque;
49
50use crate::delay::{self, Ets, BLOCK};
51use crate::gpio::{AnyOutputPin, InputPin, Level, Output, OutputMode, OutputPin, PinDriver};
52use crate::interrupt::asynch::HalIsrNotification;
53use crate::interrupt::InterruptType;
54use crate::task::embassy_sync::EspRawMutex;
55use crate::task::CriticalSection;
56
57crate::embedded_hal_error!(
58    SpiError,
59    embedded_hal::spi::Error,
60    embedded_hal::spi::ErrorKind
61);
62
63use config::{Duplex, LineWidth};
64
65pub trait Spi: Send {
66    fn device() -> spi_host_device_t;
67}
68
69/// A marker interface implemented by all SPI peripherals except SPI1 which
70/// should use a fixed set of pins
71pub trait SpiAnyPins: Spi {}
72
73#[derive(Debug, Copy, Clone, Eq, PartialEq)]
74pub enum Dma {
75    Disabled,
76    Channel1(usize),
77    Channel2(usize),
78    Auto(usize),
79}
80
81impl From<Dma> for spi_dma_chan_t {
82    fn from(dma: Dma) -> Self {
83        match dma {
84            Dma::Channel1(_) => 1,
85            Dma::Channel2(_) => 2,
86            Dma::Auto(_) => 3,
87            _ => 0,
88        }
89    }
90}
91
92impl Dma {
93    pub const fn max_transfer_size(&self) -> usize {
94        let max_transfer_size = match self {
95            Dma::Disabled => TRANS_LEN,
96            Dma::Channel1(size) | Dma::Channel2(size) | Dma::Auto(size) => *size,
97        };
98        match max_transfer_size {
99            0 => panic!("The max transfer size must be greater than 0"),
100            x if x % 4 != 0 => panic!("The max transfer size must be a multiple of 4"),
101            _ => max_transfer_size,
102        }
103    }
104}
105
106pub type SpiDriverConfig = config::DriverConfig;
107pub type SpiConfig = config::Config;
108
109/// SPI configuration
110pub mod config {
111    use crate::{interrupt::InterruptType, units::*};
112    use enumset::EnumSet;
113    use esp_idf_sys::*;
114
115    use super::Dma;
116
117    pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
118
119    pub struct V02Type<T>(pub T);
120
121    impl From<V02Type<embedded_hal_0_2::spi::Polarity>> for Polarity {
122        fn from(polarity: V02Type<embedded_hal_0_2::spi::Polarity>) -> Self {
123            match polarity.0 {
124                embedded_hal_0_2::spi::Polarity::IdleHigh => Polarity::IdleHigh,
125                embedded_hal_0_2::spi::Polarity::IdleLow => Polarity::IdleLow,
126            }
127        }
128    }
129
130    impl From<V02Type<embedded_hal_0_2::spi::Phase>> for Phase {
131        fn from(phase: V02Type<embedded_hal_0_2::spi::Phase>) -> Self {
132            match phase.0 {
133                embedded_hal_0_2::spi::Phase::CaptureOnFirstTransition => {
134                    Phase::CaptureOnFirstTransition
135                }
136                embedded_hal_0_2::spi::Phase::CaptureOnSecondTransition => {
137                    Phase::CaptureOnSecondTransition
138                }
139            }
140        }
141    }
142
143    impl From<V02Type<embedded_hal_0_2::spi::Mode>> for Mode {
144        fn from(mode: V02Type<embedded_hal_0_2::spi::Mode>) -> Self {
145            Self {
146                polarity: V02Type(mode.0.polarity).into(),
147                phase: V02Type(mode.0.phase).into(),
148            }
149        }
150    }
151
152    /// Specify the communication mode with the device
153    #[derive(Debug, Copy, Clone, Eq, PartialEq)]
154    pub enum Duplex {
155        /// Full duplex is the default
156        Full,
157        /// Half duplex in some cases
158        Half,
159        /// Use MOSI (=spid) for both sending and receiving data (implies half duplex)
160        Half3Wire,
161    }
162
163    impl Duplex {
164        pub fn as_flags(&self) -> u32 {
165            match self {
166                Duplex::Full => 0,
167                Duplex::Half => SPI_DEVICE_HALFDUPLEX,
168                Duplex::Half3Wire => SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE,
169            }
170        }
171    }
172
173    /// Specifies the order in which the bits of data should be transfered/received
174    #[derive(Debug, Copy, Clone, Eq, PartialEq)]
175    pub enum BitOrder {
176        /// Most significant bit first (default)
177        MsbFirst,
178        /// Least significant bit first
179        LsbFirst,
180        /// Least significant bit first, when sending
181        TxLsbFirst,
182        /// Least significant bit first, when receiving
183        RxLsbFirst,
184    }
185
186    impl BitOrder {
187        pub fn as_flags(&self) -> u32 {
188            match self {
189                Self::MsbFirst => 0,
190                Self::LsbFirst => SPI_DEVICE_BIT_LSBFIRST,
191                Self::TxLsbFirst => SPI_DEVICE_TXBIT_LSBFIRST,
192                Self::RxLsbFirst => SPI_DEVICE_RXBIT_LSBFIRST,
193            }
194        }
195    }
196
197    #[derive(Debug, Copy, Clone, Eq, PartialEq)]
198    pub enum LineWidth {
199        /// 1-bit, 2 wire duplex or 1 wire half-duplex
200        Single,
201        /// 2-bit, 2 wire half-duplex
202        Dual,
203        /// 4-bit, 4 wire half-duplex
204        Quad,
205    }
206
207    /// SPI Driver configuration
208    #[derive(Debug, Clone)]
209    pub struct DriverConfig {
210        pub dma: Dma,
211        pub intr_flags: EnumSet<InterruptType>,
212    }
213
214    impl DriverConfig {
215        pub fn new() -> Self {
216            Default::default()
217        }
218
219        #[must_use]
220        pub fn dma(mut self, dma: Dma) -> Self {
221            self.dma = dma;
222            self
223        }
224
225        #[must_use]
226        pub fn intr_flags(mut self, intr_flags: EnumSet<InterruptType>) -> Self {
227            self.intr_flags = intr_flags;
228            self
229        }
230    }
231
232    impl Default for DriverConfig {
233        fn default() -> Self {
234            Self {
235                dma: Dma::Disabled,
236                intr_flags: EnumSet::<InterruptType>::empty(),
237            }
238        }
239    }
240
241    /// SPI Device configuration
242    #[derive(Debug, Clone)]
243    pub struct Config {
244        pub baudrate: Hertz,
245        pub data_mode: Mode,
246        /// This property can be set to configure a SPI Device for being write only
247        /// Thus the flag SPI_DEVICE_NO_DUMMY will be passed on initialization and
248        /// it will unlock the possibility of using 80Mhz as the bus freq
249        /// See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/spi_master.html#timing-considerations
250        pub write_only: bool,
251        pub duplex: Duplex,
252        pub bit_order: BitOrder,
253        pub cs_active_high: bool,
254        /// On Half-Duplex transactions: `cs_pre_delay_us % 16`  corresponds to the number of SPI bit-cycles cs should be activated before the transmission.
255        /// On Full-Duplex transactions: `cs_pre_delay_us != 0`  will add 1 microsecond of cs activation before transmission
256        pub cs_pre_delay_us: Option<u16>, // u16 as per the C struct has a uint16_t, cf: esp-idf/components/driver/spi/include/driver/spi_master.h spi_device_interface_config_t
257        ///< Amount of SPI bit-cycles the cs should stay active after the transmission (0-16)
258        pub cs_post_delay_us: Option<u8>, // u8 as per the C struct had a uint8_t, cf: esp-idf/components/driver/spi/include/driver/spi_master.h spi_device_interface_config_t
259        pub input_delay_ns: i32,
260        pub polling: bool,
261        pub allow_pre_post_delays: bool,
262        pub queue_size: usize,
263    }
264
265    impl Config {
266        pub fn new() -> Self {
267            Default::default()
268        }
269
270        #[must_use]
271        pub fn baudrate(mut self, baudrate: Hertz) -> Self {
272            self.baudrate = baudrate;
273            self
274        }
275
276        #[must_use]
277        pub fn data_mode(mut self, data_mode: Mode) -> Self {
278            self.data_mode = data_mode;
279            self
280        }
281
282        #[must_use]
283        pub fn write_only(mut self, write_only: bool) -> Self {
284            self.write_only = write_only;
285            self
286        }
287
288        #[must_use]
289        pub fn duplex(mut self, duplex: Duplex) -> Self {
290            self.duplex = duplex;
291            self
292        }
293
294        #[must_use]
295        pub fn bit_order(mut self, bit_order: BitOrder) -> Self {
296            self.bit_order = bit_order;
297            self
298        }
299
300        #[must_use]
301        pub fn cs_active_high(mut self) -> Self {
302            self.cs_active_high = true;
303            self
304        }
305
306        /// On Half-Duplex transactions: `cs_pre_delay_us % 16`  corresponds to the number of SPI bit-cycles cs should be activated before the transmission
307        /// On Full-Duplex transactions: `cs_pre_delay_us != 0`  will add 1 microsecond of cs activation before transmission
308        #[must_use]
309        pub fn cs_pre_delay_us(mut self, delay_us: u16) -> Self {
310            self.cs_pre_delay_us = Some(delay_us);
311            self
312        }
313
314        /// Add an aditional Amount of SPI bit-cycles the cs should be activated after the transmission (0-16).
315        /// This only works on half-duplex transactions.
316        #[must_use]
317        pub fn cs_post_delay_us(mut self, delay_us: u8) -> Self {
318            self.cs_post_delay_us = Some(delay_us);
319            self
320        }
321
322        #[must_use]
323        pub fn input_delay_ns(mut self, input_delay_ns: i32) -> Self {
324            self.input_delay_ns = input_delay_ns;
325            self
326        }
327
328        #[must_use]
329        pub fn polling(mut self, polling: bool) -> Self {
330            self.polling = polling;
331            self
332        }
333
334        #[must_use]
335        pub fn allow_pre_post_delays(mut self, allow_pre_post_delays: bool) -> Self {
336            self.allow_pre_post_delays = allow_pre_post_delays;
337            self
338        }
339
340        #[must_use]
341        pub fn queue_size(mut self, queue_size: usize) -> Self {
342            self.queue_size = queue_size;
343            self
344        }
345    }
346
347    impl Default for Config {
348        fn default() -> Self {
349            Self {
350                baudrate: Hertz(1_000_000),
351                data_mode: embedded_hal::spi::MODE_0,
352                write_only: false,
353                cs_active_high: false,
354                duplex: Duplex::Full,
355                bit_order: BitOrder::MsbFirst,
356                cs_pre_delay_us: None,
357                cs_post_delay_us: None,
358                input_delay_ns: 0,
359                polling: true,
360                allow_pre_post_delays: false,
361                queue_size: 1,
362            }
363        }
364    }
365
366    impl From<&Config> for spi_device_interface_config_t {
367        fn from(config: &Config) -> Self {
368            Self {
369                spics_io_num: -1,
370                clock_speed_hz: config.baudrate.0 as i32,
371                mode: data_mode_to_u8(config.data_mode),
372                queue_size: config.queue_size as i32,
373                flags: if config.write_only {
374                    SPI_DEVICE_NO_DUMMY
375                } else {
376                    0_u32
377                } | if config.cs_active_high {
378                    SPI_DEVICE_POSITIVE_CS
379                } else {
380                    0_u32
381                } | config.duplex.as_flags()
382                    | config.bit_order.as_flags(),
383                cs_ena_pretrans: config.cs_pre_delay_us.unwrap_or(0),
384                cs_ena_posttrans: config.cs_post_delay_us.unwrap_or(0),
385                ..Default::default()
386            }
387        }
388    }
389
390    fn data_mode_to_u8(data_mode: Mode) -> u8 {
391        (((data_mode.polarity == Polarity::IdleHigh) as u8) << 1)
392            | ((data_mode.phase == Phase::CaptureOnSecondTransition) as u8)
393    }
394}
395
396/// SPI transaction operation.
397///
398/// This allows composition of SPI operations into a single bus transaction.
399#[non_exhaustive]
400#[derive(Debug, PartialEq, Eq)]
401pub enum Operation<'a> {
402    /// Read data into the provided buffer.
403    Read(&'a mut [u8]),
404    /// Read data into the provided buffer with the provided line width in half-duplex mode.
405    ReadWithWidth(&'a mut [u8], LineWidth),
406    /// Write data from the provided buffer, discarding read data.
407    Write(&'a [u8]),
408    /// Write data from the provided buffer, using the provided line width in half-duplex mode,
409    /// discarding read data.
410    WriteWithWidth(&'a [u8], LineWidth),
411    /// Read data into the first buffer, while writing data from the second buffer.
412    Transfer(&'a mut [u8], &'a [u8]),
413    /// Write data out while reading data into the provided buffer.
414    TransferInPlace(&'a mut [u8]),
415    /// Delay for at least the specified number of nanoseconds.
416    DelayNs(u32),
417}
418
419pub struct SpiDriver<'d> {
420    host: u8,
421    max_transfer_size: usize,
422    #[allow(dead_code)]
423    bus_async_lock: Mutex<EspRawMutex, ()>,
424    _p: PhantomData<&'d mut ()>,
425}
426
427impl<'d> SpiDriver<'d> {
428    /// Create new instance of SPI controller for SPI1
429    ///
430    /// SPI1 can only use fixed pin for SCLK, SDO and SDI as they are shared with SPI0.
431    #[cfg(esp32)]
432    pub fn new_spi1(
433        _spi: SPI1<'d>,
434        sclk: crate::gpio::Gpio6<'d>,
435        sdo: crate::gpio::Gpio7<'d>,
436        sdi: Option<crate::gpio::Gpio8<'d>>,
437        config: &config::DriverConfig,
438    ) -> Result<Self, EspError> {
439        use crate::gpio::Pin;
440
441        let max_transfer_size = Self::new_internal(
442            SPI1::device(),
443            Some(sclk.pin() as _),
444            Some(sdo.pin() as _),
445            sdi.map(|p| p.pin() as _),
446            None,
447            None,
448            config,
449        )?;
450
451        Ok(Self {
452            host: SPI1::device() as _,
453            max_transfer_size,
454            bus_async_lock: Mutex::new(()),
455            _p: PhantomData,
456        })
457    }
458
459    /// Create new instance of SPI controller for all others
460    pub fn new<SPI: SpiAnyPins + 'd>(
461        _spi: SPI,
462        sclk: impl OutputPin + 'd,
463        sdo: impl OutputPin + 'd,
464        sdi: Option<impl InputPin + 'd>,
465        config: &config::DriverConfig,
466    ) -> Result<Self, EspError> {
467        let max_transfer_size = Self::new_internal(
468            SPI::device(),
469            Some(sclk.pin() as _),
470            Some(sdo.pin() as _),
471            sdi.map(|p| p.pin() as _),
472            None,
473            None,
474            config,
475        )?;
476
477        Ok(Self {
478            host: SPI::device() as _,
479            max_transfer_size,
480            bus_async_lock: Mutex::new(()),
481            _p: PhantomData,
482        })
483    }
484
485    pub fn new_without_sclk<SPI: SpiAnyPins + 'd>(
486        _spi: SPI,
487        sdo: impl OutputPin + 'd,
488        sdi: Option<impl InputPin + 'd>,
489        config: &config::DriverConfig,
490    ) -> Result<Self, EspError> {
491        let max_transfer_size = Self::new_internal(
492            SPI::device(),
493            None,
494            Some(sdo.pin() as _),
495            sdi.map(|p| p.pin() as _),
496            None,
497            None,
498            config,
499        )?;
500
501        Ok(Self {
502            host: SPI::device() as _,
503            max_transfer_size,
504            bus_async_lock: Mutex::new(()),
505            _p: PhantomData,
506        })
507    }
508
509    pub fn new_dual<SPI: SpiAnyPins + 'd>(
510        _spi: SPI,
511        sclk: impl OutputPin + 'd,
512        data0: impl InputPin + OutputPin + 'd,
513        data1: impl InputPin + OutputPin + 'd,
514        config: &config::DriverConfig,
515    ) -> Result<Self, EspError> {
516        let max_transfer_size = Self::new_internal(
517            SPI::device(),
518            Some(sclk.pin() as _),
519            Some(data0.pin() as _),
520            Some(data1.pin() as _),
521            None,
522            None,
523            config,
524        )?;
525
526        Ok(Self {
527            host: SPI::device() as _,
528            max_transfer_size,
529            bus_async_lock: Mutex::new(()),
530            _p: PhantomData,
531        })
532    }
533
534    pub fn new_quad<SPI: SpiAnyPins + 'd>(
535        _spi: SPI,
536        sclk: impl OutputPin + 'd,
537        data0: impl InputPin + OutputPin + 'd,
538        data1: impl InputPin + OutputPin + 'd,
539        data2: impl InputPin + OutputPin + 'd,
540        data3: impl InputPin + OutputPin + 'd,
541        config: &config::DriverConfig,
542    ) -> Result<Self, EspError> {
543        let max_transfer_size = Self::new_internal(
544            SPI::device(),
545            Some(sclk.pin() as _),
546            Some(data0.pin() as _),
547            Some(data1.pin() as _),
548            Some(data2.pin() as _),
549            Some(data3.pin() as _),
550            config,
551        )?;
552
553        Ok(Self {
554            host: SPI::device() as _,
555            max_transfer_size,
556            bus_async_lock: Mutex::new(()),
557            _p: PhantomData,
558        })
559    }
560
561    pub fn host(&self) -> spi_host_device_t {
562        self.host as _
563    }
564
565    fn new_internal(
566        host: spi_host_device_t,
567        sclk: Option<i32>,
568        sdo: Option<i32>,
569        sdi: Option<i32>,
570        data2: Option<i32>,
571        data3: Option<i32>,
572        config: &config::DriverConfig,
573    ) -> Result<usize, EspError> {
574        let max_transfer_sz = config.dma.max_transfer_size();
575        let dma_chan: spi_dma_chan_t = config.dma.into();
576
577        #[cfg(not(esp_idf_version_at_least_6_0_0))]
578        #[allow(clippy::needless_update)]
579        let bus_config = spi_bus_config_t {
580            flags: SPICOMMON_BUSFLAG_MASTER,
581            sclk_io_num: sclk.unwrap_or(-1),
582
583            data4_io_num: -1,
584            data5_io_num: -1,
585            data6_io_num: -1,
586            data7_io_num: -1,
587            __bindgen_anon_1: spi_bus_config_t__bindgen_ty_1 {
588                mosi_io_num: sdo.unwrap_or(-1),
589                //data0_io_num: -1,
590            },
591            __bindgen_anon_2: spi_bus_config_t__bindgen_ty_2 {
592                miso_io_num: sdi.unwrap_or(-1),
593                //data1_io_num: -1,
594            },
595            __bindgen_anon_3: spi_bus_config_t__bindgen_ty_3 {
596                quadwp_io_num: data2.unwrap_or(-1),
597                //data2_io_num: -1,
598            },
599            __bindgen_anon_4: spi_bus_config_t__bindgen_ty_4 {
600                quadhd_io_num: data3.unwrap_or(-1),
601                //data3_io_num: -1,
602            },
603            max_transfer_sz: max_transfer_sz as i32,
604            intr_flags: InterruptType::to_native(config.intr_flags) as _,
605            ..Default::default()
606        };
607
608        #[cfg(esp_idf_version_at_least_6_0_0)]
609        #[allow(clippy::needless_update)]
610        let bus_config = spi_bus_config_t {
611            __bindgen_anon_1: spi_bus_config_t__bindgen_ty_1 {
612                __bindgen_anon_1: spi_bus_config_t__bindgen_ty_1__bindgen_ty_1 {
613                    sclk_io_num: sclk.unwrap_or(-1),
614                    data4_io_num: -1,
615                    data5_io_num: -1,
616                    data6_io_num: -1,
617                    data7_io_num: -1,
618                    __bindgen_anon_1: spi_bus_config_t__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1 {
619                        mosi_io_num: sdo.unwrap_or(-1),
620                        //data0_io_num: -1,
621                    },
622                    __bindgen_anon_2: spi_bus_config_t__bindgen_ty_1__bindgen_ty_1__bindgen_ty_2 {
623                        miso_io_num: sdi.unwrap_or(-1),
624                        //data1_io_num: -1,
625                    },
626                    __bindgen_anon_3: spi_bus_config_t__bindgen_ty_1__bindgen_ty_1__bindgen_ty_3 {
627                        quadwp_io_num: data2.unwrap_or(-1),
628                        //data2_io_num: -1,
629                    },
630                    __bindgen_anon_4: spi_bus_config_t__bindgen_ty_1__bindgen_ty_1__bindgen_ty_4 {
631                        quadhd_io_num: data3.unwrap_or(-1),
632                        //data3_io_num: -1,
633                    },
634                },
635            },
636
637            flags: SPICOMMON_BUSFLAG_MASTER,
638            max_transfer_sz: max_transfer_sz as i32,
639            intr_flags: InterruptType::to_native(config.intr_flags) as _,
640            ..Default::default()
641        };
642
643        esp!(unsafe { spi_bus_initialize(host, &bus_config, dma_chan) })?;
644
645        Ok(max_transfer_sz)
646    }
647}
648
649impl Drop for SpiDriver<'_> {
650    fn drop(&mut self) {
651        esp!(unsafe { spi_bus_free(self.host()) }).unwrap();
652    }
653}
654
655unsafe impl Send for SpiDriver<'_> {}
656
657pub struct SpiBusDriver<'d, T>
658where
659    T: BorrowMut<SpiDriver<'d>>,
660{
661    lock: Option<BusLock>,
662    handle: spi_device_handle_t,
663    driver: T,
664    duplex: Duplex,
665    polling: bool,
666    queue_size: usize,
667    _d: PhantomData<&'d ()>,
668}
669
670impl<'d, T> SpiBusDriver<'d, T>
671where
672    T: BorrowMut<SpiDriver<'d>>,
673{
674    pub fn new(driver: T, config: &config::Config) -> Result<Self, EspError> {
675        let mut conf: spi_device_interface_config_t = config.into();
676        conf.post_cb = Some(spi_notify);
677
678        let mut handle: spi_device_handle_t = ptr::null_mut();
679        esp!(unsafe { spi_bus_add_device(driver.borrow().host(), &conf, &mut handle as *mut _) })?;
680
681        let lock = BusLock::new(handle)?;
682
683        Ok(Self {
684            lock: Some(lock),
685            handle,
686            driver,
687            duplex: config.duplex,
688            polling: config.polling,
689            queue_size: config.queue_size,
690            _d: PhantomData,
691        })
692    }
693
694    pub fn read(&mut self, words: &mut [u8]) -> Result<(), EspError> {
695        // Full-Duplex Mode:
696        // The internal hardware 16*4 u8 FIFO buffer (shared for read/write) is not cleared
697        // between transactions (read/write/transfer)
698        // This can lead to rewriting the internal buffer to MOSI on a read call
699
700        let chunk_size = self.driver.borrow().max_transfer_size;
701
702        let transactions = spi_read_transactions(words, chunk_size, self.duplex, LineWidth::Single);
703        spi_transmit(self.handle, transactions, self.polling, self.queue_size)?;
704
705        Ok(())
706    }
707
708    #[cfg(not(esp_idf_spi_master_isr_in_iram))]
709    pub async fn read_async(&mut self, words: &mut [u8]) -> Result<(), EspError> {
710        let chunk_size = self.driver.borrow().max_transfer_size;
711
712        let transactions = spi_read_transactions(words, chunk_size, self.duplex, LineWidth::Single);
713        core::pin::pin!(spi_transmit_async(
714            self.handle,
715            transactions,
716            self.queue_size
717        ))
718        .await?;
719
720        Ok(())
721    }
722
723    pub fn write(&mut self, words: &[u8]) -> Result<(), EspError> {
724        // Full-Duplex Mode:
725        // The internal hardware 16*4 u8 FIFO buffer (shared for read/write) is not cleared
726        // between transactions ( read/write/transfer)
727        // This can lead to re-reading the last internal buffer MOSI msg, in case the Slave fails to send a msg
728
729        let chunk_size = self.driver.borrow().max_transfer_size;
730
731        let transactions = spi_write_transactions(words, chunk_size, LineWidth::Single);
732        spi_transmit(self.handle, transactions, self.polling, self.queue_size)?;
733
734        Ok(())
735    }
736
737    #[cfg(not(esp_idf_spi_master_isr_in_iram))]
738    pub async fn write_async(&mut self, words: &[u8]) -> Result<(), EspError> {
739        let chunk_size = self.driver.borrow().max_transfer_size;
740
741        let transactions = spi_write_transactions(words, chunk_size, LineWidth::Single);
742        core::pin::pin!(spi_transmit_async(
743            self.handle,
744            transactions,
745            self.queue_size
746        ))
747        .await?;
748
749        Ok(())
750    }
751
752    pub fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), EspError> {
753        // In non-DMA mode, it will internally split the transfers every 64 bytes (max_transf_len).
754        // - If the read and write buffers are not of the same length, it will first transfer the common buffer length
755        // and then (separately aligned) the remaining buffer.
756        // - Expect a delay time between every internally split (64-byte or remainder) package.
757
758        // Half-Duplex & Half-3-Duplex Mode:
759        // Data will be split into 64-byte write/read sections.
760        // Example: write: [u8;96] - read [u8; 160]
761        // Package 1: write 64, read 64 -> Package 2: write 32, read 32 -> Package 3: write 0, read 64.
762        // Note that the first "package" is a 128-byte clock out while the later are respectively 64 bytes.
763
764        let chunk_size = self.driver.borrow().max_transfer_size;
765
766        let transactions = spi_transfer_transactions(read, write, chunk_size, self.duplex);
767        spi_transmit(self.handle, transactions, self.polling, self.queue_size)?;
768
769        Ok(())
770    }
771
772    #[cfg(not(esp_idf_spi_master_isr_in_iram))]
773    pub async fn transfer_async(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), EspError> {
774        let chunk_size = self.driver.borrow().max_transfer_size;
775
776        let transactions = spi_transfer_transactions(read, write, chunk_size, self.duplex);
777        core::pin::pin!(spi_transmit_async(
778            self.handle,
779            transactions,
780            self.queue_size
781        ))
782        .await?;
783
784        Ok(())
785    }
786
787    pub fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), EspError> {
788        let chunk_size = self.driver.borrow().max_transfer_size;
789
790        let transactions = spi_transfer_in_place_transactions(words, chunk_size);
791        spi_transmit(self.handle, transactions, self.polling, self.queue_size)?;
792
793        Ok(())
794    }
795
796    #[cfg(not(esp_idf_spi_master_isr_in_iram))]
797    pub async fn transfer_in_place_async(&mut self, words: &mut [u8]) -> Result<(), EspError> {
798        let chunk_size = self.driver.borrow().max_transfer_size;
799
800        let transactions = spi_transfer_in_place_transactions(words, chunk_size);
801        core::pin::pin!(spi_transmit_async(
802            self.handle,
803            transactions,
804            self.queue_size
805        ))
806        .await?;
807
808        Ok(())
809    }
810
811    pub fn flush(&mut self) -> Result<(), EspError> {
812        Ok(())
813    }
814
815    /// Run the provided [`Operation`] on the bus.
816    ///
817    /// Only Operations that result in a transfer are supported. For example,
818    /// passing an [`Operation::DelayNs`] will return an error.
819    pub fn operation(&mut self, operation: Operation<'_>) -> Result<(), EspError> {
820        if let Operation::DelayNs(_) = operation {
821            return Err(EspError::from_infallible::<ESP_ERR_INVALID_ARG>());
822        }
823
824        let chunk_size = self.driver.borrow().max_transfer_size;
825        let transactions = spi_operations(once(operation), chunk_size, self.duplex)
826            .filter_map(|t| t.transaction());
827
828        spi_transmit(self.handle, transactions, self.polling, self.queue_size)?;
829
830        Ok(())
831    }
832
833    /// Run the provided [`Operation`] on the bus.
834    ///
835    /// Only Operations that result in a transfer are supported. For example,
836    /// passing an [`Operation::DelayNs`] will return an error.
837    #[cfg(not(esp_idf_spi_master_isr_in_iram))]
838    pub async fn operation_async(&mut self, operation: Operation<'_>) -> Result<(), EspError> {
839        if let Operation::DelayNs(_) = operation {
840            return Err(EspError::from_infallible::<ESP_ERR_INVALID_ARG>());
841        }
842
843        let chunk_size = self.driver.borrow().max_transfer_size;
844        let transactions = spi_operations(once(operation), chunk_size, self.duplex)
845            .filter_map(|t| t.transaction());
846
847        core::pin::pin!(spi_transmit_async(
848            self.handle,
849            transactions,
850            self.queue_size
851        ))
852        .await?;
853
854        Ok(())
855    }
856}
857
858impl<'d, T> Drop for SpiBusDriver<'d, T>
859where
860    T: BorrowMut<SpiDriver<'d>>,
861{
862    fn drop(&mut self) {
863        // Need to drop the lock first, because it holds the device
864        // we are about to remove below
865        self.lock = None;
866
867        esp!(unsafe { spi_bus_remove_device(self.handle) }).unwrap();
868    }
869}
870
871impl<'d, T> embedded_hal::spi::ErrorType for SpiBusDriver<'d, T>
872where
873    T: BorrowMut<SpiDriver<'d>>,
874{
875    type Error = SpiError;
876}
877
878impl<'d, T> SpiBus for SpiBusDriver<'d, T>
879where
880    T: BorrowMut<SpiDriver<'d>>,
881{
882    fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
883        SpiBusDriver::read(self, words).map_err(to_spi_err)
884    }
885
886    fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
887        SpiBusDriver::write(self, words).map_err(to_spi_err)
888    }
889
890    fn flush(&mut self) -> Result<(), Self::Error> {
891        SpiBusDriver::flush(self).map_err(to_spi_err)
892    }
893
894    fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
895        SpiBusDriver::transfer(self, read, write).map_err(to_spi_err)
896    }
897
898    fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
899        SpiBusDriver::transfer_in_place(self, words).map_err(to_spi_err)
900    }
901}
902
903#[cfg(not(esp_idf_spi_master_isr_in_iram))]
904impl<'d, T> embedded_hal_async::spi::SpiBus for SpiBusDriver<'d, T>
905where
906    T: BorrowMut<SpiDriver<'d>>,
907{
908    async fn read(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
909        SpiBusDriver::read_async(self, buf)
910            .await
911            .map_err(to_spi_err)
912    }
913
914    async fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
915        SpiBusDriver::write_async(self, buf)
916            .await
917            .map_err(to_spi_err)
918    }
919
920    async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
921        SpiBusDriver::transfer_async(self, read, write)
922            .await
923            .map_err(to_spi_err)
924    }
925
926    async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
927        SpiBusDriver::transfer_in_place_async(self, words)
928            .await
929            .map_err(to_spi_err)
930    }
931
932    async fn flush(&mut self) -> Result<(), Self::Error> {
933        SpiBusDriver::flush(self).map_err(to_spi_err)
934    }
935}
936
937enum SpiOperation {
938    Transaction(spi_transaction_t),
939    Delay(u32),
940}
941
942impl SpiOperation {
943    pub fn transaction(self) -> Option<spi_transaction_t> {
944        if let Self::Transaction(transaction) = self {
945            Some(transaction)
946        } else {
947            None
948        }
949    }
950}
951
952pub type SpiSingleDeviceDriver<'d> = SpiDeviceDriver<'d, SpiDriver<'d>>;
953
954pub struct SpiDeviceDriver<'d, T>
955where
956    T: Borrow<SpiDriver<'d>> + 'd,
957{
958    handle: spi_device_handle_t,
959    driver: T,
960    cs_pin_configured: bool,
961    duplex: Duplex,
962    polling: bool,
963    allow_pre_post_delays: bool,
964    queue_size: usize,
965    _d: PhantomData<&'d ()>,
966}
967
968impl<'d> SpiDeviceDriver<'d, SpiDriver<'d>> {
969    #[cfg(esp32)]
970    pub fn new_single_spi1(
971        spi: SPI1<'d>,
972        sclk: crate::gpio::Gpio6<'d>,
973        sdo: crate::gpio::Gpio7<'d>,
974        sdi: Option<crate::gpio::Gpio8<'d>>,
975        cs: Option<impl OutputPin + 'd>,
976        bus_config: &config::DriverConfig,
977        config: &config::Config,
978    ) -> Result<Self, EspError> {
979        Self::new(
980            SpiDriver::new_spi1(spi, sclk, sdo, sdi, bus_config)?,
981            cs,
982            config,
983        )
984    }
985
986    pub fn new_single<SPI: SpiAnyPins + 'd>(
987        spi: SPI,
988        sclk: impl OutputPin + 'd,
989        sdo: impl OutputPin + 'd,
990        sdi: Option<impl InputPin + 'd>,
991        cs: Option<impl OutputPin + 'd>,
992        bus_config: &config::DriverConfig,
993        config: &config::Config,
994    ) -> Result<Self, EspError> {
995        Self::new(SpiDriver::new(spi, sclk, sdo, sdi, bus_config)?, cs, config)
996    }
997}
998
999impl<'d, T> SpiDeviceDriver<'d, T>
1000where
1001    T: Borrow<SpiDriver<'d>> + 'd,
1002{
1003    pub fn new(
1004        driver: T,
1005        cs: Option<impl OutputPin + 'd>,
1006        config: &config::Config,
1007    ) -> Result<Self, EspError> {
1008        let cs = cs.map(|cs| cs.pin() as _).unwrap_or(-1);
1009
1010        let mut conf: spi_device_interface_config_t = config.into();
1011        conf.spics_io_num = cs;
1012        conf.post_cb = Some(spi_notify);
1013
1014        let mut handle: spi_device_handle_t = ptr::null_mut();
1015        esp!(unsafe { spi_bus_add_device(driver.borrow().host(), &conf, &mut handle as *mut _) })?;
1016
1017        Ok(Self {
1018            handle,
1019            driver,
1020            cs_pin_configured: cs >= 0,
1021            duplex: config.duplex,
1022            polling: config.polling,
1023            allow_pre_post_delays: config.allow_pre_post_delays,
1024            queue_size: config.queue_size,
1025            _d: PhantomData,
1026        })
1027    }
1028
1029    pub fn device(&self) -> spi_device_handle_t {
1030        self.handle
1031    }
1032
1033    pub fn transaction(&mut self, operations: &mut [Operation<'_>]) -> Result<(), EspError> {
1034        self.run(
1035            self.hardware_cs_ctl(operations.iter_mut().map(copy_operation))?,
1036            operations.iter_mut().map(copy_operation),
1037        )
1038    }
1039
1040    #[cfg(not(esp_idf_spi_master_isr_in_iram))]
1041    pub async fn transaction_async(
1042        &mut self,
1043        operations: &mut [Operation<'_>],
1044    ) -> Result<(), EspError> {
1045        core::pin::pin!(self.run_async(
1046            self.hardware_cs_ctl(operations.iter_mut().map(copy_operation))?,
1047            operations.iter_mut().map(copy_operation),
1048        ))
1049        .await
1050    }
1051
1052    pub fn read(&mut self, read: &mut [u8]) -> Result<(), EspError> {
1053        self.transaction(&mut [Operation::Read(read)])
1054    }
1055
1056    #[cfg(not(esp_idf_spi_master_isr_in_iram))]
1057    pub async fn read_async(&mut self, read: &mut [u8]) -> Result<(), EspError> {
1058        let mut operation = [Operation::Read(read)];
1059        let work = core::pin::pin!(self.transaction_async(&mut operation));
1060        work.await
1061    }
1062
1063    pub fn write(&mut self, write: &[u8]) -> Result<(), EspError> {
1064        self.transaction(&mut [Operation::Write(write)])
1065    }
1066
1067    #[cfg(not(esp_idf_spi_master_isr_in_iram))]
1068    pub async fn write_async(&mut self, write: &[u8]) -> Result<(), EspError> {
1069        let mut operation = [Operation::Write(write)];
1070        let work = core::pin::pin!(self.transaction_async(&mut operation));
1071        work.await
1072    }
1073
1074    pub fn transfer_in_place(&mut self, buf: &mut [u8]) -> Result<(), EspError> {
1075        self.transaction(&mut [Operation::TransferInPlace(buf)])
1076    }
1077
1078    #[cfg(not(esp_idf_spi_master_isr_in_iram))]
1079    pub async fn transfer_in_place_async(&mut self, buf: &mut [u8]) -> Result<(), EspError> {
1080        let mut operation = [Operation::TransferInPlace(buf)];
1081        let work = core::pin::pin!(self.transaction_async(&mut operation));
1082        work.await
1083    }
1084
1085    pub fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), EspError> {
1086        self.transaction(&mut [Operation::Transfer(read, write)])
1087    }
1088
1089    #[cfg(not(esp_idf_spi_master_isr_in_iram))]
1090    pub async fn transfer_async(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), EspError> {
1091        let mut operation = [Operation::Transfer(read, write)];
1092        let work = core::pin::pin!(self.transaction_async(&mut operation));
1093        work.await
1094    }
1095
1096    fn run<'a, 'c, 'p, M>(
1097        &mut self,
1098        mut cs_pin: CsCtl<'c, 'p, M>,
1099        operations: impl Iterator<Item = Operation<'a>> + 'a,
1100    ) -> Result<(), EspError>
1101    where
1102        M: OutputMode,
1103    {
1104        let _lock = if cs_pin.needs_bus_lock() {
1105            Some(BusLock::new(self.device())?)
1106        } else {
1107            None
1108        };
1109
1110        cs_pin.raise_cs()?;
1111
1112        let mut spi_operations = self
1113            .spi_operations(operations)
1114            .enumerate()
1115            .map(|(index, mut operation)| {
1116                cs_pin.configure(&mut operation, index);
1117                operation
1118            })
1119            .peekable();
1120
1121        let delay_impl = crate::delay::Delay::new_default();
1122        let mut result = Ok(());
1123
1124        while spi_operations.peek().is_some() {
1125            if let Some(SpiOperation::Delay(delay)) = spi_operations.peek() {
1126                delay_impl.delay_us(*delay / 1000);
1127                spi_operations.next();
1128            } else {
1129                let transactions = core::iter::from_fn(|| {
1130                    spi_operations
1131                        .next_if(|operation| matches!(operation, SpiOperation::Transaction(_)))
1132                })
1133                .fuse()
1134                .filter_map(|operation| operation.transaction());
1135
1136                result = spi_transmit(self.handle, transactions, self.polling, self.queue_size);
1137
1138                if result.is_err() {
1139                    break;
1140                }
1141            }
1142        }
1143
1144        cs_pin.lower_cs()?;
1145
1146        result
1147    }
1148
1149    #[allow(dead_code)]
1150    async fn run_async<'a, 'c, 'p, M>(
1151        &self,
1152        mut cs_pin: CsCtl<'c, 'p, M>,
1153        operations: impl Iterator<Item = Operation<'a>> + 'a,
1154    ) -> Result<(), EspError>
1155    where
1156        M: OutputMode,
1157    {
1158        let _async_bus_lock = if cs_pin.needs_bus_lock() {
1159            Some(self.driver.borrow().bus_async_lock.lock().await)
1160        } else {
1161            None
1162        };
1163
1164        let _lock = if cs_pin.needs_bus_lock() {
1165            Some(BusLock::new(self.device())?)
1166        } else {
1167            None
1168        };
1169
1170        cs_pin.raise_cs()?;
1171
1172        let delay_impl = crate::delay::Delay::new_default(); // TODO: Need to wait asnchronously if in async mode
1173        let mut result = Ok(());
1174
1175        let mut spi_operations = self
1176            .spi_operations(operations)
1177            .enumerate()
1178            .map(|(index, mut operation)| {
1179                cs_pin.configure(&mut operation, index);
1180                operation
1181            })
1182            .peekable();
1183
1184        while spi_operations.peek().is_some() {
1185            if let Some(SpiOperation::Delay(delay)) = spi_operations.peek() {
1186                delay_impl.delay_us(*delay);
1187                spi_operations.next();
1188            } else {
1189                let transactions = core::iter::from_fn(|| {
1190                    spi_operations
1191                        .next_if(|operation| matches!(operation, SpiOperation::Transaction(_)))
1192                })
1193                .fuse()
1194                .filter_map(|operation| operation.transaction());
1195
1196                result = core::pin::pin!(spi_transmit_async(
1197                    self.handle,
1198                    transactions,
1199                    self.queue_size
1200                ))
1201                .await;
1202
1203                if result.is_err() {
1204                    break;
1205                }
1206            }
1207        }
1208
1209        cs_pin.lower_cs()?;
1210
1211        result
1212    }
1213
1214    fn hardware_cs_ctl<'a, 'c, 'p>(
1215        &self,
1216        operations: impl Iterator<Item = Operation<'a>> + 'a,
1217    ) -> Result<CsCtl<'c, 'p, Output>, EspError> {
1218        let (total_count, transactions_count, first_transaction, last_transaction) =
1219            self.spi_operations_stats(operations);
1220
1221        if !self.allow_pre_post_delays
1222            && self.cs_pin_configured
1223            && transactions_count > 0
1224            && (first_transaction != Some(0) || last_transaction != Some(total_count - 1))
1225        {
1226            Err(EspError::from_infallible::<ESP_ERR_INVALID_ARG>())?;
1227        }
1228
1229        Ok(CsCtl::Hardware {
1230            enabled: self.cs_pin_configured,
1231            transactions_count,
1232            last_transaction,
1233        })
1234    }
1235
1236    fn spi_operations_stats<'a>(
1237        &self,
1238        operations: impl Iterator<Item = Operation<'a>> + 'a,
1239    ) -> (usize, usize, Option<usize>, Option<usize>) {
1240        self.spi_operations(operations).enumerate().fold(
1241            (0, 0, None, None),
1242            |(total_count, transactions_count, first_transaction, last_transaction),
1243             (index, operation)| {
1244                if matches!(operation, SpiOperation::Transaction(_)) {
1245                    (
1246                        total_count + 1,
1247                        transactions_count + 1,
1248                        Some(first_transaction.unwrap_or(index)),
1249                        Some(index),
1250                    )
1251                } else {
1252                    (
1253                        total_count + 1,
1254                        transactions_count,
1255                        first_transaction,
1256                        last_transaction,
1257                    )
1258                }
1259            },
1260        )
1261    }
1262
1263    fn spi_operations<'a>(
1264        &self,
1265        operations: impl Iterator<Item = Operation<'a>> + 'a,
1266    ) -> impl Iterator<Item = SpiOperation> + 'a {
1267        let chunk_size = self.driver.borrow().max_transfer_size;
1268        let duplex = self.duplex;
1269        spi_operations(operations, chunk_size, duplex)
1270    }
1271}
1272
1273impl<'d, T> Drop for SpiDeviceDriver<'d, T>
1274where
1275    T: Borrow<SpiDriver<'d>> + 'd,
1276{
1277    fn drop(&mut self) {
1278        esp!(unsafe { spi_bus_remove_device(self.handle) }).unwrap();
1279    }
1280}
1281
1282unsafe impl<'d, T> Send for SpiDeviceDriver<'d, T> where T: Send + Borrow<SpiDriver<'d>> + 'd {}
1283
1284impl<'d, T> embedded_hal::spi::ErrorType for SpiDeviceDriver<'d, T>
1285where
1286    T: Borrow<SpiDriver<'d>> + 'd,
1287{
1288    type Error = SpiError;
1289}
1290
1291impl<'d, T> SpiDevice for SpiDeviceDriver<'d, T>
1292where
1293    T: Borrow<SpiDriver<'d>> + 'd,
1294{
1295    fn read(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
1296        Self::read(self, buf).map_err(to_spi_err)
1297    }
1298
1299    fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
1300        Self::write(self, buf).map_err(to_spi_err)
1301    }
1302
1303    fn transaction(
1304        &mut self,
1305        operations: &mut [embedded_hal::spi::Operation<'_, u8>],
1306    ) -> Result<(), Self::Error> {
1307        self.run(
1308            self.hardware_cs_ctl(operations.iter_mut().map(copy_ehal_operation))?,
1309            operations.iter_mut().map(copy_ehal_operation),
1310        )
1311        .map_err(to_spi_err)
1312    }
1313}
1314
1315impl<'d, T> embedded_hal_0_2::blocking::spi::Transfer<u8> for SpiDeviceDriver<'d, T>
1316where
1317    T: Borrow<SpiDriver<'d>> + 'd,
1318{
1319    type Error = SpiError;
1320
1321    fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
1322        self.transfer_in_place(words)?;
1323
1324        Ok(words)
1325    }
1326}
1327
1328impl<'d, T> embedded_hal_0_2::blocking::spi::Write<u8> for SpiDeviceDriver<'d, T>
1329where
1330    T: Borrow<SpiDriver<'d>> + 'd,
1331{
1332    type Error = SpiError;
1333
1334    fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
1335        self.write(words).map_err(to_spi_err)
1336    }
1337}
1338
1339/// All data is chunked into max(iter.len(), 64)
1340impl<'d, T> embedded_hal_0_2::blocking::spi::WriteIter<u8> for SpiDeviceDriver<'d, T>
1341where
1342    T: Borrow<SpiDriver<'d>> + 'd,
1343{
1344    type Error = SpiError;
1345
1346    fn write_iter<WI>(&mut self, words: WI) -> Result<(), Self::Error>
1347    where
1348        WI: IntoIterator<Item = u8>,
1349    {
1350        let mut lock = None;
1351
1352        let mut words = words.into_iter().peekable();
1353        let mut buf = [0_u8; TRANS_LEN];
1354
1355        loop {
1356            let mut offset = 0_usize;
1357
1358            while offset < buf.len() {
1359                if let Some(word) = words.next() {
1360                    buf[offset] = word;
1361                    offset += 1;
1362                } else {
1363                    break;
1364                }
1365            }
1366
1367            if offset == 0 {
1368                break;
1369            }
1370
1371            let mut transaction = spi_create_transaction(
1372                core::ptr::null_mut(),
1373                buf[..offset].as_ptr(),
1374                offset,
1375                0,
1376                LineWidth::Single,
1377            );
1378
1379            if lock.is_none() && words.peek().is_some() {
1380                lock = Some(BusLock::new(self.handle)?);
1381            }
1382
1383            set_keep_cs_active(
1384                &mut transaction,
1385                self.cs_pin_configured && words.peek().is_some(),
1386            );
1387
1388            spi_transmit(
1389                self.handle,
1390                once(transaction),
1391                self.polling,
1392                self.queue_size,
1393            )?;
1394        }
1395
1396        Ok(())
1397    }
1398}
1399
1400impl<'d, T> embedded_hal_0_2::blocking::spi::Transactional<u8> for SpiDeviceDriver<'d, T>
1401where
1402    T: Borrow<SpiDriver<'d>> + 'd,
1403{
1404    type Error = SpiError;
1405
1406    fn exec(
1407        &mut self,
1408        operations: &mut [embedded_hal_0_2::blocking::spi::Operation<'_, u8>],
1409    ) -> Result<(), Self::Error> {
1410        self.run(
1411            self.hardware_cs_ctl(operations.iter_mut().map(|op| match op {
1412                embedded_hal_0_2::blocking::spi::Operation::Write(words) => Operation::Write(words),
1413                embedded_hal_0_2::blocking::spi::Operation::Transfer(words) => {
1414                    Operation::TransferInPlace(words)
1415                }
1416            }))?,
1417            operations.iter_mut().map(|op| match op {
1418                embedded_hal_0_2::blocking::spi::Operation::Write(words) => Operation::Write(words),
1419                embedded_hal_0_2::blocking::spi::Operation::Transfer(words) => {
1420                    Operation::TransferInPlace(words)
1421                }
1422            }),
1423        )
1424        .map_err(to_spi_err)
1425    }
1426}
1427
1428#[cfg(not(esp_idf_spi_master_isr_in_iram))]
1429impl<'d, T> embedded_hal_async::spi::SpiDevice for SpiDeviceDriver<'d, T>
1430where
1431    T: Borrow<SpiDriver<'d>> + 'd,
1432{
1433    async fn read(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
1434        Self::read_async(self, buf).await.map_err(to_spi_err)
1435    }
1436
1437    async fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
1438        Self::write_async(self, buf).await.map_err(to_spi_err)
1439    }
1440
1441    async fn transaction(
1442        &mut self,
1443        operations: &mut [embedded_hal::spi::Operation<'_, u8>],
1444    ) -> Result<(), Self::Error> {
1445        core::pin::pin!(self.run_async(
1446            self.hardware_cs_ctl(operations.iter_mut().map(copy_ehal_operation))?,
1447            operations.iter_mut().map(copy_ehal_operation),
1448        ))
1449        .await
1450        .map_err(to_spi_err)
1451    }
1452}
1453
1454pub struct SpiSharedDeviceDriver<'d, T>
1455where
1456    T: Borrow<SpiDriver<'d>> + 'd,
1457{
1458    driver: UnsafeCell<SpiDeviceDriver<'d, T>>,
1459    lock: CriticalSection,
1460    #[allow(dead_code)]
1461    async_lock: Mutex<EspRawMutex, ()>,
1462}
1463
1464impl<'d, T> SpiSharedDeviceDriver<'d, T>
1465where
1466    T: Borrow<SpiDriver<'d>> + 'd,
1467{
1468    pub fn new(driver: T, config: &config::Config) -> Result<Self, EspError> {
1469        Ok(Self::wrap(SpiDeviceDriver::new(
1470            driver,
1471            Option::<AnyOutputPin>::None,
1472            config,
1473        )?))
1474    }
1475
1476    pub const fn wrap(device: SpiDeviceDriver<'d, T>) -> Self {
1477        Self {
1478            driver: UnsafeCell::new(device),
1479            lock: CriticalSection::new(),
1480            async_lock: Mutex::new(()),
1481        }
1482    }
1483
1484    pub fn lock<R>(&self, f: impl FnOnce(&mut SpiDeviceDriver<'d, T>) -> R) -> R {
1485        let _guard = self.lock.enter();
1486
1487        let device = unsafe { self.driver_mut() };
1488
1489        f(device)
1490    }
1491
1492    pub fn release(self) -> SpiDeviceDriver<'d, T> {
1493        self.driver.into_inner()
1494    }
1495
1496    #[allow(clippy::mut_from_ref)]
1497    unsafe fn driver_mut(&self) -> &mut SpiDeviceDriver<'d, T> {
1498        &mut *self.driver.get()
1499    }
1500}
1501
1502pub struct SpiSoftCsDeviceDriver<'d, DEVICE, DRIVER> {
1503    shared_device: DEVICE,
1504    cs_pin: PinDriver<'d, Output>,
1505    pre_delay_us: Option<u32>,
1506    post_delay_us: Option<u32>,
1507    _p: PhantomData<fn() -> DRIVER>,
1508}
1509
1510impl<'d, DEVICE, DRIVER> SpiSoftCsDeviceDriver<'d, DEVICE, DRIVER>
1511where
1512    DEVICE: Borrow<SpiSharedDeviceDriver<'d, DRIVER>>,
1513    DRIVER: Borrow<SpiDriver<'d>> + 'd,
1514{
1515    pub fn new(
1516        shared_device: DEVICE,
1517        cs: impl OutputPin + 'd,
1518        cs_level: Level,
1519    ) -> Result<Self, EspError> {
1520        let mut cs_pin: PinDriver<Output> = PinDriver::output(cs)?;
1521
1522        cs_pin.set_level(cs_level)?;
1523
1524        Ok(Self {
1525            shared_device,
1526            cs_pin,
1527            pre_delay_us: None,
1528            post_delay_us: None,
1529            _p: PhantomData,
1530        })
1531    }
1532
1533    /// Add an aditional Amount of SPI bit-cycles the cs should be activated before the transmission (0-16).
1534    /// This only works on half-duplex transactions.
1535    pub fn cs_pre_delay_us(&mut self, delay_us: u32) -> &mut Self {
1536        self.pre_delay_us = Some(delay_us);
1537
1538        self
1539    }
1540
1541    /// Add an aditional delay of x in uSeconds after transaction
1542    /// between last clk out and chip select
1543    pub fn cs_post_delay_us(&mut self, delay_us: u32) -> &mut Self {
1544        self.post_delay_us = Some(delay_us);
1545
1546        self
1547    }
1548
1549    pub fn transaction(&mut self, operations: &mut [Operation<'_>]) -> Result<(), EspError> {
1550        self.run(operations.iter_mut().map(copy_operation))
1551    }
1552
1553    #[cfg(not(esp_idf_spi_master_isr_in_iram))]
1554    pub async fn transaction_async(
1555        &mut self,
1556        operations: &mut [Operation<'_>],
1557    ) -> Result<(), EspError> {
1558        core::pin::pin!(self.run_async(operations.iter_mut().map(copy_operation))).await
1559    }
1560
1561    pub fn read(&mut self, read: &mut [u8]) -> Result<(), EspError> {
1562        self.transaction(&mut [Operation::Read(read)])
1563    }
1564
1565    #[cfg(not(esp_idf_spi_master_isr_in_iram))]
1566    pub async fn read_async(&mut self, read: &mut [u8]) -> Result<(), EspError> {
1567        let mut operation = [Operation::Read(read)];
1568        let work = core::pin::pin!(self.transaction_async(&mut operation));
1569        work.await
1570    }
1571
1572    pub fn write(&mut self, write: &[u8]) -> Result<(), EspError> {
1573        self.transaction(&mut [Operation::Write(write)])
1574    }
1575
1576    #[cfg(not(esp_idf_spi_master_isr_in_iram))]
1577    pub async fn write_async(&mut self, write: &[u8]) -> Result<(), EspError> {
1578        let mut operation = [Operation::Write(write)];
1579        let work = core::pin::pin!(self.transaction_async(&mut operation));
1580        work.await
1581    }
1582
1583    pub fn transfer_in_place(&mut self, buf: &mut [u8]) -> Result<(), EspError> {
1584        self.transaction(&mut [Operation::TransferInPlace(buf)])
1585    }
1586
1587    #[cfg(not(esp_idf_spi_master_isr_in_iram))]
1588    pub async fn transfer_in_place_async(&mut self, buf: &mut [u8]) -> Result<(), EspError> {
1589        let mut operation = [Operation::TransferInPlace(buf)];
1590        let work = core::pin::pin!(self.transaction_async(&mut operation));
1591        work.await
1592    }
1593
1594    pub fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), EspError> {
1595        self.transaction(&mut [Operation::Transfer(read, write)])
1596    }
1597
1598    #[cfg(not(esp_idf_spi_master_isr_in_iram))]
1599    pub async fn transfer_async(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), EspError> {
1600        let mut operation = [Operation::Transfer(read, write)];
1601        let work = core::pin::pin!(self.transaction_async(&mut operation));
1602        work.await
1603    }
1604
1605    fn run<'a>(
1606        &mut self,
1607        operations: impl Iterator<Item = Operation<'a>> + 'a,
1608    ) -> Result<(), EspError> {
1609        let cs_pin = CsCtl::Software {
1610            cs: &mut self.cs_pin,
1611            pre_delay: self.pre_delay_us,
1612            post_delay: self.post_delay_us,
1613        };
1614
1615        self.shared_device
1616            .borrow()
1617            .lock(move |device| device.run(cs_pin, operations))
1618    }
1619
1620    #[allow(dead_code)]
1621    async fn run_async<'a>(
1622        &mut self,
1623        operations: impl Iterator<Item = Operation<'a>> + 'a,
1624    ) -> Result<(), EspError> {
1625        let cs_pin = CsCtl::Software {
1626            cs: &mut self.cs_pin,
1627            pre_delay: self.pre_delay_us,
1628            post_delay: self.post_delay_us,
1629        };
1630
1631        let device = self.shared_device.borrow();
1632
1633        let _async_guard = device.async_lock.lock().await;
1634        let _guard = device.lock.enter();
1635
1636        let driver = unsafe { device.driver_mut() };
1637
1638        driver.run_async(cs_pin, operations).await
1639    }
1640}
1641
1642impl<'d, DEVICE, DRIVER> embedded_hal::spi::ErrorType for SpiSoftCsDeviceDriver<'d, DEVICE, DRIVER>
1643where
1644    DEVICE: Borrow<SpiSharedDeviceDriver<'d, DRIVER>> + 'd,
1645    DRIVER: Borrow<SpiDriver<'d>> + 'd,
1646{
1647    type Error = SpiError;
1648}
1649
1650impl<'d, DEVICE, DRIVER> SpiDevice for SpiSoftCsDeviceDriver<'d, DEVICE, DRIVER>
1651where
1652    DEVICE: Borrow<SpiSharedDeviceDriver<'d, DRIVER>> + 'd,
1653    DRIVER: Borrow<SpiDriver<'d>> + 'd,
1654{
1655    fn read(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
1656        Self::read(self, buf).map_err(to_spi_err)
1657    }
1658
1659    fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
1660        Self::write(self, buf).map_err(to_spi_err)
1661    }
1662
1663    fn transaction(
1664        &mut self,
1665        operations: &mut [embedded_hal::spi::Operation<'_, u8>],
1666    ) -> Result<(), Self::Error> {
1667        self.run(operations.iter_mut().map(copy_ehal_operation))
1668            .map_err(to_spi_err)
1669    }
1670}
1671
1672#[cfg(not(esp_idf_spi_master_isr_in_iram))]
1673impl<'d, DEVICE, DRIVER> embedded_hal_async::spi::SpiDevice
1674    for SpiSoftCsDeviceDriver<'d, DEVICE, DRIVER>
1675where
1676    DEVICE: Borrow<SpiSharedDeviceDriver<'d, DRIVER>> + 'd,
1677    DRIVER: Borrow<SpiDriver<'d>> + 'd,
1678{
1679    async fn read(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
1680        Self::read_async(self, buf).await.map_err(to_spi_err)
1681    }
1682
1683    async fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
1684        Self::write_async(self, buf).await.map_err(to_spi_err)
1685    }
1686
1687    async fn transaction(
1688        &mut self,
1689        operations: &mut [embedded_hal::spi::Operation<'_, u8>],
1690    ) -> Result<(), Self::Error> {
1691        core::pin::pin!(self.run_async(operations.iter_mut().map(copy_ehal_operation)))
1692            .await
1693            .map_err(to_spi_err)
1694    }
1695}
1696
1697fn to_spi_err(err: EspError) -> SpiError {
1698    SpiError::other(err)
1699}
1700
1701// Limit to 64, as we sometimes allocate a buffer of size TRANS_LEN on the stack, so we have to keep it small
1702// SOC_SPI_MAXIMUM_BUFFER_SIZE equals 64 or 72 (esp32s2) anyway
1703const TRANS_LEN: usize = if SOC_SPI_MAXIMUM_BUFFER_SIZE < 64_u32 {
1704    SOC_SPI_MAXIMUM_BUFFER_SIZE as _
1705} else {
1706    64_usize
1707};
1708
1709// Whilst ESP-IDF doesn't have a documented maximum for queued transactions, we need a compile time
1710// max to be able to place the transactions on the stack (without recursion hacks) and not be
1711// forced to use box. Perhaps this is something the user can inject in, via generics or slice.
1712// This means a spi_device_interface_config_t.queue_size higher than this constant will be clamped
1713// down in practice.
1714const MAX_QUEUED_TRANSACTIONS: usize = 6;
1715
1716struct BusLock(spi_device_handle_t);
1717
1718impl BusLock {
1719    fn new(device: spi_device_handle_t) -> Result<Self, EspError> {
1720        esp!(unsafe { spi_device_acquire_bus(device, BLOCK) })?;
1721
1722        Ok(Self(device))
1723    }
1724}
1725
1726impl Drop for BusLock {
1727    fn drop(&mut self) {
1728        unsafe {
1729            spi_device_release_bus(self.0);
1730        }
1731    }
1732}
1733
1734enum CsCtl<'c, 'p, M>
1735where
1736    M: OutputMode,
1737{
1738    Hardware {
1739        enabled: bool,
1740        transactions_count: usize,
1741        last_transaction: Option<usize>,
1742    },
1743    Software {
1744        cs: &'c mut PinDriver<'p, M>,
1745        pre_delay: Option<u32>,
1746        post_delay: Option<u32>,
1747    },
1748}
1749
1750impl<M> CsCtl<'_, '_, M>
1751where
1752    M: OutputMode,
1753{
1754    fn needs_bus_lock(&self) -> bool {
1755        match self {
1756            Self::Hardware {
1757                transactions_count, ..
1758            } => *transactions_count > 1,
1759            Self::Software { .. } => true,
1760        }
1761    }
1762
1763    fn raise_cs(&mut self) -> Result<(), EspError> {
1764        if let CsCtl::Software { cs, pre_delay, .. } = self {
1765            cs.toggle()?;
1766
1767            // TODO: Need to wait asnchronously if in async mode
1768            if let Some(delay) = pre_delay {
1769                Ets::delay_us(*delay);
1770            }
1771        }
1772
1773        Ok(())
1774    }
1775
1776    fn lower_cs(&mut self) -> Result<(), EspError> {
1777        if let CsCtl::Software { cs, post_delay, .. } = self {
1778            cs.toggle()?;
1779
1780            // TODO: Need to wait asnchronously if in async mode
1781            if let Some(delay) = post_delay {
1782                Ets::delay_us(*delay);
1783            }
1784        }
1785
1786        Ok(())
1787    }
1788
1789    fn configure(&self, operation: &mut SpiOperation, index: usize) {
1790        if let SpiOperation::Transaction(transaction) = operation {
1791            self.configure_transaction(transaction, index)
1792        }
1793    }
1794
1795    fn configure_transaction(&self, transaction: &mut spi_transaction_t, index: usize) {
1796        if let Self::Hardware {
1797            enabled,
1798            last_transaction,
1799            ..
1800        } = self
1801        {
1802            set_keep_cs_active(transaction, *enabled && Some(index) != *last_transaction);
1803        }
1804    }
1805}
1806
1807fn spi_operations<'a>(
1808    operations: impl Iterator<Item = Operation<'a>> + 'a,
1809    chunk_size: usize,
1810    duplex: Duplex,
1811) -> impl Iterator<Item = SpiOperation> + 'a {
1812    enum OperationsIter<R, W, T, I, D> {
1813        Read(R),
1814        Write(W),
1815        Transfer(T),
1816        TransferInPlace(I),
1817        Delay(D),
1818    }
1819
1820    impl<R, W, T, I, D> Iterator for OperationsIter<R, W, T, I, D>
1821    where
1822        R: Iterator<Item = SpiOperation>,
1823        W: Iterator<Item = SpiOperation>,
1824        T: Iterator<Item = SpiOperation>,
1825        I: Iterator<Item = SpiOperation>,
1826        D: Iterator<Item = SpiOperation>,
1827    {
1828        type Item = SpiOperation;
1829
1830        fn next(&mut self) -> Option<Self::Item> {
1831            match self {
1832                Self::Read(iter) => iter.next(),
1833                Self::Write(iter) => iter.next(),
1834                Self::Transfer(iter) => iter.next(),
1835                Self::TransferInPlace(iter) => iter.next(),
1836                Self::Delay(iter) => iter.next(),
1837            }
1838        }
1839    }
1840
1841    operations.flat_map(move |op| match op {
1842        Operation::Read(words) => OperationsIter::Read(
1843            spi_read_transactions(words, chunk_size, duplex, LineWidth::Single)
1844                .map(SpiOperation::Transaction),
1845        ),
1846        Operation::ReadWithWidth(words, line_width) => OperationsIter::Read(
1847            spi_read_transactions(words, chunk_size, duplex, line_width)
1848                .map(SpiOperation::Transaction),
1849        ),
1850        Operation::Write(words) => OperationsIter::Write(
1851            spi_write_transactions(words, chunk_size, LineWidth::Single)
1852                .map(SpiOperation::Transaction),
1853        ),
1854        Operation::WriteWithWidth(words, line_width) => OperationsIter::Write(
1855            spi_write_transactions(words, chunk_size, line_width).map(SpiOperation::Transaction),
1856        ),
1857        Operation::Transfer(read, write) => OperationsIter::Transfer(
1858            spi_transfer_transactions(read, write, chunk_size, duplex)
1859                .map(SpiOperation::Transaction),
1860        ),
1861        Operation::TransferInPlace(words) => OperationsIter::TransferInPlace(
1862            spi_transfer_in_place_transactions(words, chunk_size).map(SpiOperation::Transaction),
1863        ),
1864        Operation::DelayNs(delay) => {
1865            OperationsIter::Delay(core::iter::once(SpiOperation::Delay(delay)))
1866        }
1867    })
1868}
1869
1870fn spi_read_transactions(
1871    words: &mut [u8],
1872    chunk_size: usize,
1873    duplex: Duplex,
1874    line_width: LineWidth,
1875) -> impl Iterator<Item = spi_transaction_t> + '_ {
1876    words.chunks_mut(chunk_size).map(move |chunk| {
1877        spi_create_transaction(
1878            chunk.as_mut_ptr(),
1879            core::ptr::null(),
1880            if duplex == Duplex::Full {
1881                chunk.len()
1882            } else {
1883                0
1884            },
1885            chunk.len(),
1886            line_width,
1887        )
1888    })
1889}
1890
1891fn spi_write_transactions(
1892    words: &[u8],
1893    chunk_size: usize,
1894    line_width: LineWidth,
1895) -> impl Iterator<Item = spi_transaction_t> + '_ {
1896    words.chunks(chunk_size).map(move |chunk| {
1897        spi_create_transaction(
1898            core::ptr::null_mut(),
1899            chunk.as_ptr(),
1900            chunk.len(),
1901            0,
1902            line_width,
1903        )
1904    })
1905}
1906
1907fn spi_transfer_in_place_transactions(
1908    words: &mut [u8],
1909    chunk_size: usize,
1910) -> impl Iterator<Item = spi_transaction_t> + '_ {
1911    words.chunks_mut(chunk_size).map(|chunk| {
1912        spi_create_transaction(
1913            chunk.as_mut_ptr(),
1914            chunk.as_mut_ptr(),
1915            chunk.len(),
1916            chunk.len(),
1917            LineWidth::Single,
1918        )
1919    })
1920}
1921
1922fn spi_transfer_transactions<'a>(
1923    read: &'a mut [u8],
1924    write: &'a [u8],
1925    chunk_size: usize,
1926    duplex: Duplex,
1927) -> impl Iterator<Item = spi_transaction_t> + 'a {
1928    enum OperationsIter<E, R, W> {
1929        Equal(E),
1930        ReadLonger(R),
1931        WriteLonger(W),
1932    }
1933
1934    impl<E, R, W> Iterator for OperationsIter<E, R, W>
1935    where
1936        E: Iterator<Item = spi_transaction_t>,
1937        R: Iterator<Item = spi_transaction_t>,
1938        W: Iterator<Item = spi_transaction_t>,
1939    {
1940        type Item = spi_transaction_t;
1941
1942        fn next(&mut self) -> Option<Self::Item> {
1943            match self {
1944                Self::Equal(iter) => iter.next(),
1945                Self::ReadLonger(iter) => iter.next(),
1946                Self::WriteLonger(iter) => iter.next(),
1947            }
1948        }
1949    }
1950
1951    match read.len().cmp(&write.len()) {
1952        Ordering::Equal => {
1953            OperationsIter::Equal(spi_transfer_equal_transactions(read, write, chunk_size))
1954        }
1955        Ordering::Greater => {
1956            let (read, read_trail) = read.split_at_mut(write.len());
1957
1958            OperationsIter::ReadLonger(
1959                spi_transfer_equal_transactions(read, write, chunk_size).chain(
1960                    spi_read_transactions(read_trail, chunk_size, duplex, LineWidth::Single),
1961                ),
1962            )
1963        }
1964        Ordering::Less => {
1965            let (write, write_trail) = write.split_at(read.len());
1966
1967            OperationsIter::WriteLonger(
1968                spi_transfer_equal_transactions(read, write, chunk_size).chain(
1969                    spi_write_transactions(write_trail, chunk_size, LineWidth::Single),
1970                ),
1971            )
1972        }
1973    }
1974}
1975
1976fn spi_transfer_equal_transactions<'a>(
1977    read: &'a mut [u8],
1978    write: &'a [u8],
1979    chunk_size: usize,
1980) -> impl Iterator<Item = spi_transaction_t> + 'a {
1981    read.chunks_mut(chunk_size)
1982        .zip(write.chunks(chunk_size))
1983        .map(|(read_chunk, write_chunk)| {
1984            spi_create_transaction(
1985                read_chunk.as_mut_ptr(),
1986                write_chunk.as_ptr(),
1987                max(read_chunk.len(), write_chunk.len()),
1988                read_chunk.len(),
1989                LineWidth::Single,
1990            )
1991        })
1992}
1993
1994// These parameters assume full duplex.
1995fn spi_create_transaction(
1996    read: *mut u8,
1997    write: *const u8,
1998    transaction_length: usize,
1999    rx_length: usize,
2000    line_width: LineWidth,
2001) -> spi_transaction_t {
2002    let flags = match line_width {
2003        LineWidth::Single => 0,
2004        LineWidth::Dual => SPI_TRANS_MODE_DIO,
2005        LineWidth::Quad => SPI_TRANS_MODE_QIO,
2006    };
2007    spi_transaction_t {
2008        flags,
2009        __bindgen_anon_1: spi_transaction_t__bindgen_ty_1 {
2010            tx_buffer: write as *const _,
2011        },
2012        __bindgen_anon_2: spi_transaction_t__bindgen_ty_2 {
2013            rx_buffer: read as *mut _,
2014        },
2015        length: (transaction_length * 8) as _,
2016        rxlength: (rx_length * 8) as _,
2017        ..Default::default()
2018    }
2019}
2020
2021fn set_keep_cs_active(transaction: &mut spi_transaction_t, _keep_cs_active: bool) {
2022    if _keep_cs_active {
2023        transaction.flags |= SPI_TRANS_CS_KEEP_ACTIVE
2024    }
2025}
2026
2027fn spi_transmit(
2028    handle: spi_device_handle_t,
2029    transactions: impl Iterator<Item = spi_transaction_t>,
2030    polling: bool,
2031    queue_size: usize,
2032) -> Result<(), EspError> {
2033    if polling {
2034        for mut transaction in transactions {
2035            esp!(unsafe { spi_device_polling_transmit(handle, &mut transaction as *mut _) })?;
2036        }
2037    } else {
2038        pub type Queue = Deque<spi_transaction_t, MAX_QUEUED_TRANSACTIONS>;
2039
2040        let mut queue = Queue::new();
2041        let queue_size = min(MAX_QUEUED_TRANSACTIONS, queue_size);
2042
2043        let push = |queue: &mut Queue, transaction| {
2044            let _ = queue.push_back(transaction);
2045            esp!(unsafe { spi_device_queue_trans(handle, queue.back_mut().unwrap(), delay::BLOCK) })
2046        };
2047
2048        let pop = |queue: &mut Queue| {
2049            let mut rtrans = ptr::null_mut();
2050            esp!(unsafe { spi_device_get_trans_result(handle, &mut rtrans, delay::BLOCK) })?;
2051
2052            if rtrans != queue.front_mut().unwrap() {
2053                unreachable!();
2054            }
2055            queue.pop_front().unwrap();
2056
2057            Ok(())
2058        };
2059
2060        let pop_all = |queue: &mut Queue| {
2061            while !queue.is_empty() {
2062                pop(queue)?;
2063            }
2064
2065            Ok(())
2066        };
2067
2068        for transaction in transactions {
2069            if queue.len() == queue_size {
2070                // If the queue is full, we wait for the first transaction in the queue
2071                pop(&mut queue)?;
2072            }
2073
2074            // Write transaction to a stable memory location
2075            push(&mut queue, transaction)?;
2076        }
2077
2078        pop_all(&mut queue)?;
2079    }
2080
2081    Ok(())
2082}
2083
2084#[allow(dead_code)]
2085async fn spi_transmit_async(
2086    handle: spi_device_handle_t,
2087    transactions: impl Iterator<Item = spi_transaction_t>,
2088    queue_size: usize,
2089) -> Result<(), EspError> {
2090    pub type Queue = Deque<(spi_transaction_t, HalIsrNotification), MAX_QUEUED_TRANSACTIONS>;
2091
2092    let mut queue = Queue::new();
2093    let queue = &mut queue;
2094
2095    let queue_size = min(MAX_QUEUED_TRANSACTIONS, queue_size);
2096    let queued = Cell::new(0_usize);
2097
2098    let fut = &mut core::pin::pin!(async {
2099        let push = |queue: &mut Queue, transaction| {
2100            queue
2101                .push_back((transaction, HalIsrNotification::new()))
2102                .map_err(|_| EspError::from_infallible::<{ ESP_ERR_INVALID_STATE }>())?;
2103            queued.set(queue.len());
2104
2105            let last = queue.back_mut().unwrap();
2106            last.0.user = &last.1 as *const _ as *mut _;
2107            match esp!(unsafe { spi_device_queue_trans(handle, &mut last.0, delay::BLOCK) }) {
2108                Err(e) if e.code() == ESP_ERR_TIMEOUT => unreachable!(),
2109                other => other,
2110            }
2111        };
2112
2113        let pop = |queue: &mut Queue| {
2114            let mut rtrans = ptr::null_mut();
2115            match esp!(unsafe {
2116                spi_device_get_trans_result(handle, &mut rtrans, delay::NON_BLOCK)
2117            }) {
2118                Err(e) if e.code() == ESP_ERR_TIMEOUT => return Ok(false),
2119                Err(e) => Err(e)?,
2120                Ok(()) => (),
2121            };
2122
2123            if rtrans != &mut queue.front_mut().unwrap().0 {
2124                unreachable!();
2125            }
2126
2127            queue.pop_front().unwrap();
2128            queued.set(queue.len());
2129
2130            Ok(true)
2131        };
2132
2133        for transaction in transactions {
2134            while queue.len() == queue_size {
2135                if pop(queue)? {
2136                    break;
2137                }
2138
2139                // If the queue is full, we wait for the first transaction in the queue
2140                queue.front_mut().unwrap().1.wait().await;
2141            }
2142
2143            // Write transaction to a stable memory location
2144            push(queue, transaction)?;
2145        }
2146
2147        while !queue.is_empty() {
2148            if !pop(queue)? {
2149                queue.front_mut().unwrap().1.wait().await;
2150            }
2151        }
2152
2153        Ok(())
2154    });
2155
2156    with_completion(fut, |completed| {
2157        if !completed {
2158            for _ in 0..queued.get() {
2159                let mut rtrans = ptr::null_mut();
2160                esp!(unsafe { spi_device_get_trans_result(handle, &mut rtrans, delay::BLOCK) })
2161                    .unwrap();
2162            }
2163        }
2164    })
2165    .await
2166}
2167
2168extern "C" fn spi_notify(transaction: *mut spi_transaction_t) {
2169    if let Some(transaction) = unsafe { transaction.as_ref() } {
2170        if let Some(notification) = unsafe {
2171            (transaction.user as *mut HalIsrNotification as *const HalIsrNotification).as_ref()
2172        } {
2173            notification.notify_lsb();
2174        }
2175    }
2176}
2177
2178fn copy_operation<'b>(operation: &'b mut Operation<'_>) -> Operation<'b> {
2179    match operation {
2180        Operation::Read(read) => Operation::Read(read),
2181        Operation::ReadWithWidth(read, line_width) => Operation::ReadWithWidth(read, *line_width),
2182        Operation::Write(write) => Operation::Write(write),
2183        Operation::WriteWithWidth(write, line_width) => {
2184            Operation::WriteWithWidth(write, *line_width)
2185        }
2186        Operation::Transfer(read, write) => Operation::Transfer(read, write),
2187        Operation::TransferInPlace(write) => Operation::TransferInPlace(write),
2188        Operation::DelayNs(delay) => Operation::DelayNs(*delay),
2189    }
2190}
2191
2192fn copy_ehal_operation<'b>(
2193    operation: &'b mut embedded_hal::spi::Operation<'_, u8>,
2194) -> Operation<'b> {
2195    match operation {
2196        embedded_hal::spi::Operation::Read(read) => Operation::Read(read),
2197        embedded_hal::spi::Operation::Write(write) => Operation::Write(write),
2198        embedded_hal::spi::Operation::Transfer(read, write) => Operation::Transfer(read, write),
2199        embedded_hal::spi::Operation::TransferInPlace(write) => Operation::TransferInPlace(write),
2200        embedded_hal::spi::Operation::DelayNs(delay) => Operation::DelayNs(*delay),
2201    }
2202}
2203
2204#[allow(dead_code)]
2205async fn with_completion<F, D>(fut: F, dtor: D) -> F::Output
2206where
2207    F: Future,
2208    D: FnMut(bool),
2209{
2210    struct Completion<D>
2211    where
2212        D: FnMut(bool),
2213    {
2214        dtor: D,
2215        completed: bool,
2216    }
2217
2218    impl<D> Drop for Completion<D>
2219    where
2220        D: FnMut(bool),
2221    {
2222        fn drop(&mut self) {
2223            (self.dtor)(self.completed);
2224        }
2225    }
2226
2227    let mut completion = Completion {
2228        dtor,
2229        completed: false,
2230    };
2231
2232    let result = fut.await;
2233
2234    completion.completed = true;
2235
2236    result
2237}
2238
2239macro_rules! impl_spi {
2240    ($spi:ident: $device:expr) => {
2241        crate::impl_peripheral!($spi);
2242
2243        impl Spi for $spi<'_> {
2244            #[inline(always)]
2245            fn device() -> spi_host_device_t {
2246                $device
2247            }
2248        }
2249    };
2250}
2251
2252macro_rules! impl_spi_any_pins {
2253    ($spi:ident) => {
2254        impl SpiAnyPins for $spi<'_> {}
2255    };
2256}
2257
2258impl_spi!(SPI1: spi_host_device_t_SPI1_HOST);
2259impl_spi!(SPI2: spi_host_device_t_SPI2_HOST);
2260#[cfg(any(esp32, esp32s2, esp32s3))]
2261impl_spi!(SPI3: spi_host_device_t_SPI3_HOST);
2262
2263impl_spi_any_pins!(SPI2);
2264#[cfg(any(esp32, esp32s2, esp32s3))]
2265impl_spi_any_pins!(SPI3);