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 = match BusLock::new(handle) {
687 Ok(lock) => lock,
688 Err(err) => {
689 esp!(unsafe { spi_bus_remove_device(handle) }).unwrap();
692
693 return Err(err);
694 }
695 };
696
697 Ok(Self {
698 lock: Some(lock),
699 handle,
700 driver,
701 duplex: config.duplex,
702 polling: config.polling,
703 queue_size: config.queue_size,
704 _d: PhantomData,
705 })
706 }
707
708 pub fn read(&mut self, words: &mut [u8]) -> Result<(), EspError> {
709 let chunk_size = self.driver.borrow().max_transfer_size;
715
716 let transactions = spi_read_transactions(words, chunk_size, self.duplex, LineWidth::Single);
717 spi_transmit(self.handle, transactions, self.polling, self.queue_size)?;
718
719 Ok(())
720 }
721
722 #[cfg(not(esp_idf_spi_master_isr_in_iram))]
723 pub async fn read_async(&mut self, words: &mut [u8]) -> Result<(), EspError> {
724 let chunk_size = self.driver.borrow().max_transfer_size;
725
726 let transactions = spi_read_transactions(words, chunk_size, self.duplex, LineWidth::Single);
727 core::pin::pin!(spi_transmit_async(
728 self.handle,
729 transactions,
730 self.queue_size
731 ))
732 .await?;
733
734 Ok(())
735 }
736
737 pub fn write(&mut self, words: &[u8]) -> Result<(), EspError> {
738 let chunk_size = self.driver.borrow().max_transfer_size;
744
745 let transactions = spi_write_transactions(words, chunk_size, LineWidth::Single);
746 spi_transmit(self.handle, transactions, self.polling, self.queue_size)?;
747
748 Ok(())
749 }
750
751 #[cfg(not(esp_idf_spi_master_isr_in_iram))]
752 pub async fn write_async(&mut self, words: &[u8]) -> Result<(), EspError> {
753 let chunk_size = self.driver.borrow().max_transfer_size;
754
755 let transactions = spi_write_transactions(words, chunk_size, LineWidth::Single);
756 core::pin::pin!(spi_transmit_async(
757 self.handle,
758 transactions,
759 self.queue_size
760 ))
761 .await?;
762
763 Ok(())
764 }
765
766 pub fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), EspError> {
767 let chunk_size = self.driver.borrow().max_transfer_size;
779
780 let transactions = spi_transfer_transactions(read, write, chunk_size, self.duplex);
781 spi_transmit(self.handle, transactions, self.polling, self.queue_size)?;
782
783 Ok(())
784 }
785
786 #[cfg(not(esp_idf_spi_master_isr_in_iram))]
787 pub async fn transfer_async(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), EspError> {
788 let chunk_size = self.driver.borrow().max_transfer_size;
789
790 let transactions = spi_transfer_transactions(read, write, chunk_size, self.duplex);
791 core::pin::pin!(spi_transmit_async(
792 self.handle,
793 transactions,
794 self.queue_size
795 ))
796 .await?;
797
798 Ok(())
799 }
800
801 pub fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), EspError> {
802 let chunk_size = self.driver.borrow().max_transfer_size;
803
804 let transactions = spi_transfer_in_place_transactions(words, chunk_size);
805 spi_transmit(self.handle, transactions, self.polling, self.queue_size)?;
806
807 Ok(())
808 }
809
810 #[cfg(not(esp_idf_spi_master_isr_in_iram))]
811 pub async fn transfer_in_place_async(&mut self, words: &mut [u8]) -> Result<(), EspError> {
812 let chunk_size = self.driver.borrow().max_transfer_size;
813
814 let transactions = spi_transfer_in_place_transactions(words, chunk_size);
815 core::pin::pin!(spi_transmit_async(
816 self.handle,
817 transactions,
818 self.queue_size
819 ))
820 .await?;
821
822 Ok(())
823 }
824
825 pub fn flush(&mut self) -> Result<(), EspError> {
826 Ok(())
827 }
828
829 pub fn operation(&mut self, operation: Operation<'_>) -> Result<(), EspError> {
834 if let Operation::DelayNs(_) = operation {
835 return Err(EspError::from_infallible::<ESP_ERR_INVALID_ARG>());
836 }
837
838 let chunk_size = self.driver.borrow().max_transfer_size;
839 let transactions = spi_operations(once(operation), chunk_size, self.duplex)
840 .filter_map(|t| t.transaction());
841
842 spi_transmit(self.handle, transactions, self.polling, self.queue_size)?;
843
844 Ok(())
845 }
846
847 #[cfg(not(esp_idf_spi_master_isr_in_iram))]
852 pub async fn operation_async(&mut self, operation: Operation<'_>) -> Result<(), EspError> {
853 if let Operation::DelayNs(_) = operation {
854 return Err(EspError::from_infallible::<ESP_ERR_INVALID_ARG>());
855 }
856
857 let chunk_size = self.driver.borrow().max_transfer_size;
858 let transactions = spi_operations(once(operation), chunk_size, self.duplex)
859 .filter_map(|t| t.transaction());
860
861 core::pin::pin!(spi_transmit_async(
862 self.handle,
863 transactions,
864 self.queue_size
865 ))
866 .await?;
867
868 Ok(())
869 }
870}
871
872impl<'d, T> Drop for SpiBusDriver<'d, T>
873where
874 T: BorrowMut<SpiDriver<'d>>,
875{
876 fn drop(&mut self) {
877 self.lock = None;
880
881 esp!(unsafe { spi_bus_remove_device(self.handle) }).unwrap();
882 }
883}
884
885impl<'d, T> embedded_hal::spi::ErrorType for SpiBusDriver<'d, T>
886where
887 T: BorrowMut<SpiDriver<'d>>,
888{
889 type Error = SpiError;
890}
891
892impl<'d, T> SpiBus for SpiBusDriver<'d, T>
893where
894 T: BorrowMut<SpiDriver<'d>>,
895{
896 fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
897 SpiBusDriver::read(self, words).map_err(to_spi_err)
898 }
899
900 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
901 SpiBusDriver::write(self, words).map_err(to_spi_err)
902 }
903
904 fn flush(&mut self) -> Result<(), Self::Error> {
905 SpiBusDriver::flush(self).map_err(to_spi_err)
906 }
907
908 fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
909 SpiBusDriver::transfer(self, read, write).map_err(to_spi_err)
910 }
911
912 fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
913 SpiBusDriver::transfer_in_place(self, words).map_err(to_spi_err)
914 }
915}
916
917#[cfg(not(esp_idf_spi_master_isr_in_iram))]
918impl<'d, T> embedded_hal_async::spi::SpiBus for SpiBusDriver<'d, T>
919where
920 T: BorrowMut<SpiDriver<'d>>,
921{
922 async fn read(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
923 SpiBusDriver::read_async(self, buf)
924 .await
925 .map_err(to_spi_err)
926 }
927
928 async fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
929 SpiBusDriver::write_async(self, buf)
930 .await
931 .map_err(to_spi_err)
932 }
933
934 async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
935 SpiBusDriver::transfer_async(self, read, write)
936 .await
937 .map_err(to_spi_err)
938 }
939
940 async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
941 SpiBusDriver::transfer_in_place_async(self, words)
942 .await
943 .map_err(to_spi_err)
944 }
945
946 async fn flush(&mut self) -> Result<(), Self::Error> {
947 SpiBusDriver::flush(self).map_err(to_spi_err)
948 }
949}
950
951enum SpiOperation {
952 Transaction(spi_transaction_t),
953 Delay(u32),
954}
955
956impl SpiOperation {
957 pub fn transaction(self) -> Option<spi_transaction_t> {
958 if let Self::Transaction(transaction) = self {
959 Some(transaction)
960 } else {
961 None
962 }
963 }
964}
965
966pub type SpiSingleDeviceDriver<'d> = SpiDeviceDriver<'d, SpiDriver<'d>>;
967
968pub struct SpiDeviceDriver<'d, T>
969where
970 T: Borrow<SpiDriver<'d>> + 'd,
971{
972 handle: spi_device_handle_t,
973 driver: T,
974 cs_pin_configured: bool,
975 duplex: Duplex,
976 polling: bool,
977 allow_pre_post_delays: bool,
978 queue_size: usize,
979 _d: PhantomData<&'d ()>,
980}
981
982impl<'d> SpiDeviceDriver<'d, SpiDriver<'d>> {
983 #[cfg(esp32)]
984 pub fn new_single_spi1(
985 spi: SPI1<'d>,
986 sclk: crate::gpio::Gpio6<'d>,
987 sdo: crate::gpio::Gpio7<'d>,
988 sdi: Option<crate::gpio::Gpio8<'d>>,
989 cs: Option<impl OutputPin + 'd>,
990 bus_config: &config::DriverConfig,
991 config: &config::Config,
992 ) -> Result<Self, EspError> {
993 Self::new(
994 SpiDriver::new_spi1(spi, sclk, sdo, sdi, bus_config)?,
995 cs,
996 config,
997 )
998 }
999
1000 pub fn new_single<SPI: SpiAnyPins + 'd>(
1001 spi: SPI,
1002 sclk: impl OutputPin + 'd,
1003 sdo: impl OutputPin + 'd,
1004 sdi: Option<impl InputPin + 'd>,
1005 cs: Option<impl OutputPin + 'd>,
1006 bus_config: &config::DriverConfig,
1007 config: &config::Config,
1008 ) -> Result<Self, EspError> {
1009 Self::new(SpiDriver::new(spi, sclk, sdo, sdi, bus_config)?, cs, config)
1010 }
1011}
1012
1013impl<'d, T> SpiDeviceDriver<'d, T>
1014where
1015 T: Borrow<SpiDriver<'d>> + 'd,
1016{
1017 pub fn new(
1018 driver: T,
1019 cs: Option<impl OutputPin + 'd>,
1020 config: &config::Config,
1021 ) -> Result<Self, EspError> {
1022 let cs = cs.map(|cs| cs.pin() as _).unwrap_or(-1);
1023
1024 let mut conf: spi_device_interface_config_t = config.into();
1025 conf.spics_io_num = cs;
1026 conf.post_cb = Some(spi_notify);
1027
1028 let mut handle: spi_device_handle_t = ptr::null_mut();
1029 esp!(unsafe { spi_bus_add_device(driver.borrow().host(), &conf, &mut handle as *mut _) })?;
1030
1031 Ok(Self {
1032 handle,
1033 driver,
1034 cs_pin_configured: cs >= 0,
1035 duplex: config.duplex,
1036 polling: config.polling,
1037 allow_pre_post_delays: config.allow_pre_post_delays,
1038 queue_size: config.queue_size,
1039 _d: PhantomData,
1040 })
1041 }
1042
1043 pub fn device(&self) -> spi_device_handle_t {
1044 self.handle
1045 }
1046
1047 pub fn transaction(&mut self, operations: &mut [Operation<'_>]) -> Result<(), EspError> {
1048 self.run(
1049 self.hardware_cs_ctl(operations.iter_mut().map(copy_operation))?,
1050 operations.iter_mut().map(copy_operation),
1051 )
1052 }
1053
1054 #[cfg(not(esp_idf_spi_master_isr_in_iram))]
1055 pub async fn transaction_async(
1056 &mut self,
1057 operations: &mut [Operation<'_>],
1058 ) -> Result<(), EspError> {
1059 core::pin::pin!(self.run_async(
1060 self.hardware_cs_ctl(operations.iter_mut().map(copy_operation))?,
1061 operations.iter_mut().map(copy_operation),
1062 ))
1063 .await
1064 }
1065
1066 pub fn read(&mut self, read: &mut [u8]) -> Result<(), EspError> {
1067 self.transaction(&mut [Operation::Read(read)])
1068 }
1069
1070 #[cfg(not(esp_idf_spi_master_isr_in_iram))]
1071 pub async fn read_async(&mut self, read: &mut [u8]) -> Result<(), EspError> {
1072 let mut operation = [Operation::Read(read)];
1073 let work = core::pin::pin!(self.transaction_async(&mut operation));
1074 work.await
1075 }
1076
1077 pub fn write(&mut self, write: &[u8]) -> Result<(), EspError> {
1078 self.transaction(&mut [Operation::Write(write)])
1079 }
1080
1081 #[cfg(not(esp_idf_spi_master_isr_in_iram))]
1082 pub async fn write_async(&mut self, write: &[u8]) -> Result<(), EspError> {
1083 let mut operation = [Operation::Write(write)];
1084 let work = core::pin::pin!(self.transaction_async(&mut operation));
1085 work.await
1086 }
1087
1088 pub fn transfer_in_place(&mut self, buf: &mut [u8]) -> Result<(), EspError> {
1089 self.transaction(&mut [Operation::TransferInPlace(buf)])
1090 }
1091
1092 #[cfg(not(esp_idf_spi_master_isr_in_iram))]
1093 pub async fn transfer_in_place_async(&mut self, buf: &mut [u8]) -> Result<(), EspError> {
1094 let mut operation = [Operation::TransferInPlace(buf)];
1095 let work = core::pin::pin!(self.transaction_async(&mut operation));
1096 work.await
1097 }
1098
1099 pub fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), EspError> {
1100 self.transaction(&mut [Operation::Transfer(read, write)])
1101 }
1102
1103 #[cfg(not(esp_idf_spi_master_isr_in_iram))]
1104 pub async fn transfer_async(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), EspError> {
1105 let mut operation = [Operation::Transfer(read, write)];
1106 let work = core::pin::pin!(self.transaction_async(&mut operation));
1107 work.await
1108 }
1109
1110 fn run<'a, 'c, 'p, M>(
1111 &mut self,
1112 mut cs_pin: CsCtl<'c, 'p, M>,
1113 operations: impl Iterator<Item = Operation<'a>> + 'a,
1114 ) -> Result<(), EspError>
1115 where
1116 M: OutputMode,
1117 {
1118 let _lock = if cs_pin.needs_bus_lock() {
1119 Some(BusLock::new(self.device())?)
1120 } else {
1121 None
1122 };
1123
1124 cs_pin.raise_cs()?;
1125
1126 let mut spi_operations = self
1127 .spi_operations(operations)
1128 .enumerate()
1129 .map(|(index, mut operation)| {
1130 cs_pin.configure(&mut operation, index);
1131 operation
1132 })
1133 .peekable();
1134
1135 let delay_impl = crate::delay::Delay::new_default();
1136 let mut result = Ok(());
1137
1138 while spi_operations.peek().is_some() {
1139 if let Some(SpiOperation::Delay(delay)) = spi_operations.peek() {
1140 delay_impl.delay_us(*delay / 1000);
1141 spi_operations.next();
1142 } else {
1143 let transactions = core::iter::from_fn(|| {
1144 spi_operations
1145 .next_if(|operation| matches!(operation, SpiOperation::Transaction(_)))
1146 })
1147 .fuse()
1148 .filter_map(|operation| operation.transaction());
1149
1150 result = spi_transmit(self.handle, transactions, self.polling, self.queue_size);
1151
1152 if result.is_err() {
1153 break;
1154 }
1155 }
1156 }
1157
1158 cs_pin.lower_cs()?;
1159
1160 result
1161 }
1162
1163 #[allow(dead_code)]
1164 async fn run_async<'a, 'c, 'p, M>(
1165 &self,
1166 mut cs_pin: CsCtl<'c, 'p, M>,
1167 operations: impl Iterator<Item = Operation<'a>> + 'a,
1168 ) -> Result<(), EspError>
1169 where
1170 M: OutputMode,
1171 {
1172 let _async_bus_lock = if cs_pin.needs_bus_lock() {
1173 Some(self.driver.borrow().bus_async_lock.lock().await)
1174 } else {
1175 None
1176 };
1177
1178 let _lock = if cs_pin.needs_bus_lock() {
1179 Some(BusLock::new(self.device())?)
1180 } else {
1181 None
1182 };
1183
1184 cs_pin.raise_cs()?;
1185
1186 let delay_impl = crate::delay::Delay::new_default(); let mut result = Ok(());
1188
1189 let mut spi_operations = self
1190 .spi_operations(operations)
1191 .enumerate()
1192 .map(|(index, mut operation)| {
1193 cs_pin.configure(&mut operation, index);
1194 operation
1195 })
1196 .peekable();
1197
1198 while spi_operations.peek().is_some() {
1199 if let Some(SpiOperation::Delay(delay)) = spi_operations.peek() {
1200 delay_impl.delay_us(*delay);
1201 spi_operations.next();
1202 } else {
1203 let transactions = core::iter::from_fn(|| {
1204 spi_operations
1205 .next_if(|operation| matches!(operation, SpiOperation::Transaction(_)))
1206 })
1207 .fuse()
1208 .filter_map(|operation| operation.transaction());
1209
1210 result = core::pin::pin!(spi_transmit_async(
1211 self.handle,
1212 transactions,
1213 self.queue_size
1214 ))
1215 .await;
1216
1217 if result.is_err() {
1218 break;
1219 }
1220 }
1221 }
1222
1223 cs_pin.lower_cs()?;
1224
1225 result
1226 }
1227
1228 fn hardware_cs_ctl<'a, 'c, 'p>(
1229 &self,
1230 operations: impl Iterator<Item = Operation<'a>> + 'a,
1231 ) -> Result<CsCtl<'c, 'p, Output>, EspError> {
1232 let (total_count, transactions_count, first_transaction, last_transaction) =
1233 self.spi_operations_stats(operations);
1234
1235 if !self.allow_pre_post_delays
1236 && self.cs_pin_configured
1237 && transactions_count > 0
1238 && (first_transaction != Some(0) || last_transaction != Some(total_count - 1))
1239 {
1240 Err(EspError::from_infallible::<ESP_ERR_INVALID_ARG>())?;
1241 }
1242
1243 Ok(CsCtl::Hardware {
1244 enabled: self.cs_pin_configured,
1245 transactions_count,
1246 last_transaction,
1247 })
1248 }
1249
1250 fn spi_operations_stats<'a>(
1251 &self,
1252 operations: impl Iterator<Item = Operation<'a>> + 'a,
1253 ) -> (usize, usize, Option<usize>, Option<usize>) {
1254 self.spi_operations(operations).enumerate().fold(
1255 (0, 0, None, None),
1256 |(total_count, transactions_count, first_transaction, last_transaction),
1257 (index, operation)| {
1258 if matches!(operation, SpiOperation::Transaction(_)) {
1259 (
1260 total_count + 1,
1261 transactions_count + 1,
1262 Some(first_transaction.unwrap_or(index)),
1263 Some(index),
1264 )
1265 } else {
1266 (
1267 total_count + 1,
1268 transactions_count,
1269 first_transaction,
1270 last_transaction,
1271 )
1272 }
1273 },
1274 )
1275 }
1276
1277 fn spi_operations<'a>(
1278 &self,
1279 operations: impl Iterator<Item = Operation<'a>> + 'a,
1280 ) -> impl Iterator<Item = SpiOperation> + 'a {
1281 let chunk_size = self.driver.borrow().max_transfer_size;
1282 let duplex = self.duplex;
1283 spi_operations(operations, chunk_size, duplex)
1284 }
1285}
1286
1287impl<'d, T> Drop for SpiDeviceDriver<'d, T>
1288where
1289 T: Borrow<SpiDriver<'d>> + 'd,
1290{
1291 fn drop(&mut self) {
1292 esp!(unsafe { spi_bus_remove_device(self.handle) }).unwrap();
1293 }
1294}
1295
1296unsafe impl<'d, T> Send for SpiDeviceDriver<'d, T> where T: Send + Borrow<SpiDriver<'d>> + 'd {}
1297
1298impl<'d, T> embedded_hal::spi::ErrorType for SpiDeviceDriver<'d, T>
1299where
1300 T: Borrow<SpiDriver<'d>> + 'd,
1301{
1302 type Error = SpiError;
1303}
1304
1305impl<'d, T> SpiDevice for SpiDeviceDriver<'d, T>
1306where
1307 T: Borrow<SpiDriver<'d>> + 'd,
1308{
1309 fn read(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
1310 Self::read(self, buf).map_err(to_spi_err)
1311 }
1312
1313 fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
1314 Self::write(self, buf).map_err(to_spi_err)
1315 }
1316
1317 fn transaction(
1318 &mut self,
1319 operations: &mut [embedded_hal::spi::Operation<'_, u8>],
1320 ) -> Result<(), Self::Error> {
1321 self.run(
1322 self.hardware_cs_ctl(operations.iter_mut().map(copy_ehal_operation))?,
1323 operations.iter_mut().map(copy_ehal_operation),
1324 )
1325 .map_err(to_spi_err)
1326 }
1327}
1328
1329impl<'d, T> embedded_hal_0_2::blocking::spi::Transfer<u8> for SpiDeviceDriver<'d, T>
1330where
1331 T: Borrow<SpiDriver<'d>> + 'd,
1332{
1333 type Error = SpiError;
1334
1335 fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
1336 self.transfer_in_place(words)?;
1337
1338 Ok(words)
1339 }
1340}
1341
1342impl<'d, T> embedded_hal_0_2::blocking::spi::Write<u8> for SpiDeviceDriver<'d, T>
1343where
1344 T: Borrow<SpiDriver<'d>> + 'd,
1345{
1346 type Error = SpiError;
1347
1348 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
1349 self.write(words).map_err(to_spi_err)
1350 }
1351}
1352
1353impl<'d, T> embedded_hal_0_2::blocking::spi::WriteIter<u8> for SpiDeviceDriver<'d, T>
1355where
1356 T: Borrow<SpiDriver<'d>> + 'd,
1357{
1358 type Error = SpiError;
1359
1360 fn write_iter<WI>(&mut self, words: WI) -> Result<(), Self::Error>
1361 where
1362 WI: IntoIterator<Item = u8>,
1363 {
1364 let mut lock = None;
1365
1366 let mut words = words.into_iter().peekable();
1367 let mut buf = [0_u8; TRANS_LEN];
1368
1369 loop {
1370 let mut offset = 0_usize;
1371
1372 while offset < buf.len() {
1373 if let Some(word) = words.next() {
1374 buf[offset] = word;
1375 offset += 1;
1376 } else {
1377 break;
1378 }
1379 }
1380
1381 if offset == 0 {
1382 break;
1383 }
1384
1385 let mut transaction = spi_create_transaction(
1386 core::ptr::null_mut(),
1387 buf[..offset].as_ptr(),
1388 offset,
1389 0,
1390 LineWidth::Single,
1391 );
1392
1393 if lock.is_none() && words.peek().is_some() {
1394 lock = Some(BusLock::new(self.handle)?);
1395 }
1396
1397 set_keep_cs_active(
1398 &mut transaction,
1399 self.cs_pin_configured && words.peek().is_some(),
1400 );
1401
1402 spi_transmit(
1403 self.handle,
1404 once(transaction),
1405 self.polling,
1406 self.queue_size,
1407 )?;
1408 }
1409
1410 Ok(())
1411 }
1412}
1413
1414impl<'d, T> embedded_hal_0_2::blocking::spi::Transactional<u8> for SpiDeviceDriver<'d, T>
1415where
1416 T: Borrow<SpiDriver<'d>> + 'd,
1417{
1418 type Error = SpiError;
1419
1420 fn exec(
1421 &mut self,
1422 operations: &mut [embedded_hal_0_2::blocking::spi::Operation<'_, u8>],
1423 ) -> Result<(), Self::Error> {
1424 self.run(
1425 self.hardware_cs_ctl(operations.iter_mut().map(|op| match op {
1426 embedded_hal_0_2::blocking::spi::Operation::Write(words) => Operation::Write(words),
1427 embedded_hal_0_2::blocking::spi::Operation::Transfer(words) => {
1428 Operation::TransferInPlace(words)
1429 }
1430 }))?,
1431 operations.iter_mut().map(|op| match op {
1432 embedded_hal_0_2::blocking::spi::Operation::Write(words) => Operation::Write(words),
1433 embedded_hal_0_2::blocking::spi::Operation::Transfer(words) => {
1434 Operation::TransferInPlace(words)
1435 }
1436 }),
1437 )
1438 .map_err(to_spi_err)
1439 }
1440}
1441
1442#[cfg(not(esp_idf_spi_master_isr_in_iram))]
1443impl<'d, T> embedded_hal_async::spi::SpiDevice for SpiDeviceDriver<'d, T>
1444where
1445 T: Borrow<SpiDriver<'d>> + 'd,
1446{
1447 async fn read(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
1448 Self::read_async(self, buf).await.map_err(to_spi_err)
1449 }
1450
1451 async fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
1452 Self::write_async(self, buf).await.map_err(to_spi_err)
1453 }
1454
1455 async fn transaction(
1456 &mut self,
1457 operations: &mut [embedded_hal::spi::Operation<'_, u8>],
1458 ) -> Result<(), Self::Error> {
1459 core::pin::pin!(self.run_async(
1460 self.hardware_cs_ctl(operations.iter_mut().map(copy_ehal_operation))?,
1461 operations.iter_mut().map(copy_ehal_operation),
1462 ))
1463 .await
1464 .map_err(to_spi_err)
1465 }
1466}
1467
1468pub struct SpiSharedDeviceDriver<'d, T>
1469where
1470 T: Borrow<SpiDriver<'d>> + 'd,
1471{
1472 driver: UnsafeCell<SpiDeviceDriver<'d, T>>,
1473 lock: CriticalSection,
1474 #[allow(dead_code)]
1475 async_lock: Mutex<EspRawMutex, ()>,
1476}
1477
1478impl<'d, T> SpiSharedDeviceDriver<'d, T>
1479where
1480 T: Borrow<SpiDriver<'d>> + 'd,
1481{
1482 pub fn new(driver: T, config: &config::Config) -> Result<Self, EspError> {
1483 Ok(Self::wrap(SpiDeviceDriver::new(
1484 driver,
1485 Option::<AnyOutputPin>::None,
1486 config,
1487 )?))
1488 }
1489
1490 pub const fn wrap(device: SpiDeviceDriver<'d, T>) -> Self {
1491 Self {
1492 driver: UnsafeCell::new(device),
1493 lock: CriticalSection::new(),
1494 async_lock: Mutex::new(()),
1495 }
1496 }
1497
1498 pub fn lock<R>(&self, f: impl FnOnce(&mut SpiDeviceDriver<'d, T>) -> R) -> R {
1499 let _guard = self.lock.enter();
1500
1501 let device = unsafe { self.driver_mut() };
1502
1503 f(device)
1504 }
1505
1506 pub fn release(self) -> SpiDeviceDriver<'d, T> {
1507 self.driver.into_inner()
1508 }
1509
1510 #[allow(clippy::mut_from_ref)]
1511 unsafe fn driver_mut(&self) -> &mut SpiDeviceDriver<'d, T> {
1512 &mut *self.driver.get()
1513 }
1514}
1515
1516pub struct SpiSoftCsDeviceDriver<'d, DEVICE, DRIVER> {
1517 shared_device: DEVICE,
1518 cs_pin: PinDriver<'d, Output>,
1519 pre_delay_us: Option<u32>,
1520 post_delay_us: Option<u32>,
1521 _p: PhantomData<fn() -> DRIVER>,
1522}
1523
1524impl<'d, DEVICE, DRIVER> SpiSoftCsDeviceDriver<'d, DEVICE, DRIVER>
1525where
1526 DEVICE: Borrow<SpiSharedDeviceDriver<'d, DRIVER>>,
1527 DRIVER: Borrow<SpiDriver<'d>> + 'd,
1528{
1529 pub fn new(
1530 shared_device: DEVICE,
1531 cs: impl OutputPin + 'd,
1532 cs_level: Level,
1533 ) -> Result<Self, EspError> {
1534 let mut cs_pin: PinDriver<Output> = PinDriver::output(cs)?;
1535
1536 cs_pin.set_level(cs_level)?;
1537
1538 Ok(Self {
1539 shared_device,
1540 cs_pin,
1541 pre_delay_us: None,
1542 post_delay_us: None,
1543 _p: PhantomData,
1544 })
1545 }
1546
1547 pub fn cs_pre_delay_us(&mut self, delay_us: u32) -> &mut Self {
1550 self.pre_delay_us = Some(delay_us);
1551
1552 self
1553 }
1554
1555 pub fn cs_post_delay_us(&mut self, delay_us: u32) -> &mut Self {
1558 self.post_delay_us = Some(delay_us);
1559
1560 self
1561 }
1562
1563 pub fn transaction(&mut self, operations: &mut [Operation<'_>]) -> Result<(), EspError> {
1564 self.run(operations.iter_mut().map(copy_operation))
1565 }
1566
1567 #[cfg(not(esp_idf_spi_master_isr_in_iram))]
1568 pub async fn transaction_async(
1569 &mut self,
1570 operations: &mut [Operation<'_>],
1571 ) -> Result<(), EspError> {
1572 core::pin::pin!(self.run_async(operations.iter_mut().map(copy_operation))).await
1573 }
1574
1575 pub fn read(&mut self, read: &mut [u8]) -> Result<(), EspError> {
1576 self.transaction(&mut [Operation::Read(read)])
1577 }
1578
1579 #[cfg(not(esp_idf_spi_master_isr_in_iram))]
1580 pub async fn read_async(&mut self, read: &mut [u8]) -> Result<(), EspError> {
1581 let mut operation = [Operation::Read(read)];
1582 let work = core::pin::pin!(self.transaction_async(&mut operation));
1583 work.await
1584 }
1585
1586 pub fn write(&mut self, write: &[u8]) -> Result<(), EspError> {
1587 self.transaction(&mut [Operation::Write(write)])
1588 }
1589
1590 #[cfg(not(esp_idf_spi_master_isr_in_iram))]
1591 pub async fn write_async(&mut self, write: &[u8]) -> Result<(), EspError> {
1592 let mut operation = [Operation::Write(write)];
1593 let work = core::pin::pin!(self.transaction_async(&mut operation));
1594 work.await
1595 }
1596
1597 pub fn transfer_in_place(&mut self, buf: &mut [u8]) -> Result<(), EspError> {
1598 self.transaction(&mut [Operation::TransferInPlace(buf)])
1599 }
1600
1601 #[cfg(not(esp_idf_spi_master_isr_in_iram))]
1602 pub async fn transfer_in_place_async(&mut self, buf: &mut [u8]) -> Result<(), EspError> {
1603 let mut operation = [Operation::TransferInPlace(buf)];
1604 let work = core::pin::pin!(self.transaction_async(&mut operation));
1605 work.await
1606 }
1607
1608 pub fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), EspError> {
1609 self.transaction(&mut [Operation::Transfer(read, write)])
1610 }
1611
1612 #[cfg(not(esp_idf_spi_master_isr_in_iram))]
1613 pub async fn transfer_async(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), EspError> {
1614 let mut operation = [Operation::Transfer(read, write)];
1615 let work = core::pin::pin!(self.transaction_async(&mut operation));
1616 work.await
1617 }
1618
1619 fn run<'a>(
1620 &mut self,
1621 operations: impl Iterator<Item = Operation<'a>> + 'a,
1622 ) -> Result<(), EspError> {
1623 let cs_pin = CsCtl::Software {
1624 cs: &mut self.cs_pin,
1625 pre_delay: self.pre_delay_us,
1626 post_delay: self.post_delay_us,
1627 };
1628
1629 self.shared_device
1630 .borrow()
1631 .lock(move |device| device.run(cs_pin, operations))
1632 }
1633
1634 #[allow(dead_code)]
1635 async fn run_async<'a>(
1636 &mut self,
1637 operations: impl Iterator<Item = Operation<'a>> + 'a,
1638 ) -> Result<(), EspError> {
1639 let cs_pin = CsCtl::Software {
1640 cs: &mut self.cs_pin,
1641 pre_delay: self.pre_delay_us,
1642 post_delay: self.post_delay_us,
1643 };
1644
1645 let device = self.shared_device.borrow();
1646
1647 let _async_guard = device.async_lock.lock().await;
1648 let _guard = device.lock.enter();
1649
1650 let driver = unsafe { device.driver_mut() };
1651
1652 driver.run_async(cs_pin, operations).await
1653 }
1654}
1655
1656impl<'d, DEVICE, DRIVER> embedded_hal::spi::ErrorType for SpiSoftCsDeviceDriver<'d, DEVICE, DRIVER>
1657where
1658 DEVICE: Borrow<SpiSharedDeviceDriver<'d, DRIVER>> + 'd,
1659 DRIVER: Borrow<SpiDriver<'d>> + 'd,
1660{
1661 type Error = SpiError;
1662}
1663
1664impl<'d, DEVICE, DRIVER> SpiDevice for SpiSoftCsDeviceDriver<'d, DEVICE, DRIVER>
1665where
1666 DEVICE: Borrow<SpiSharedDeviceDriver<'d, DRIVER>> + 'd,
1667 DRIVER: Borrow<SpiDriver<'d>> + 'd,
1668{
1669 fn read(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
1670 Self::read(self, buf).map_err(to_spi_err)
1671 }
1672
1673 fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
1674 Self::write(self, buf).map_err(to_spi_err)
1675 }
1676
1677 fn transaction(
1678 &mut self,
1679 operations: &mut [embedded_hal::spi::Operation<'_, u8>],
1680 ) -> Result<(), Self::Error> {
1681 self.run(operations.iter_mut().map(copy_ehal_operation))
1682 .map_err(to_spi_err)
1683 }
1684}
1685
1686#[cfg(not(esp_idf_spi_master_isr_in_iram))]
1687impl<'d, DEVICE, DRIVER> embedded_hal_async::spi::SpiDevice
1688 for SpiSoftCsDeviceDriver<'d, DEVICE, DRIVER>
1689where
1690 DEVICE: Borrow<SpiSharedDeviceDriver<'d, DRIVER>> + 'd,
1691 DRIVER: Borrow<SpiDriver<'d>> + 'd,
1692{
1693 async fn read(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
1694 Self::read_async(self, buf).await.map_err(to_spi_err)
1695 }
1696
1697 async fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
1698 Self::write_async(self, buf).await.map_err(to_spi_err)
1699 }
1700
1701 async fn transaction(
1702 &mut self,
1703 operations: &mut [embedded_hal::spi::Operation<'_, u8>],
1704 ) -> Result<(), Self::Error> {
1705 core::pin::pin!(self.run_async(operations.iter_mut().map(copy_ehal_operation)))
1706 .await
1707 .map_err(to_spi_err)
1708 }
1709}
1710
1711fn to_spi_err(err: EspError) -> SpiError {
1712 SpiError::other(err)
1713}
1714
1715const TRANS_LEN: usize = if SOC_SPI_MAXIMUM_BUFFER_SIZE < 64_u32 {
1718 SOC_SPI_MAXIMUM_BUFFER_SIZE as _
1719} else {
1720 64_usize
1721};
1722
1723const MAX_QUEUED_TRANSACTIONS: usize = 6;
1729
1730struct BusLock(spi_device_handle_t);
1731
1732impl BusLock {
1733 fn new(device: spi_device_handle_t) -> Result<Self, EspError> {
1734 esp!(unsafe { spi_device_acquire_bus(device, BLOCK) })?;
1735
1736 Ok(Self(device))
1737 }
1738}
1739
1740impl Drop for BusLock {
1741 fn drop(&mut self) {
1742 unsafe {
1743 spi_device_release_bus(self.0);
1744 }
1745 }
1746}
1747
1748enum CsCtl<'c, 'p, M>
1749where
1750 M: OutputMode,
1751{
1752 Hardware {
1753 enabled: bool,
1754 transactions_count: usize,
1755 last_transaction: Option<usize>,
1756 },
1757 Software {
1758 cs: &'c mut PinDriver<'p, M>,
1759 pre_delay: Option<u32>,
1760 post_delay: Option<u32>,
1761 },
1762}
1763
1764impl<M> CsCtl<'_, '_, M>
1765where
1766 M: OutputMode,
1767{
1768 fn needs_bus_lock(&self) -> bool {
1769 match self {
1770 Self::Hardware {
1771 transactions_count, ..
1772 } => *transactions_count > 1,
1773 Self::Software { .. } => true,
1774 }
1775 }
1776
1777 fn raise_cs(&mut self) -> Result<(), EspError> {
1778 if let CsCtl::Software { cs, pre_delay, .. } = self {
1779 cs.toggle()?;
1780
1781 if let Some(delay) = pre_delay {
1783 Ets::delay_us(*delay);
1784 }
1785 }
1786
1787 Ok(())
1788 }
1789
1790 fn lower_cs(&mut self) -> Result<(), EspError> {
1791 if let CsCtl::Software { cs, post_delay, .. } = self {
1792 cs.toggle()?;
1793
1794 if let Some(delay) = post_delay {
1796 Ets::delay_us(*delay);
1797 }
1798 }
1799
1800 Ok(())
1801 }
1802
1803 fn configure(&self, operation: &mut SpiOperation, index: usize) {
1804 if let SpiOperation::Transaction(transaction) = operation {
1805 self.configure_transaction(transaction, index)
1806 }
1807 }
1808
1809 fn configure_transaction(&self, transaction: &mut spi_transaction_t, index: usize) {
1810 if let Self::Hardware {
1811 enabled,
1812 last_transaction,
1813 ..
1814 } = self
1815 {
1816 set_keep_cs_active(transaction, *enabled && Some(index) != *last_transaction);
1817 }
1818 }
1819}
1820
1821fn spi_operations<'a>(
1822 operations: impl Iterator<Item = Operation<'a>> + 'a,
1823 chunk_size: usize,
1824 duplex: Duplex,
1825) -> impl Iterator<Item = SpiOperation> + 'a {
1826 enum OperationsIter<R, W, T, I, D> {
1827 Read(R),
1828 Write(W),
1829 Transfer(T),
1830 TransferInPlace(I),
1831 Delay(D),
1832 }
1833
1834 impl<R, W, T, I, D> Iterator for OperationsIter<R, W, T, I, D>
1835 where
1836 R: Iterator<Item = SpiOperation>,
1837 W: Iterator<Item = SpiOperation>,
1838 T: Iterator<Item = SpiOperation>,
1839 I: Iterator<Item = SpiOperation>,
1840 D: Iterator<Item = SpiOperation>,
1841 {
1842 type Item = SpiOperation;
1843
1844 fn next(&mut self) -> Option<Self::Item> {
1845 match self {
1846 Self::Read(iter) => iter.next(),
1847 Self::Write(iter) => iter.next(),
1848 Self::Transfer(iter) => iter.next(),
1849 Self::TransferInPlace(iter) => iter.next(),
1850 Self::Delay(iter) => iter.next(),
1851 }
1852 }
1853 }
1854
1855 operations.flat_map(move |op| match op {
1856 Operation::Read(words) => OperationsIter::Read(
1857 spi_read_transactions(words, chunk_size, duplex, LineWidth::Single)
1858 .map(SpiOperation::Transaction),
1859 ),
1860 Operation::ReadWithWidth(words, line_width) => OperationsIter::Read(
1861 spi_read_transactions(words, chunk_size, duplex, line_width)
1862 .map(SpiOperation::Transaction),
1863 ),
1864 Operation::Write(words) => OperationsIter::Write(
1865 spi_write_transactions(words, chunk_size, LineWidth::Single)
1866 .map(SpiOperation::Transaction),
1867 ),
1868 Operation::WriteWithWidth(words, line_width) => OperationsIter::Write(
1869 spi_write_transactions(words, chunk_size, line_width).map(SpiOperation::Transaction),
1870 ),
1871 Operation::Transfer(read, write) => OperationsIter::Transfer(
1872 spi_transfer_transactions(read, write, chunk_size, duplex)
1873 .map(SpiOperation::Transaction),
1874 ),
1875 Operation::TransferInPlace(words) => OperationsIter::TransferInPlace(
1876 spi_transfer_in_place_transactions(words, chunk_size).map(SpiOperation::Transaction),
1877 ),
1878 Operation::DelayNs(delay) => {
1879 OperationsIter::Delay(core::iter::once(SpiOperation::Delay(delay)))
1880 }
1881 })
1882}
1883
1884fn spi_read_transactions(
1885 words: &mut [u8],
1886 chunk_size: usize,
1887 duplex: Duplex,
1888 line_width: LineWidth,
1889) -> impl Iterator<Item = spi_transaction_t> + '_ {
1890 words.chunks_mut(chunk_size).map(move |chunk| {
1891 spi_create_transaction(
1892 chunk.as_mut_ptr(),
1893 core::ptr::null(),
1894 if duplex == Duplex::Full {
1895 chunk.len()
1896 } else {
1897 0
1898 },
1899 chunk.len(),
1900 line_width,
1901 )
1902 })
1903}
1904
1905fn spi_write_transactions(
1906 words: &[u8],
1907 chunk_size: usize,
1908 line_width: LineWidth,
1909) -> impl Iterator<Item = spi_transaction_t> + '_ {
1910 words.chunks(chunk_size).map(move |chunk| {
1911 spi_create_transaction(
1912 core::ptr::null_mut(),
1913 chunk.as_ptr(),
1914 chunk.len(),
1915 0,
1916 line_width,
1917 )
1918 })
1919}
1920
1921fn spi_transfer_in_place_transactions(
1922 words: &mut [u8],
1923 chunk_size: usize,
1924) -> impl Iterator<Item = spi_transaction_t> + '_ {
1925 words.chunks_mut(chunk_size).map(|chunk| {
1926 spi_create_transaction(
1927 chunk.as_mut_ptr(),
1928 chunk.as_mut_ptr(),
1929 chunk.len(),
1930 chunk.len(),
1931 LineWidth::Single,
1932 )
1933 })
1934}
1935
1936fn spi_transfer_transactions<'a>(
1937 read: &'a mut [u8],
1938 write: &'a [u8],
1939 chunk_size: usize,
1940 duplex: Duplex,
1941) -> impl Iterator<Item = spi_transaction_t> + 'a {
1942 enum OperationsIter<E, R, W> {
1943 Equal(E),
1944 ReadLonger(R),
1945 WriteLonger(W),
1946 }
1947
1948 impl<E, R, W> Iterator for OperationsIter<E, R, W>
1949 where
1950 E: Iterator<Item = spi_transaction_t>,
1951 R: Iterator<Item = spi_transaction_t>,
1952 W: Iterator<Item = spi_transaction_t>,
1953 {
1954 type Item = spi_transaction_t;
1955
1956 fn next(&mut self) -> Option<Self::Item> {
1957 match self {
1958 Self::Equal(iter) => iter.next(),
1959 Self::ReadLonger(iter) => iter.next(),
1960 Self::WriteLonger(iter) => iter.next(),
1961 }
1962 }
1963 }
1964
1965 match read.len().cmp(&write.len()) {
1966 Ordering::Equal => {
1967 OperationsIter::Equal(spi_transfer_equal_transactions(read, write, chunk_size))
1968 }
1969 Ordering::Greater => {
1970 let (read, read_trail) = read.split_at_mut(write.len());
1971
1972 OperationsIter::ReadLonger(
1973 spi_transfer_equal_transactions(read, write, chunk_size).chain(
1974 spi_read_transactions(read_trail, chunk_size, duplex, LineWidth::Single),
1975 ),
1976 )
1977 }
1978 Ordering::Less => {
1979 let (write, write_trail) = write.split_at(read.len());
1980
1981 OperationsIter::WriteLonger(
1982 spi_transfer_equal_transactions(read, write, chunk_size).chain(
1983 spi_write_transactions(write_trail, chunk_size, LineWidth::Single),
1984 ),
1985 )
1986 }
1987 }
1988}
1989
1990fn spi_transfer_equal_transactions<'a>(
1991 read: &'a mut [u8],
1992 write: &'a [u8],
1993 chunk_size: usize,
1994) -> impl Iterator<Item = spi_transaction_t> + 'a {
1995 read.chunks_mut(chunk_size)
1996 .zip(write.chunks(chunk_size))
1997 .map(|(read_chunk, write_chunk)| {
1998 spi_create_transaction(
1999 read_chunk.as_mut_ptr(),
2000 write_chunk.as_ptr(),
2001 max(read_chunk.len(), write_chunk.len()),
2002 read_chunk.len(),
2003 LineWidth::Single,
2004 )
2005 })
2006}
2007
2008fn spi_create_transaction(
2010 read: *mut u8,
2011 write: *const u8,
2012 transaction_length: usize,
2013 rx_length: usize,
2014 line_width: LineWidth,
2015) -> spi_transaction_t {
2016 let flags = match line_width {
2017 LineWidth::Single => 0,
2018 LineWidth::Dual => SPI_TRANS_MODE_DIO,
2019 LineWidth::Quad => SPI_TRANS_MODE_QIO,
2020 };
2021 spi_transaction_t {
2022 flags,
2023 __bindgen_anon_1: spi_transaction_t__bindgen_ty_1 {
2024 tx_buffer: write as *const _,
2025 },
2026 __bindgen_anon_2: spi_transaction_t__bindgen_ty_2 {
2027 rx_buffer: read as *mut _,
2028 },
2029 length: (transaction_length * 8) as _,
2030 rxlength: (rx_length * 8) as _,
2031 ..Default::default()
2032 }
2033}
2034
2035fn set_keep_cs_active(transaction: &mut spi_transaction_t, _keep_cs_active: bool) {
2036 if _keep_cs_active {
2037 transaction.flags |= SPI_TRANS_CS_KEEP_ACTIVE
2038 }
2039}
2040
2041fn spi_transmit(
2042 handle: spi_device_handle_t,
2043 transactions: impl Iterator<Item = spi_transaction_t>,
2044 polling: bool,
2045 queue_size: usize,
2046) -> Result<(), EspError> {
2047 if polling {
2048 for mut transaction in transactions {
2049 esp!(unsafe { spi_device_polling_transmit(handle, &mut transaction as *mut _) })?;
2050 }
2051 } else {
2052 pub type Queue = Deque<spi_transaction_t, MAX_QUEUED_TRANSACTIONS>;
2053
2054 let mut queue = Queue::new();
2055 let queue_size = min(MAX_QUEUED_TRANSACTIONS, queue_size);
2056
2057 let push = |queue: &mut Queue, transaction| {
2058 let _ = queue.push_back(transaction);
2059 esp!(unsafe { spi_device_queue_trans(handle, queue.back_mut().unwrap(), delay::BLOCK) })
2060 };
2061
2062 let pop = |queue: &mut Queue| {
2063 let mut rtrans = ptr::null_mut();
2064 esp!(unsafe { spi_device_get_trans_result(handle, &mut rtrans, delay::BLOCK) })?;
2065
2066 if rtrans != queue.front_mut().unwrap() {
2067 unreachable!();
2068 }
2069 queue.pop_front().unwrap();
2070
2071 Ok(())
2072 };
2073
2074 let pop_all = |queue: &mut Queue| {
2075 while !queue.is_empty() {
2076 pop(queue)?;
2077 }
2078
2079 Ok(())
2080 };
2081
2082 for transaction in transactions {
2083 if queue.len() == queue_size {
2084 pop(&mut queue)?;
2086 }
2087
2088 push(&mut queue, transaction)?;
2090 }
2091
2092 pop_all(&mut queue)?;
2093 }
2094
2095 Ok(())
2096}
2097
2098#[allow(dead_code)]
2099async fn spi_transmit_async(
2100 handle: spi_device_handle_t,
2101 transactions: impl Iterator<Item = spi_transaction_t>,
2102 queue_size: usize,
2103) -> Result<(), EspError> {
2104 pub type Queue = Deque<(spi_transaction_t, HalIsrNotification), MAX_QUEUED_TRANSACTIONS>;
2105
2106 let mut queue = Queue::new();
2107 let queue = &mut queue;
2108
2109 let queue_size = min(MAX_QUEUED_TRANSACTIONS, queue_size);
2110 let queued = Cell::new(0_usize);
2111
2112 let fut = &mut core::pin::pin!(async {
2113 let push = |queue: &mut Queue, transaction| {
2114 queue
2115 .push_back((transaction, HalIsrNotification::new()))
2116 .map_err(|_| EspError::from_infallible::<{ ESP_ERR_INVALID_STATE }>())?;
2117 queued.set(queue.len());
2118
2119 let last = queue.back_mut().unwrap();
2120 last.0.user = &last.1 as *const _ as *mut _;
2121 match esp!(unsafe { spi_device_queue_trans(handle, &mut last.0, delay::BLOCK) }) {
2122 Err(e) if e.code() == ESP_ERR_TIMEOUT => unreachable!(),
2123 other => other,
2124 }
2125 };
2126
2127 let pop = |queue: &mut Queue, delay: TickType_t| {
2128 let mut rtrans = ptr::null_mut();
2129 match esp!(unsafe { spi_device_get_trans_result(handle, &mut rtrans, delay) }) {
2130 Err(e) if e.code() == ESP_ERR_TIMEOUT => return Ok(false),
2131 Err(e) => Err(e)?,
2132 Ok(()) => (),
2133 };
2134
2135 if rtrans != &mut queue.front_mut().unwrap().0 {
2136 unreachable!();
2137 }
2138
2139 queue.pop_front().unwrap();
2140 queued.set(queue.len());
2141
2142 Ok(true)
2143 };
2144
2145 for transaction in transactions {
2156 while queue.len() == queue_size {
2158 if !pop(queue, delay::NON_BLOCK)? {
2159 queue.front_mut().unwrap().1.wait().await;
2160 pop(queue, delay::BLOCK)?;
2161 }
2162 }
2163
2164 push(queue, transaction)?;
2166 }
2167
2168 while !queue.is_empty() {
2169 if !pop(queue, delay::NON_BLOCK)? {
2170 queue.front_mut().unwrap().1.wait().await;
2171 pop(queue, delay::BLOCK)?;
2172 }
2173 }
2174
2175 Ok(())
2176 });
2177
2178 with_completion(fut, |completed| {
2179 if !completed {
2180 for _ in 0..queued.get() {
2181 let mut rtrans = ptr::null_mut();
2182 esp!(unsafe { spi_device_get_trans_result(handle, &mut rtrans, delay::BLOCK) })
2183 .unwrap();
2184 }
2185 }
2186 })
2187 .await
2188}
2189
2190extern "C" fn spi_notify(transaction: *mut spi_transaction_t) {
2191 if let Some(transaction) = unsafe { transaction.as_ref() } {
2192 if let Some(notification) = unsafe {
2193 (transaction.user as *mut HalIsrNotification as *const HalIsrNotification).as_ref()
2194 } {
2195 notification.notify_lsb();
2196 }
2197 }
2198}
2199
2200fn copy_operation<'b>(operation: &'b mut Operation<'_>) -> Operation<'b> {
2201 match operation {
2202 Operation::Read(read) => Operation::Read(read),
2203 Operation::ReadWithWidth(read, line_width) => Operation::ReadWithWidth(read, *line_width),
2204 Operation::Write(write) => Operation::Write(write),
2205 Operation::WriteWithWidth(write, line_width) => {
2206 Operation::WriteWithWidth(write, *line_width)
2207 }
2208 Operation::Transfer(read, write) => Operation::Transfer(read, write),
2209 Operation::TransferInPlace(write) => Operation::TransferInPlace(write),
2210 Operation::DelayNs(delay) => Operation::DelayNs(*delay),
2211 }
2212}
2213
2214fn copy_ehal_operation<'b>(
2215 operation: &'b mut embedded_hal::spi::Operation<'_, u8>,
2216) -> Operation<'b> {
2217 match operation {
2218 embedded_hal::spi::Operation::Read(read) => Operation::Read(read),
2219 embedded_hal::spi::Operation::Write(write) => Operation::Write(write),
2220 embedded_hal::spi::Operation::Transfer(read, write) => Operation::Transfer(read, write),
2221 embedded_hal::spi::Operation::TransferInPlace(write) => Operation::TransferInPlace(write),
2222 embedded_hal::spi::Operation::DelayNs(delay) => Operation::DelayNs(*delay),
2223 }
2224}
2225
2226#[allow(dead_code)]
2227async fn with_completion<F, D>(fut: F, dtor: D) -> F::Output
2228where
2229 F: Future,
2230 D: FnMut(bool),
2231{
2232 struct Completion<D>
2233 where
2234 D: FnMut(bool),
2235 {
2236 dtor: D,
2237 completed: bool,
2238 }
2239
2240 impl<D> Drop for Completion<D>
2241 where
2242 D: FnMut(bool),
2243 {
2244 fn drop(&mut self) {
2245 (self.dtor)(self.completed);
2246 }
2247 }
2248
2249 let mut completion = Completion {
2250 dtor,
2251 completed: false,
2252 };
2253
2254 let result = fut.await;
2255
2256 completion.completed = true;
2257
2258 result
2259}
2260
2261macro_rules! impl_spi {
2262 ($spi:ident: $device:expr) => {
2263 crate::impl_peripheral!($spi);
2264
2265 impl Spi for $spi<'_> {
2266 #[inline(always)]
2267 fn device() -> spi_host_device_t {
2268 $device
2269 }
2270 }
2271 };
2272}
2273
2274macro_rules! impl_spi_any_pins {
2275 ($spi:ident) => {
2276 impl SpiAnyPins for $spi<'_> {}
2277 };
2278}
2279
2280impl_spi!(SPI1: spi_host_device_t_SPI1_HOST);
2281impl_spi!(SPI2: spi_host_device_t_SPI2_HOST);
2282#[cfg(any(esp32, esp32s2, esp32s3, esp32p4))]
2283impl_spi!(SPI3: spi_host_device_t_SPI3_HOST);
2284
2285impl_spi_any_pins!(SPI2);
2286#[cfg(any(esp32, esp32s2, esp32s3, esp32p4))]
2287impl_spi_any_pins!(SPI3);