Skip to main content

esp_hal/spi/master/
mod.rs

1//! # Serial Peripheral Interface - Master Mode
2//!
3//! ## Overview
4//!
5//! In this mode, the SPI acts as master and initiates the SPI transactions.
6//!
7//! ## Configuration
8//!
9//! The peripheral can be used in full-duplex and half-duplex mode and can
10//! leverage DMA for data transfers. It can also be used in blocking or async.
11//!
12//! ### Exclusive access to the SPI bus
13//!
14//! If all you want to do is to communicate to a single device, and you initiate
15//! transactions yourself, there are a number of ways to achieve this:
16//!
17//! - Use the [`SpiBus`] or [`SpiBusAsync`] trait and its associated functions to initiate
18//!   transactions with simultaneous reads and writes, or
19//! - Use the `ExclusiveDevice` struct from [`embedded-hal-bus`] or `SpiDevice` from
20//!   [`embassy-embedded-hal`].
21//!
22//! ### Shared SPI access
23//!
24//! If you have multiple devices on the same SPI bus that each have their own CS
25//! line (and optionally, configuration), you may want to have a look at the
26//! implementations provided by [`embedded-hal-bus`] and
27//! [`embassy-embedded-hal`].
28//!
29//! ## Usage
30//!
31//! The module implements several third-party traits from embedded-hal@1.x.x
32//! and [`embassy-embedded-hal`].
33//!
34//! [`embedded-hal-bus`]: https://docs.rs/embedded-hal-bus/latest/embedded_hal_bus/spi/index.html
35//! [`embassy-embedded-hal`]: embassy_embedded_hal::shared_bus
36
37use core::{marker::PhantomData, sync::atomic::Ordering};
38
39#[cfg(spi_master_supports_dma)]
40mod dma;
41mod low_level;
42
43#[instability::unstable]
44#[cfg(spi_master_supports_dma)]
45pub use dma::*;
46use embedded_hal::spi::SpiBus;
47use embedded_hal_async::spi::SpiBus as SpiBusAsync;
48use enumset::EnumSetType;
49use low_level::{Driver, SpiWrapper};
50pub use low_level::{Info, Instance, QspiInstance, State};
51use procmacros::doc_replace;
52
53use super::{BitOrder, Error, Mode};
54use crate::{
55    Async,
56    Blocking,
57    DriverMode,
58    gpio::{
59        InputConfig,
60        NoPin,
61        OutputConfig,
62        OutputSignal,
63        PinGuard,
64        interconnect::{self, PeripheralInput, PeripheralOutput},
65    },
66    interrupt::InterruptHandler,
67    private::Sealed,
68    spi::master::low_level::SpiClockGuard,
69    time::Rate,
70};
71
72/// Enumeration of possible SPI interrupt events.
73#[derive(Debug, Hash, EnumSetType)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))]
75#[non_exhaustive]
76#[instability::unstable]
77pub enum SpiInterrupt {
78    /// Indicates that the SPI transaction has completed successfully.
79    ///
80    /// This interrupt is triggered when an SPI transaction has finished
81    /// transmitting and receiving data.
82    TransferDone,
83
84    /// Triggered at the end of configurable segmented transfer.
85    #[cfg(spi_master_has_dma_segmented_transfer)]
86    DmaSegmentedTransferDone,
87
88    /// Used and triggered by software. Only used for user defined function.
89    #[cfg(spi_master_has_app_interrupts)]
90    App2,
91
92    /// Used and triggered by software. Only used for user defined function.
93    #[cfg(spi_master_has_app_interrupts)]
94    App1,
95}
96
97/// The size of the FIFO buffer for SPI.
98const FIFO_SIZE: usize = property!("spi_master.fifo_size");
99
100/// Padding byte for empty write transfers
101const EMPTY_WRITE_PAD: u8 = 0x00;
102
103/// SPI commands, each consisting of a 16-bit command value and a data mode.
104///
105/// Used to define specific commands sent over the SPI bus.
106/// Can be [Command::None] if command phase should be suppressed.
107#[non_exhaustive]
108#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
109#[cfg_attr(feature = "defmt", derive(defmt::Format))]
110#[instability::unstable]
111pub enum Command {
112    /// No command is sent.
113    None,
114    /// A 1-bit command.
115    _1Bit(u16, DataMode),
116    /// A 2-bit command.
117    _2Bit(u16, DataMode),
118    /// A 3-bit command.
119    _3Bit(u16, DataMode),
120    /// A 4-bit command.
121    _4Bit(u16, DataMode),
122    /// A 5-bit command.
123    _5Bit(u16, DataMode),
124    /// A 6-bit command.
125    _6Bit(u16, DataMode),
126    /// A 7-bit command.
127    _7Bit(u16, DataMode),
128    /// A 8-bit command.
129    _8Bit(u16, DataMode),
130    /// A 9-bit command.
131    _9Bit(u16, DataMode),
132    /// A 10-bit command.
133    _10Bit(u16, DataMode),
134    /// A 11-bit command.
135    _11Bit(u16, DataMode),
136    /// A 12-bit command.
137    _12Bit(u16, DataMode),
138    /// A 13-bit command.
139    _13Bit(u16, DataMode),
140    /// A 14-bit command.
141    _14Bit(u16, DataMode),
142    /// A 15-bit command.
143    _15Bit(u16, DataMode),
144    /// A 16-bit command.
145    _16Bit(u16, DataMode),
146}
147
148impl Command {
149    fn width(&self) -> usize {
150        match self {
151            Command::None => 0,
152            Command::_1Bit(_, _) => 1,
153            Command::_2Bit(_, _) => 2,
154            Command::_3Bit(_, _) => 3,
155            Command::_4Bit(_, _) => 4,
156            Command::_5Bit(_, _) => 5,
157            Command::_6Bit(_, _) => 6,
158            Command::_7Bit(_, _) => 7,
159            Command::_8Bit(_, _) => 8,
160            Command::_9Bit(_, _) => 9,
161            Command::_10Bit(_, _) => 10,
162            Command::_11Bit(_, _) => 11,
163            Command::_12Bit(_, _) => 12,
164            Command::_13Bit(_, _) => 13,
165            Command::_14Bit(_, _) => 14,
166            Command::_15Bit(_, _) => 15,
167            Command::_16Bit(_, _) => 16,
168        }
169    }
170
171    fn value(&self) -> u16 {
172        match self {
173            Command::None => 0,
174            Command::_1Bit(value, _)
175            | Command::_2Bit(value, _)
176            | Command::_3Bit(value, _)
177            | Command::_4Bit(value, _)
178            | Command::_5Bit(value, _)
179            | Command::_6Bit(value, _)
180            | Command::_7Bit(value, _)
181            | Command::_8Bit(value, _)
182            | Command::_9Bit(value, _)
183            | Command::_10Bit(value, _)
184            | Command::_11Bit(value, _)
185            | Command::_12Bit(value, _)
186            | Command::_13Bit(value, _)
187            | Command::_14Bit(value, _)
188            | Command::_15Bit(value, _)
189            | Command::_16Bit(value, _) => *value,
190        }
191    }
192
193    fn mode(&self) -> DataMode {
194        match self {
195            Command::None => DataMode::SingleTwoDataLines,
196            Command::_1Bit(_, mode)
197            | Command::_2Bit(_, mode)
198            | Command::_3Bit(_, mode)
199            | Command::_4Bit(_, mode)
200            | Command::_5Bit(_, mode)
201            | Command::_6Bit(_, mode)
202            | Command::_7Bit(_, mode)
203            | Command::_8Bit(_, mode)
204            | Command::_9Bit(_, mode)
205            | Command::_10Bit(_, mode)
206            | Command::_11Bit(_, mode)
207            | Command::_12Bit(_, mode)
208            | Command::_13Bit(_, mode)
209            | Command::_14Bit(_, mode)
210            | Command::_15Bit(_, mode)
211            | Command::_16Bit(_, mode) => *mode,
212        }
213    }
214
215    fn is_none(&self) -> bool {
216        matches!(self, Command::None)
217    }
218}
219
220/// SPI address, ranging from 1 to 32 bits, paired with a data mode.
221///
222/// This can be used to specify the address phase of SPI transactions.
223/// Can be [Address::None] if address phase should be suppressed.
224#[non_exhaustive]
225#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
226#[cfg_attr(feature = "defmt", derive(defmt::Format))]
227#[instability::unstable]
228pub enum Address {
229    /// No address phase.
230    None,
231    /// A 1-bit address.
232    _1Bit(u32, DataMode),
233    /// A 2-bit address.
234    _2Bit(u32, DataMode),
235    /// A 3-bit address.
236    _3Bit(u32, DataMode),
237    /// A 4-bit address.
238    _4Bit(u32, DataMode),
239    /// A 5-bit address.
240    _5Bit(u32, DataMode),
241    /// A 6-bit address.
242    _6Bit(u32, DataMode),
243    /// A 7-bit address.
244    _7Bit(u32, DataMode),
245    /// A 8-bit address.
246    _8Bit(u32, DataMode),
247    /// A 9-bit address.
248    _9Bit(u32, DataMode),
249    /// A 10-bit address.
250    _10Bit(u32, DataMode),
251    /// A 11-bit address.
252    _11Bit(u32, DataMode),
253    /// A 12-bit address.
254    _12Bit(u32, DataMode),
255    /// A 13-bit address.
256    _13Bit(u32, DataMode),
257    /// A 14-bit address.
258    _14Bit(u32, DataMode),
259    /// A 15-bit address.
260    _15Bit(u32, DataMode),
261    /// A 16-bit address.
262    _16Bit(u32, DataMode),
263    /// A 17-bit address.
264    _17Bit(u32, DataMode),
265    /// A 18-bit address.
266    _18Bit(u32, DataMode),
267    /// A 19-bit address.
268    _19Bit(u32, DataMode),
269    /// A 20-bit address.
270    _20Bit(u32, DataMode),
271    /// A 21-bit address.
272    _21Bit(u32, DataMode),
273    /// A 22-bit address.
274    _22Bit(u32, DataMode),
275    /// A 23-bit address.
276    _23Bit(u32, DataMode),
277    /// A 24-bit address.
278    _24Bit(u32, DataMode),
279    /// A 25-bit address.
280    _25Bit(u32, DataMode),
281    /// A 26-bit address.
282    _26Bit(u32, DataMode),
283    /// A 27-bit address.
284    _27Bit(u32, DataMode),
285    /// A 28-bit address.
286    _28Bit(u32, DataMode),
287    /// A 29-bit address.
288    _29Bit(u32, DataMode),
289    /// A 30-bit address.
290    _30Bit(u32, DataMode),
291    /// A 31-bit address.
292    _31Bit(u32, DataMode),
293    /// A 32-bit address.
294    _32Bit(u32, DataMode),
295}
296
297impl Address {
298    fn width(&self) -> usize {
299        match self {
300            Address::None => 0,
301            Address::_1Bit(_, _) => 1,
302            Address::_2Bit(_, _) => 2,
303            Address::_3Bit(_, _) => 3,
304            Address::_4Bit(_, _) => 4,
305            Address::_5Bit(_, _) => 5,
306            Address::_6Bit(_, _) => 6,
307            Address::_7Bit(_, _) => 7,
308            Address::_8Bit(_, _) => 8,
309            Address::_9Bit(_, _) => 9,
310            Address::_10Bit(_, _) => 10,
311            Address::_11Bit(_, _) => 11,
312            Address::_12Bit(_, _) => 12,
313            Address::_13Bit(_, _) => 13,
314            Address::_14Bit(_, _) => 14,
315            Address::_15Bit(_, _) => 15,
316            Address::_16Bit(_, _) => 16,
317            Address::_17Bit(_, _) => 17,
318            Address::_18Bit(_, _) => 18,
319            Address::_19Bit(_, _) => 19,
320            Address::_20Bit(_, _) => 20,
321            Address::_21Bit(_, _) => 21,
322            Address::_22Bit(_, _) => 22,
323            Address::_23Bit(_, _) => 23,
324            Address::_24Bit(_, _) => 24,
325            Address::_25Bit(_, _) => 25,
326            Address::_26Bit(_, _) => 26,
327            Address::_27Bit(_, _) => 27,
328            Address::_28Bit(_, _) => 28,
329            Address::_29Bit(_, _) => 29,
330            Address::_30Bit(_, _) => 30,
331            Address::_31Bit(_, _) => 31,
332            Address::_32Bit(_, _) => 32,
333        }
334    }
335
336    fn value(&self) -> u32 {
337        match self {
338            Address::None => 0,
339            Address::_1Bit(value, _)
340            | Address::_2Bit(value, _)
341            | Address::_3Bit(value, _)
342            | Address::_4Bit(value, _)
343            | Address::_5Bit(value, _)
344            | Address::_6Bit(value, _)
345            | Address::_7Bit(value, _)
346            | Address::_8Bit(value, _)
347            | Address::_9Bit(value, _)
348            | Address::_10Bit(value, _)
349            | Address::_11Bit(value, _)
350            | Address::_12Bit(value, _)
351            | Address::_13Bit(value, _)
352            | Address::_14Bit(value, _)
353            | Address::_15Bit(value, _)
354            | Address::_16Bit(value, _)
355            | Address::_17Bit(value, _)
356            | Address::_18Bit(value, _)
357            | Address::_19Bit(value, _)
358            | Address::_20Bit(value, _)
359            | Address::_21Bit(value, _)
360            | Address::_22Bit(value, _)
361            | Address::_23Bit(value, _)
362            | Address::_24Bit(value, _)
363            | Address::_25Bit(value, _)
364            | Address::_26Bit(value, _)
365            | Address::_27Bit(value, _)
366            | Address::_28Bit(value, _)
367            | Address::_29Bit(value, _)
368            | Address::_30Bit(value, _)
369            | Address::_31Bit(value, _)
370            | Address::_32Bit(value, _) => *value,
371        }
372    }
373
374    fn is_none(&self) -> bool {
375        matches!(self, Address::None)
376    }
377
378    fn mode(&self) -> DataMode {
379        match self {
380            Address::None => DataMode::SingleTwoDataLines,
381            Address::_1Bit(_, mode)
382            | Address::_2Bit(_, mode)
383            | Address::_3Bit(_, mode)
384            | Address::_4Bit(_, mode)
385            | Address::_5Bit(_, mode)
386            | Address::_6Bit(_, mode)
387            | Address::_7Bit(_, mode)
388            | Address::_8Bit(_, mode)
389            | Address::_9Bit(_, mode)
390            | Address::_10Bit(_, mode)
391            | Address::_11Bit(_, mode)
392            | Address::_12Bit(_, mode)
393            | Address::_13Bit(_, mode)
394            | Address::_14Bit(_, mode)
395            | Address::_15Bit(_, mode)
396            | Address::_16Bit(_, mode)
397            | Address::_17Bit(_, mode)
398            | Address::_18Bit(_, mode)
399            | Address::_19Bit(_, mode)
400            | Address::_20Bit(_, mode)
401            | Address::_21Bit(_, mode)
402            | Address::_22Bit(_, mode)
403            | Address::_23Bit(_, mode)
404            | Address::_24Bit(_, mode)
405            | Address::_25Bit(_, mode)
406            | Address::_26Bit(_, mode)
407            | Address::_27Bit(_, mode)
408            | Address::_28Bit(_, mode)
409            | Address::_29Bit(_, mode)
410            | Address::_30Bit(_, mode)
411            | Address::_31Bit(_, mode)
412            | Address::_32Bit(_, mode) => *mode,
413        }
414    }
415}
416
417/// SPI clock source.
418#[instability::unstable]
419pub use crate::soc::clocks::SpiFunctionClockConfig as ClockSource;
420
421/// SPI peripheral configuration
422#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, procmacros::BuilderLite)]
423#[cfg_attr(feature = "defmt", derive(defmt::Format))]
424#[non_exhaustive]
425pub struct Config {
426    /// The precomputed clock configuration register value.
427    ///
428    /// Clock divider calculations are relatively expensive, and the SPI
429    /// peripheral is commonly expected to be used in a shared bus
430    /// configuration, where different devices may need different bus clock
431    /// frequencies. To reduce the time required to reconfigure the bus, the
432    /// clock register value is cached here for each configuration.
433    ///
434    /// This field is not intended to be set from application code, and is only used
435    /// internally.
436    #[builder_lite(skip)]
437    reg: Result<u32, ConfigError>,
438
439    /// The target frequency.
440    #[builder_lite(skip_setter)]
441    frequency: Rate,
442
443    /// The clock source.
444    #[builder_lite(unstable)]
445    #[builder_lite(skip_setter)]
446    clock_source: ClockSource,
447
448    /// SPI sample/shift mode.
449    mode: Mode,
450
451    /// Bit order of the read data.
452    read_bit_order: BitOrder,
453
454    /// Bit order of the written data.
455    write_bit_order: BitOrder,
456
457    /// Minimum transfer size in bytes below which CPU-driven (blocking) I/O
458    /// is used instead of async or DMA transfers.
459    ///
460    /// This can reduce overhead for small transfers where DMA setup or
461    /// async context-switch cost exceeds the benefit. For
462    /// [`SpiDma`][crate::spi::master::dma::SpiDma], the threshold applies in
463    /// both blocking and async DMA modes: when met, DMA is disabled and the
464    /// transfer is performed by the CPU. This applies to both full-duplex and
465    /// half-duplex transfers.
466    ///
467    /// A value of `0` (the default) disables the threshold — all transfers use
468    /// the driver's default method.
469    #[builder_lite(unstable)]
470    min_async_transfer_size: usize,
471}
472
473impl Default for Config {
474    fn default() -> Self {
475        let mut this = Config {
476            reg: Ok(0),
477            frequency: Rate::from_mhz(1),
478            clock_source: ClockSource::default(),
479            mode: Mode::_0,
480            read_bit_order: BitOrder::MsbFirst,
481            write_bit_order: BitOrder::MsbFirst,
482            min_async_transfer_size: 0,
483        };
484
485        this.reg = this.recalculate();
486
487        this
488    }
489}
490
491impl Config {
492    /// Sets the frequency of the SPI bus clock.
493    ///
494    /// The closest available frequency that does not exceed `frequency` is used,
495    /// so the bus never runs faster than requested.
496    pub fn with_frequency(mut self, frequency: Rate) -> Self {
497        self.frequency = frequency;
498        self.reg = self.recalculate();
499
500        self
501    }
502
503    /// Sets the clock source of the SPI bus.
504    #[instability::unstable]
505    pub fn with_clock_source(mut self, clock_source: ClockSource) -> Self {
506        self.clock_source = clock_source;
507        self.reg = self.recalculate();
508
509        self
510    }
511
512    fn clock_source_freq_hz(&self) -> Rate {
513        Rate::from_hz(
514            crate::soc::clocks::SpiInstance::function_clock_source_frequency(self.clock_source),
515        )
516    }
517
518    fn recalculate(&self) -> Result<u32, ConfigError> {
519        // TODO: model peripheral-side clock divider, allow the user to directly configure it
520        // taken from https://github.com/apache/incubator-nuttx/blob/8267a7618629838231256edfa666e44b5313348e/arch/risc-v/src/esp32c3/esp32c3_spi.c#L496
521        let source_freq = self.clock_source_freq_hz();
522
523        // In HW, n, h and l fields range from 1 to 64, pre ranges from 1 to 8K.
524        // The value written to register is one lower than the used value.
525
526        if self.frequency >= source_freq {
527            // Bypass the divider, which is exactly the source frequency.
528            // Set the SPI_CLK_EQU_SYSCLK bit.
529            return Ok(1 << 31);
530        }
531
532        let (n, pre) = Self::divider_pair(source_freq.as_hz(), self.frequency.as_hz());
533
534        // In master mode, L == N
535        let l = n;
536
537        // In master mode, this field must be floor((SPI_CLKCNT_N + 1)/2 - 1)
538        let h = (n / 2).max(1);
539
540        Ok((l - 1) // SPI_CLKCNT_L
541            | ((h - 1) << 6) // SPI_CLKCNT_H
542            | ((n - 1) << 12) // SPI_CLKCNT_N
543            | ((pre - 1) << 18)) // SPI_CLKDIV_PRE
544    }
545
546    /// Finds the `(n, pre)` pair producing the highest bus frequency that does
547    /// not exceed `target_freq_hz`, where `n` is `SPI_CLKCNT_N + 1` and `pre` is
548    /// `SPI_CLKDIV_PRE + 1`.
549    ///
550    /// The peripheral divides the source clock by `pre * n`, so this is the
551    /// smallest divider that does not overshoot. `n` also determines the duty
552    /// cycle resolution, so among pairs forming that divider the one with the
553    /// largest `n` is preferred.
554    ///
555    /// Out-of-range frequencies (see [`Config::validate`]) yield the slowest pair
556    /// available rather than an error.
557    fn divider_pair(source_freq_hz: u32, target_freq_hz: u32) -> (u32, u32) {
558        // A zero target is rejected by `validate`, but must not divide by zero
559        // here.
560        if target_freq_hz == 0 {
561            return (64, 16);
562        }
563
564        // Any smaller divider would run the bus faster than requested. `n` starts
565        // at 2 so that h/l can describe at least one high and one low pulse.
566        let min_divider = source_freq_hz.div_ceil(target_freq_hz).max(2);
567
568        // A `pre` of 1 offers every divider up to 64, so if the smallest usable
569        // divider is in that range we can form it directly, with the largest `n`
570        // that produces it.
571        if min_divider <= 64 {
572            return (min_divider, 1);
573        }
574
575        // `n` maxes out at 64, so a smaller `pre` cannot bring the source clock
576        // down to the target. As `n` shrinks when `pre` grows, walking `pre`
577        // upwards visits the candidates in order of decreasing duty cycle
578        // resolution, which lets us keep the first of several that share a
579        // divider.
580        //
581        // The seed is the slowest pair, which also answers requests below the
582        // supported range.
583        let mut best = (64, 16);
584        let mut best_divider = 64 * 16;
585
586        // A `for` loop over a range would leave a divide-by-zero check on `pre`
587        // in the generated code, as the lower bound is not visible through the
588        // range iterator on all targets.
589        let mut pre = min_divider.div_ceil(64);
590        while pre <= 16 {
591            // The smallest `n` that keeps `pre * n` from overshooting. The lower
592            // bound on `pre` keeps this at or below 64.
593            let n = min_divider.div_ceil(pre);
594            let divider = pre * n;
595
596            if divider < best_divider {
597                best = (n, pre);
598                best_divider = divider;
599
600                // Nothing can beat hitting the smallest usable divider exactly.
601                if divider == min_divider {
602                    break;
603                }
604            }
605
606            pre += 1;
607        }
608
609        best
610    }
611
612    fn raw_clock_reg_value(&self) -> Result<u32, ConfigError> {
613        self.reg
614    }
615
616    fn validate(&self) -> Result<(), ConfigError> {
617        let source_freq = self.clock_source_freq_hz();
618        let min_divider = 1;
619        // FIXME: while ESP32 and S2 support pre dividers as large as 8192,
620        // those values are not currently supported by the divider calculation.
621        let max_divider = 16 * 64; // n * pre
622
623        if self.frequency < source_freq / max_divider || self.frequency > source_freq / min_divider
624        {
625            return Err(ConfigError::FrequencyOutOfRange);
626        }
627
628        Ok(())
629    }
630}
631
632const SIO_PIN_COUNT: usize = 4 + cfg!(spi_master_has_octal) as usize * 4;
633
634#[derive(Debug)]
635#[cfg_attr(feature = "defmt", derive(defmt::Format))]
636struct SpiPinGuard {
637    sclk_pin: PinGuard,
638    cs_pin: PinGuard,
639    sio_pins: [PinGuard; SIO_PIN_COUNT],
640}
641
642impl SpiPinGuard {
643    const fn new_unconnected() -> Self {
644        Self {
645            sclk_pin: PinGuard::new_unconnected(),
646            cs_pin: PinGuard::new_unconnected(),
647            sio_pins: [const { PinGuard::new_unconnected() }; SIO_PIN_COUNT],
648        }
649    }
650}
651
652/// Configuration errors.
653#[non_exhaustive]
654#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
655#[cfg_attr(feature = "defmt", derive(defmt::Format))]
656pub enum ConfigError {
657    /// The requested frequency is not in the supported range.
658    FrequencyOutOfRange,
659}
660
661impl core::error::Error for ConfigError {}
662
663impl core::fmt::Display for ConfigError {
664    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
665        match self {
666            ConfigError::FrequencyOutOfRange => {
667                write!(f, "The requested frequency is not in the supported range")
668            }
669        }
670    }
671}
672
673#[procmacros::doc_replace]
674/// SPI peripheral driver
675///
676/// # Examples
677///
678/// ```rust, no_run
679/// # {before_snippet}
680/// use esp_hal::spi::{
681///     Mode,
682///     master::{Config, Spi},
683/// };
684/// let mut spi = Spi::new(
685///     peripherals.SPI2,
686///     Config::default()
687///         .with_frequency(Rate::from_khz(100))
688///         .with_mode(Mode::_0),
689/// )?
690/// .with_sck(peripherals.GPIO0)
691/// .with_mosi(peripherals.GPIO1)
692/// .with_miso(peripherals.GPIO2);
693/// # {after_snippet}
694/// ```
695#[derive(Debug)]
696#[cfg_attr(feature = "defmt", derive(defmt::Format))]
697pub struct Spi<'d, Dm: DriverMode> {
698    spi: SpiWrapper<'d>,
699    _mode: PhantomData<Dm>,
700}
701
702impl<Dm: DriverMode> Sealed for Spi<'_, Dm> {}
703
704impl<'d> Spi<'d, Blocking> {
705    #[procmacros::doc_replace]
706    /// Creates a new SPI instance in 8-bit data-frame mode.
707    ///
708    /// # Examples
709    ///
710    /// ```rust, no_run
711    /// # {before_snippet}
712    /// use esp_hal::spi::{
713    ///     Mode,
714    ///     master::{Config, Spi},
715    /// };
716    /// let mut spi = Spi::new(peripherals.SPI2, Config::default())?
717    ///     .with_sck(peripherals.GPIO0)
718    ///     .with_mosi(peripherals.GPIO1)
719    ///     .with_miso(peripherals.GPIO2);
720    /// # {after_snippet}
721    /// ```
722    ///
723    /// # Errors
724    ///
725    /// See [`Spi::apply_config`]
726    pub fn new(spi: impl Instance + 'd, config: Config) -> Result<Self, ConfigError> {
727        let mut this = Spi {
728            _mode: PhantomData,
729            spi: SpiWrapper::new(spi),
730        };
731
732        this.driver().init();
733        this.apply_config(&config)?;
734
735        let this = this.with_sck(NoPin).with_cs(NoPin);
736
737        for sio in 0..8 {
738            if let Some(signal) = this.driver().info.opt_sio_input(sio) {
739                signal.connect_to(&NoPin);
740            }
741            if let Some(signal) = this.driver().info.opt_sio_output(sio) {
742                signal.connect_to(&NoPin);
743            }
744        }
745
746        Ok(this)
747    }
748
749    /// Reconfigures the driver to operate in [`Async`] mode.
750    ///
751    /// See the [`Async`] documentation for an example on how to use this
752    /// method.
753    pub fn into_async(mut self) -> Spi<'d, Async> {
754        self.set_interrupt_handler(self.spi.info().async_handler);
755        Spi {
756            spi: self.spi,
757            _mode: PhantomData,
758        }
759    }
760
761    #[doc_replace(
762        "peripheral_on" => {
763            cfg(multi_core) => "peripheral on the current core",
764            _ => "peripheral",
765        }
766    )]
767    /// Registers an interrupt handler for the __peripheral_on__.
768    ///
769    /// Replaces any previously registered interrupt handlers.
770    ///
771    /// The default/unhandled interrupt handler can be restored with
772    /// [crate::interrupt::DEFAULT_INTERRUPT_HANDLER]
773    ///
774    /// # Panics
775    ///
776    /// Panics if passed interrupt handler is invalid (e.g. has priority
777    /// `None`)
778    #[instability::unstable]
779    pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
780        self.spi.set_interrupt_handler(handler);
781    }
782}
783
784#[instability::unstable]
785impl crate::interrupt::InterruptConfigurable for Spi<'_, Blocking> {
786    /// Sets the interrupt handler.
787    ///
788    /// Interrupts are not enabled at the peripheral level here.
789    fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
790        self.set_interrupt_handler(handler);
791    }
792}
793
794impl<'d> Spi<'d, Async> {
795    /// Reconfigures the driver to operate in [`Blocking`] mode.
796    ///
797    /// See the [`Blocking`] documentation for an example on how to use this
798    /// method.
799    pub fn into_blocking(self) -> Spi<'d, Blocking> {
800        self.spi.disable_peri_interrupt_on_all_cores();
801        Spi {
802            spi: self.spi,
803            _mode: PhantomData,
804        }
805    }
806
807    #[procmacros::doc_replace]
808    /// Waits for the completion of previous operations.
809    ///
810    /// # Examples
811    ///
812    /// ```rust, no_run
813    /// # {before_snippet}
814    /// use esp_hal::spi::{
815    ///     Mode,
816    ///     master::{Config, Spi},
817    /// };
818    /// let mut spi = Spi::new(peripherals.SPI2, Config::default())?
819    ///     .with_sck(peripherals.GPIO0)
820    ///     .with_mosi(peripherals.GPIO1)
821    ///     .with_miso(peripherals.GPIO2)
822    ///     .into_async();
823    ///
824    /// let mut buffer = [0; 10];
825    /// spi.transfer_in_place_async(&mut buffer).await?;
826    /// spi.flush_async().await?;
827    ///
828    /// # {after_snippet}
829    /// ```
830    pub async fn flush_async(&mut self) -> Result<(), Error> {
831        Ok(())
832    }
833
834    #[procmacros::doc_replace]
835    /// Sends `words` to the slave. Returns the `words` received from the slave.
836    ///
837    /// Aborts the transfer when its Future is dropped. Some amount of data may have
838    /// been transferred before the Future is dropped. Dropping the future may block
839    /// for a short while to ensure the transfer is aborted.
840    ///
841    /// # Examples
842    ///
843    /// ```rust, no_run
844    /// # {before_snippet}
845    /// use esp_hal::spi::{
846    ///     Mode,
847    ///     master::{Config, Spi},
848    /// };
849    /// let mut spi = Spi::new(peripherals.SPI2, Config::default())?
850    ///     .with_sck(peripherals.GPIO0)
851    ///     .with_mosi(peripherals.GPIO1)
852    ///     .with_miso(peripherals.GPIO2)
853    ///     .into_async();
854    ///
855    /// let mut buffer = [0; 10];
856    /// spi.transfer_in_place_async(&mut buffer).await?;
857    ///
858    /// # {after_snippet}
859    /// ```
860    pub async fn transfer_in_place_async(&mut self, words: &mut [u8]) -> Result<(), Error> {
861        let _clock = SpiClockGuard::new(self.spi.info());
862
863        self.driver().setup_full_duplex()?;
864
865        if self.use_blocking_transfer(words.len()) {
866            return self.driver().transfer_in_place(words);
867        }
868
869        self.driver().transfer_in_place_async(words).await
870    }
871
872    /// Half-duplex read.
873    ///
874    /// Transfers larger than the hardware FIFO are split into chunks. CS remains asserted across
875    /// chunks, but the clock pauses while the CPU prepares each subsequent chunk.
876    ///
877    /// Aborts the transfer when its Future is dropped. Some amount of data may have
878    /// been transferred before the Future is dropped. Dropping the future may block
879    /// for a short while to ensure the transfer is aborted.
880    ///
881    /// # Errors
882    ///
883    /// [`Error::Unsupported`] when the buffer is empty (currently unsupported).
884    /// `DataMode::Single` cannot be combined with any other [`DataMode`], otherwise
885    /// [`Error::Unsupported`].
886    #[instability::unstable]
887    pub async fn half_duplex_read_async(
888        &mut self,
889        data_mode: DataMode,
890        cmd: Command,
891        address: Address,
892        dummy: u8,
893        buffer: &mut [u8],
894    ) -> Result<(), Error> {
895        let _clock = SpiClockGuard::new(self.spi.info());
896
897        if self.use_blocking_transfer(buffer.len()) {
898            return self
899                .driver()
900                .half_duplex_read(data_mode, cmd, address, dummy, buffer);
901        }
902
903        self.driver()
904            .half_duplex_read_async(data_mode, cmd, address, dummy, buffer)
905            .await
906    }
907
908    /// Half-duplex write.
909    ///
910    /// Transfers larger than the hardware FIFO are split into chunks. CS remains asserted across
911    /// chunks, but the clock pauses while the CPU prepares each subsequent chunk.
912    ///
913    /// Aborts the transfer when its Future is dropped. Some amount of data may have
914    /// been transferred before the Future is dropped. Dropping the future may block
915    /// for a short while to ensure the transfer is aborted.
916    ///
917    /// # Errors
918    ///
919    /// [`Error::Unsupported`] for unsupported combinations of command, address,
920    /// dummy, and data modes.
921    #[cfg_attr(
922        esp32,
923        doc = "Dummy phase configuration is currently not supported, only value `0` is valid (see issue [#2240](https://github.com/esp-rs/esp-hal/issues/2240))."
924    )]
925    #[instability::unstable]
926    pub async fn half_duplex_write_async(
927        &mut self,
928        data_mode: DataMode,
929        cmd: Command,
930        address: Address,
931        dummy: u8,
932        buffer: &[u8],
933    ) -> Result<(), Error> {
934        let _clock = SpiClockGuard::new(self.spi.info());
935
936        if self.use_blocking_transfer(buffer.len()) {
937            return self
938                .driver()
939                .half_duplex_write(data_mode, cmd, address, dummy, buffer);
940        }
941
942        self.driver()
943            .half_duplex_write_async(data_mode, cmd, address, dummy, buffer)
944            .await
945    }
946
947    // TODO: These inherent methods should be public
948
949    async fn read_async(&mut self, words: &mut [u8]) -> Result<(), Error> {
950        let _clock = SpiClockGuard::new(self.spi.info());
951
952        self.driver().setup_full_duplex()?;
953
954        if self.use_blocking_transfer(words.len()) {
955            return self.driver().read(words);
956        }
957
958        self.driver().read_async(words).await
959    }
960
961    async fn write_async(&mut self, words: &[u8]) -> Result<(), Error> {
962        let _clock = SpiClockGuard::new(self.spi.info());
963
964        self.driver().setup_full_duplex()?;
965
966        if self.use_blocking_transfer(words.len()) {
967            return self.driver().write(words);
968        }
969
970        self.driver().write_async(words).await
971    }
972}
973
974macro_rules! def_with_sio_pin {
975    ($fn:ident, $n:literal) => {
976        #[doc = concat!(" Assign the SIO", stringify!($n), " pin for the SPI instance.")]
977        #[doc = " "]
978        #[doc = " Enables both input and output functionality for the pin, and connects it"]
979        #[doc = concat!(" to the SIO", stringify!($n), " output and input signals.")]
980        #[instability::unstable]
981        pub fn $fn(mut self, sio: impl PeripheralInput<'d> + PeripheralOutput<'d>) -> Self {
982            self.spi.pins().sio_pins[$n] = self.connect_sio_pin(sio.into(), $n);
983
984            self
985        }
986    };
987}
988
989impl<'d, Dm> Spi<'d, Dm>
990where
991    Dm: DriverMode,
992{
993    fn connect_sio_pin(&self, pin: interconnect::OutputSignal<'d>, n: usize) -> PinGuard {
994        let in_signal = self.spi.info().sio_input(n);
995        let out_signal = self.spi.info().sio_output(n);
996
997        pin.apply_input_config(&InputConfig::default());
998        pin.apply_output_config(&OutputConfig::default());
999
1000        pin.set_input_enable(true);
1001        pin.set_output_enable(false);
1002
1003        in_signal.connect_to(&pin);
1004        pin.connect_with_guard(out_signal)
1005    }
1006
1007    fn connect_sio_output_pin(&self, pin: interconnect::OutputSignal<'d>, n: usize) -> PinGuard {
1008        let out_signal = self.spi.info().sio_output(n);
1009
1010        self.connect_output_pin(pin, out_signal)
1011    }
1012
1013    fn connect_output_pin(
1014        &self,
1015        pin: interconnect::OutputSignal<'d>,
1016        signal: OutputSignal,
1017    ) -> PinGuard {
1018        pin.apply_output_config(&OutputConfig::default());
1019        pin.set_output_enable(true); // TODO turn this bool into a Yes/No/PeripheralControl trio
1020
1021        pin.connect_with_guard(signal)
1022    }
1023
1024    #[procmacros::doc_replace]
1025    /// Assigns the SCK (Serial Clock) pin for the SPI instance.
1026    ///
1027    /// Configures the specified pin to push-pull output and connects it to the
1028    /// SPI clock signal.
1029    ///
1030    /// Disconnects the previous pin that was assigned with `with_sck`.
1031    ///
1032    /// # Examples
1033    ///
1034    /// ```rust, no_run
1035    /// # {before_snippet}
1036    /// use esp_hal::spi::{
1037    ///     Mode,
1038    ///     master::{Config, Spi},
1039    /// };
1040    /// let mut spi = Spi::new(peripherals.SPI2, Config::default())?.with_sck(peripherals.GPIO0);
1041    ///
1042    /// # {after_snippet}
1043    /// ```
1044    pub fn with_sck(mut self, sclk: impl PeripheralOutput<'d>) -> Self {
1045        let info = self.spi.info();
1046        self.spi.pins().sclk_pin = self.connect_output_pin(sclk.into(), info.sclk);
1047
1048        self
1049    }
1050
1051    #[procmacros::doc_replace]
1052    /// Assigns the MOSI (Master Out Slave In) pin for the SPI instance.
1053    ///
1054    /// Enables output functionality for the pin, and connects it as the MOSI
1055    /// signal. Use this for full-duplex SPI or
1056    /// when using [DataMode::SingleTwoDataLines].
1057    ///
1058    /// Disconnects the previous pin that was assigned with `with_mosi` or
1059    /// `with_sio0`.
1060    ///
1061    /// # Examples
1062    ///
1063    /// ```rust, no_run
1064    /// # {before_snippet}
1065    /// use esp_hal::spi::{
1066    ///     Mode,
1067    ///     master::{Config, Spi},
1068    /// };
1069    /// let mut spi = Spi::new(peripherals.SPI2, Config::default())?.with_mosi(peripherals.GPIO1);
1070    ///
1071    /// # {after_snippet}
1072    /// ```
1073    pub fn with_mosi(mut self, mosi: impl PeripheralOutput<'d>) -> Self {
1074        self.spi.pins().sio_pins[0] = self.connect_sio_output_pin(mosi.into(), 0);
1075        self
1076    }
1077
1078    #[procmacros::doc_replace]
1079    /// Assigns the MISO (Master In Slave Out) pin for the SPI instance.
1080    ///
1081    /// Enables input functionality for the pin, and connects it to the MISO
1082    /// signal.
1083    ///
1084    /// Use this for full-duplex SPI or
1085    /// [DataMode::SingleTwoDataLines]
1086    ///
1087    /// # Examples
1088    ///
1089    /// ```rust, no_run
1090    /// # {before_snippet}
1091    /// use esp_hal::spi::{
1092    ///     Mode,
1093    ///     master::{Config, Spi},
1094    /// };
1095    /// let mut spi = Spi::new(peripherals.SPI2, Config::default())?.with_miso(peripherals.GPIO2);
1096    ///
1097    /// # {after_snippet}
1098    /// ```
1099    pub fn with_miso(self, miso: impl PeripheralInput<'d>) -> Self {
1100        let miso = miso.into();
1101
1102        miso.apply_input_config(&InputConfig::default());
1103        miso.set_input_enable(true);
1104
1105        self.driver().info.sio_input(1).connect_to(&miso);
1106
1107        self
1108    }
1109
1110    /// Assigns the SIO0 pin for the SPI instance.
1111    ///
1112    /// Enables both input and output functionality for the pin, and connects it
1113    /// to the MOSI output signal and SIO0 input signal.
1114    ///
1115    /// Disconnects the previous pin that was assigned with `with_sio0` or
1116    /// `with_mosi`.
1117    ///
1118    /// Use this if any of the devices on the bus use half-duplex SPI.
1119    ///
1120    /// See also [Self::with_mosi] for a one-directional MOSI
1121    /// signal.
1122    #[instability::unstable]
1123    pub fn with_sio0(mut self, mosi: impl PeripheralInput<'d> + PeripheralOutput<'d>) -> Self {
1124        self.spi.pins().sio_pins[0] = self.connect_sio_pin(mosi.into(), 0);
1125
1126        self
1127    }
1128
1129    /// Assigns the SIO1/MISO pin for the SPI instance.
1130    ///
1131    /// Enables both input and output functionality for the pin, and connects it
1132    /// to the MISO input signal and SIO1 output signal.
1133    ///
1134    /// Disconnects the previous pin that was assigned with `with_sio1`.
1135    ///
1136    /// Use this if any of the devices on the bus use half-duplex SPI.
1137    ///
1138    /// See also [Self::with_miso] for a one-directional MISO
1139    /// signal.
1140    #[instability::unstable]
1141    pub fn with_sio1(mut self, sio1: impl PeripheralInput<'d> + PeripheralOutput<'d>) -> Self {
1142        self.spi.pins().sio_pins[1] = self.connect_sio_pin(sio1.into(), 1);
1143
1144        self
1145    }
1146
1147    def_with_sio_pin!(with_sio2, 2);
1148    def_with_sio_pin!(with_sio3, 3);
1149
1150    #[cfg(spi_master_has_octal)]
1151    def_with_sio_pin!(with_sio4, 4);
1152
1153    #[cfg(spi_master_has_octal)]
1154    def_with_sio_pin!(with_sio5, 5);
1155
1156    #[cfg(spi_master_has_octal)]
1157    def_with_sio_pin!(with_sio6, 6);
1158
1159    #[cfg(spi_master_has_octal)]
1160    def_with_sio_pin!(with_sio7, 7);
1161
1162    /// Assigns the CS (Chip Select) pin for the SPI instance.
1163    ///
1164    /// Configures the specified pin to push-pull output and connects it to the
1165    /// SPI CS signal.
1166    ///
1167    /// Disconnects the previous pin that was assigned with `with_cs`.
1168    ///
1169    /// # Current Stability Limitations
1170    /// The hardware chip select functionality is limited; only one CS line can
1171    /// be set, regardless of the total number available. There is no
1172    /// mechanism to select which CS line to use.
1173    #[instability::unstable]
1174    pub fn with_cs(mut self, cs: impl PeripheralOutput<'d>) -> Self {
1175        let info = self.spi.info();
1176        self.spi.pins().cs_pin = self.connect_output_pin(cs.into(), info.cs(0));
1177
1178        self
1179    }
1180
1181    #[doc_replace(
1182        "max_frequency" => {
1183            cfg(esp32h2) => "48MHz",
1184            _ => "80MHz",
1185        }
1186    )]
1187    /// Changes the bus configuration.
1188    ///
1189    /// # Examples
1190    ///
1191    /// ```rust, no_run
1192    /// # {before_snippet}
1193    /// use esp_hal::spi::{
1194    ///     Mode,
1195    ///     master::{Config, Spi},
1196    /// };
1197    /// let mut spi = Spi::new(peripherals.SPI2, Config::default())?;
1198    ///
1199    /// spi.apply_config(&Config::default().with_frequency(Rate::from_khz(100)));
1200    /// #
1201    /// # {after_snippet}
1202    /// ```
1203    ///
1204    /// # Errors
1205    ///
1206    /// [`ConfigError::FrequencyOutOfRange`] when frequency passed in config exceeds
1207    /// __max_frequency__ or is below 70 kHz.
1208    pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> {
1209        self.driver().apply_config(config)
1210    }
1211
1212    #[procmacros::doc_replace]
1213    /// Writes bytes to SPI. After writing, flush is called to ensure all data
1214    /// has been transmitted.
1215    ///
1216    /// # Examples
1217    ///
1218    /// ```rust, no_run
1219    /// # {before_snippet}
1220    /// use esp_hal::spi::{
1221    ///     Mode,
1222    ///     master::{Config, Spi},
1223    /// };
1224    /// let mut spi = Spi::new(peripherals.SPI2, Config::default())?
1225    ///     .with_sck(peripherals.GPIO0)
1226    ///     .with_mosi(peripherals.GPIO1)
1227    ///     .with_miso(peripherals.GPIO2)
1228    ///     .into_async();
1229    ///
1230    /// let buffer = [0; 10];
1231    /// spi.write(&buffer)?;
1232    ///
1233    /// # {after_snippet}
1234    /// ```
1235    pub fn write(&mut self, words: &[u8]) -> Result<(), Error> {
1236        let _clock = SpiClockGuard::new(self.spi.info());
1237
1238        self.driver().setup_full_duplex()?;
1239        self.driver().write(words)
1240    }
1241
1242    #[procmacros::doc_replace]
1243    /// Reads bytes from SPI. The provided slice is filled with data received
1244    /// from the slave.
1245    ///
1246    /// # Examples
1247    ///
1248    /// ```rust, no_run
1249    /// # {before_snippet}
1250    /// use esp_hal::spi::{
1251    ///     Mode,
1252    ///     master::{Config, Spi},
1253    /// };
1254    /// let mut spi = Spi::new(peripherals.SPI2, Config::default())?
1255    ///     .with_sck(peripherals.GPIO0)
1256    ///     .with_mosi(peripherals.GPIO1)
1257    ///     .with_miso(peripherals.GPIO2)
1258    ///     .into_async();
1259    ///
1260    /// let mut buffer = [0; 10];
1261    /// spi.read(&mut buffer)?;
1262    ///
1263    /// # {after_snippet}
1264    /// ```
1265    pub fn read(&mut self, words: &mut [u8]) -> Result<(), Error> {
1266        let _clock = SpiClockGuard::new(self.spi.info());
1267        self.driver().setup_full_duplex()?;
1268        self.driver().read(words)
1269    }
1270
1271    #[procmacros::doc_replace]
1272    /// Sends `words` to the slave. The received data will be written to
1273    /// `words`, overwriting its contents.
1274    ///
1275    /// # Examples
1276    ///
1277    /// ```rust, no_run
1278    /// # {before_snippet}
1279    /// use esp_hal::spi::{
1280    ///     Mode,
1281    ///     master::{Config, Spi},
1282    /// };
1283    /// let mut spi = Spi::new(peripherals.SPI2, Config::default())?
1284    ///     .with_sck(peripherals.GPIO0)
1285    ///     .with_mosi(peripherals.GPIO1)
1286    ///     .with_miso(peripherals.GPIO2)
1287    ///     .into_async();
1288    ///
1289    /// let mut buffer = [0; 10];
1290    /// spi.transfer(&mut buffer)?;
1291    ///
1292    /// # {after_snippet}
1293    /// ```
1294    pub fn transfer(&mut self, words: &mut [u8]) -> Result<(), Error> {
1295        let _clock = SpiClockGuard::new(self.spi.info());
1296        self.driver().setup_full_duplex()?;
1297        self.driver().transfer_in_place(words)
1298    }
1299
1300    /// Half-duplex read.
1301    ///
1302    /// Transfers larger than the hardware FIFO are split into chunks. CS remains asserted across
1303    /// chunks, but the clock pauses while the CPU prepares each subsequent chunk.
1304    ///
1305    /// # Errors
1306    ///
1307    /// [`Error::Unsupported`] when the buffer is empty (currently unsupported).
1308    /// `DataMode::Single` cannot be combined with any other [`DataMode`], otherwise
1309    /// [`Error::Unsupported`].
1310    #[instability::unstable]
1311    pub fn half_duplex_read(
1312        &mut self,
1313        data_mode: DataMode,
1314        cmd: Command,
1315        address: Address,
1316        dummy: u8,
1317        buffer: &mut [u8],
1318    ) -> Result<(), Error> {
1319        let _clock = SpiClockGuard::new(self.spi.info());
1320        self.driver()
1321            .half_duplex_read(data_mode, cmd, address, dummy, buffer)
1322    }
1323
1324    /// Half-duplex write.
1325    ///
1326    /// Transfers larger than the hardware FIFO are split into chunks. CS remains asserted across
1327    /// chunks, but the clock pauses while the CPU prepares each subsequent chunk.
1328    ///
1329    /// # Errors
1330    ///
1331    /// [`Error::Unsupported`] for unsupported combinations of command, address,
1332    /// dummy, and data modes.
1333    #[cfg_attr(
1334        esp32,
1335        doc = "Dummy phase configuration is currently not supported, only value `0` is valid (see issue [#2240](https://github.com/esp-rs/esp-hal/issues/2240))."
1336    )]
1337    #[instability::unstable]
1338    pub fn half_duplex_write(
1339        &mut self,
1340        data_mode: DataMode,
1341        cmd: Command,
1342        address: Address,
1343        dummy: u8,
1344        buffer: &[u8],
1345    ) -> Result<(), Error> {
1346        let _clock = SpiClockGuard::new(self.spi.info());
1347        self.driver()
1348            .half_duplex_write(data_mode, cmd, address, dummy, buffer)
1349    }
1350
1351    fn use_blocking_transfer(&self, transfer_size: usize) -> bool {
1352        let threshold = self
1353            .spi
1354            .state()
1355            .min_async_transfer_size
1356            .load(Ordering::Relaxed);
1357        threshold > 0 && transfer_size < threshold
1358    }
1359
1360    fn driver(&self) -> Driver {
1361        Driver {
1362            info: self.spi.info(),
1363            state: self.spi.state(),
1364        }
1365    }
1366}
1367
1368#[instability::unstable]
1369impl<Dm> embassy_embedded_hal::SetConfig for Spi<'_, Dm>
1370where
1371    Dm: DriverMode,
1372{
1373    type Config = Config;
1374    type ConfigError = ConfigError;
1375
1376    fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
1377        self.apply_config(config)
1378    }
1379}
1380
1381impl<Dm> embedded_hal::spi::ErrorType for Spi<'_, Dm>
1382where
1383    Dm: DriverMode,
1384{
1385    type Error = Error;
1386}
1387
1388impl<Dm> SpiBus for Spi<'_, Dm>
1389where
1390    Dm: DriverMode,
1391{
1392    fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
1393        self.read(words)
1394    }
1395
1396    fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
1397        self.write(words)
1398    }
1399
1400    fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
1401        let _clock = SpiClockGuard::new(self.spi.info());
1402        self.driver().setup_full_duplex()?;
1403
1404        if read.is_empty() {
1405            self.driver().write(write)
1406        } else if write.is_empty() {
1407            self.driver().read(read)
1408        } else {
1409            self.driver().transfer(read, write)
1410        }
1411    }
1412
1413    fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
1414        let _clock = SpiClockGuard::new(self.spi.info());
1415        self.driver().setup_full_duplex()?;
1416        self.driver().transfer_in_place(words)
1417    }
1418
1419    fn flush(&mut self) -> Result<(), Self::Error> {
1420        Ok(())
1421    }
1422}
1423
1424impl SpiBusAsync for Spi<'_, Async> {
1425    async fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
1426        self.read_async(words).await
1427    }
1428
1429    async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
1430        self.write_async(words).await
1431    }
1432
1433    async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
1434        let _clock = SpiClockGuard::new(self.spi.info());
1435
1436        self.driver().setup_full_duplex()?;
1437
1438        if self.use_blocking_transfer(read.len().max(write.len())) {
1439            return if read.is_empty() {
1440                self.driver().write(write)
1441            } else if write.is_empty() {
1442                self.driver().read(read)
1443            } else {
1444                self.driver().transfer(read, write)
1445            };
1446        }
1447
1448        if read.is_empty() {
1449            self.driver().write_async(write).await
1450        } else if write.is_empty() {
1451            self.driver().read_async(read).await
1452        } else {
1453            self.driver().transfer_async(read, write).await
1454        }
1455    }
1456
1457    async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
1458        self.transfer_in_place_async(words).await
1459    }
1460
1461    async fn flush(&mut self) -> Result<(), Self::Error> {
1462        Ok(())
1463    }
1464}
1465
1466/// SPI data mode.
1467#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1468#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1469#[instability::unstable]
1470pub enum DataMode {
1471    /// 1 bit, two data lines. (MOSI, MISO)
1472    SingleTwoDataLines,
1473    /// 1 bit, 1 data line (SIO0)
1474    Single,
1475    /// 2 bits, two data lines. (SIO0, SIO1)
1476    Dual,
1477    /// 4 bit, 4 data lines. (SIO0 .. SIO3)
1478    Quad,
1479    #[cfg(spi_master_has_octal)]
1480    /// 8 bit, 8 data lines. (SIO0 .. SIO7)
1481    Octal,
1482}
1483
1484crate::any_peripheral! {
1485    /// Any SPI peripheral.
1486    pub peripheral AnySpi<'d> {
1487        #[cfg(spi_master_spi2)]
1488        Spi2(crate::peripherals::SPI2<'d>),
1489        #[cfg(spi_master_spi3)]
1490        Spi3(crate::peripherals::SPI3<'d>),
1491    }
1492}
1493
1494#[cfg(spi_master_supports_dma)]
1495with_spi_master_dma_engine! {
1496    ($engine:tt, $any_ch:ident) => {
1497        use crate::dma::DmaEligiblePeripheral;
1498
1499        impl<'d> DmaEligiblePeripheral<crate::dma::$any_ch<'d>> for AnySpi<'d> {
1500            fn dma_peripheral(&self) -> crate::dma::DmaPeripheral {
1501                any::delegate!(self, spi => { spi.dma_peripheral() })
1502            }
1503        }
1504    };
1505}
1506
1507impl QspiInstance for AnySpi<'_> {}
1508
1509impl Instance for AnySpi<'_> {
1510    #[inline]
1511    fn parts(&self) -> (&'static Info, &'static State) {
1512        any::delegate!(self, spi => { spi.parts() })
1513    }
1514}
1515
1516impl AnySpi<'_> {
1517    fn bind_peri_interrupt(&self, handler: InterruptHandler) {
1518        any::delegate!(self, spi => { spi.bind_peri_interrupt(handler) })
1519    }
1520
1521    fn disable_peri_interrupt_on_all_cores(&self) {
1522        any::delegate!(self, spi => { spi.disable_peri_interrupt_on_all_cores() })
1523    }
1524
1525    fn set_interrupt_handler(&self, handler: InterruptHandler) {
1526        self.disable_peri_interrupt_on_all_cores();
1527        self.bind_peri_interrupt(handler);
1528    }
1529}