1use 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
69pub 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
109pub 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 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
154 pub enum Duplex {
155 Full,
157 Half,
159 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 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
175 pub enum BitOrder {
176 MsbFirst,
178 LsbFirst,
180 TxLsbFirst,
182 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 Single,
201 Dual,
203 Quad,
205 }
206
207 #[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 #[derive(Debug, Clone)]
243 pub struct Config {
244 pub baudrate: Hertz,
245 pub data_mode: Mode,
246 pub write_only: bool,
251 pub duplex: Duplex,
252 pub bit_order: BitOrder,
253 pub cs_active_high: bool,
254 pub cs_pre_delay_us: Option<u16>, pub cs_post_delay_us: Option<u8>, 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 #[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 #[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#[non_exhaustive]
400#[derive(Debug, PartialEq, Eq)]
401pub enum Operation<'a> {
402 Read(&'a mut [u8]),
404 ReadWithWidth(&'a mut [u8], LineWidth),
406 Write(&'a [u8]),
408 WriteWithWidth(&'a [u8], LineWidth),
411 Transfer(&'a mut [u8], &'a [u8]),
413 TransferInPlace(&'a mut [u8]),
415 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 #[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 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 },
591 __bindgen_anon_2: spi_bus_config_t__bindgen_ty_2 {
592 miso_io_num: sdi.unwrap_or(-1),
593 },
595 __bindgen_anon_3: spi_bus_config_t__bindgen_ty_3 {
596 quadwp_io_num: data2.unwrap_or(-1),
597 },
599 __bindgen_anon_4: spi_bus_config_t__bindgen_ty_4 {
600 quadhd_io_num: data3.unwrap_or(-1),
601 },
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 },
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 },
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 },
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 },
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 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 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 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 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 #[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 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(); 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
1339impl<'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 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 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
1701const 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
1709const 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 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 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
1994fn 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 pop(&mut queue)?;
2072 }
2073
2074 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 queue.front_mut().unwrap().1.wait().await;
2141 }
2142
2143 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);