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, we
432    /// cache clock register's value here, for each configuration.
433    ///
434    /// This field is not intended to be set by the user, 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    /// Set 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    /// Set 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 out of pairs forming that divider we want the one
553    /// with the largest `n`.
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/// ## Example
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    /// Constructs an SPI instance in 8bit dataframe mode.
707    ///
708    /// ## Errors
709    ///
710    /// See [`Spi::apply_config`].
711    ///
712    /// ## Example
713    ///
714    /// ```rust, no_run
715    /// # {before_snippet}
716    /// use esp_hal::spi::{
717    ///     Mode,
718    ///     master::{Config, Spi},
719    /// };
720    /// let mut spi = Spi::new(peripherals.SPI2, Config::default())?
721    ///     .with_sck(peripherals.GPIO0)
722    ///     .with_mosi(peripherals.GPIO1)
723    ///     .with_miso(peripherals.GPIO2);
724    /// # {after_snippet}
725    /// ```
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    /// Note that this will replace any previously registered interrupt
770    /// handlers.
771    ///
772    /// You can restore the default/unhandled interrupt handler by using
773    /// [crate::interrupt::DEFAULT_INTERRUPT_HANDLER]
774    ///
775    /// # Panics
776    ///
777    /// Panics if passed interrupt handler is invalid (e.g. has priority
778    /// `None`)
779    #[instability::unstable]
780    pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
781        self.spi.set_interrupt_handler(handler);
782    }
783}
784
785#[instability::unstable]
786impl crate::interrupt::InterruptConfigurable for Spi<'_, Blocking> {
787    /// Sets the interrupt handler
788    ///
789    /// Interrupts are not enabled at the peripheral level here.
790    fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
791        self.set_interrupt_handler(handler);
792    }
793}
794
795impl<'d> Spi<'d, Async> {
796    /// Reconfigures the driver to operate in [`Blocking`] mode.
797    ///
798    /// See the [`Blocking`] documentation for an example on how to use this
799    /// method.
800    pub fn into_blocking(self) -> Spi<'d, Blocking> {
801        self.spi.disable_peri_interrupt_on_all_cores();
802        Spi {
803            spi: self.spi,
804            _mode: PhantomData,
805        }
806    }
807
808    #[procmacros::doc_replace]
809    /// Waits for the completion of previous operations.
810    ///
811    /// ## Example
812    ///
813    /// ```rust, no_run
814    /// # {before_snippet}
815    /// use esp_hal::spi::{
816    ///     Mode,
817    ///     master::{Config, Spi},
818    /// };
819    /// let mut spi = Spi::new(peripherals.SPI2, Config::default())?
820    ///     .with_sck(peripherals.GPIO0)
821    ///     .with_mosi(peripherals.GPIO1)
822    ///     .with_miso(peripherals.GPIO2)
823    ///     .into_async();
824    ///
825    /// let mut buffer = [0; 10];
826    /// spi.transfer_in_place_async(&mut buffer).await?;
827    /// spi.flush_async().await?;
828    ///
829    /// # {after_snippet}
830    /// ```
831    pub async fn flush_async(&mut self) -> Result<(), Error> {
832        Ok(())
833    }
834
835    #[procmacros::doc_replace]
836    /// Sends `words` to the slave. Returns the `words` received from the slave.
837    ///
838    /// This function aborts the transfer when its Future is dropped. Some
839    /// amount of data may have been transferred before the Future is
840    /// dropped. Dropping the future may block for a short while to ensure
841    /// the transfer is aborted.
842    ///
843    /// ## Example
844    ///
845    /// ```rust, no_run
846    /// # {before_snippet}
847    /// use esp_hal::spi::{
848    ///     Mode,
849    ///     master::{Config, Spi},
850    /// };
851    /// let mut spi = Spi::new(peripherals.SPI2, Config::default())?
852    ///     .with_sck(peripherals.GPIO0)
853    ///     .with_mosi(peripherals.GPIO1)
854    ///     .with_miso(peripherals.GPIO2)
855    ///     .into_async();
856    ///
857    /// let mut buffer = [0; 10];
858    /// spi.transfer_in_place_async(&mut buffer).await?;
859    ///
860    /// # {after_snippet}
861    /// ```
862    pub async fn transfer_in_place_async(&mut self, words: &mut [u8]) -> Result<(), Error> {
863        let _clock = SpiClockGuard::new(self.spi.info());
864
865        self.driver().setup_full_duplex()?;
866
867        if self.use_blocking_transfer(words.len()) {
868            return self.driver().transfer_in_place(words);
869        }
870
871        self.driver().transfer_in_place_async(words).await
872    }
873
874    /// Half-duplex read.
875    ///
876    /// Transfers larger than the hardware FIFO are split into chunks. CS remains asserted across
877    /// chunks, but the clock pauses while the CPU prepares each subsequent chunk.
878    ///
879    /// This function aborts the transfer when its Future is dropped. Some amount of data may have
880    /// been transferred before the Future is dropped. Dropping the future may block for a short
881    /// while to ensure the transfer is aborted.
882    ///
883    /// # Errors
884    ///
885    /// [`Error::Unsupported`] will be returned if the buffer is empty (currently unsupported).
886    /// `DataMode::Single` cannot be combined with any other [`DataMode`], otherwise
887    /// [`Error::Unsupported`] will be returned.
888    #[instability::unstable]
889    pub async fn half_duplex_read_async(
890        &mut self,
891        data_mode: DataMode,
892        cmd: Command,
893        address: Address,
894        dummy: u8,
895        buffer: &mut [u8],
896    ) -> Result<(), Error> {
897        let _clock = SpiClockGuard::new(self.spi.info());
898
899        if self.use_blocking_transfer(buffer.len()) {
900            return self
901                .driver()
902                .half_duplex_read(data_mode, cmd, address, dummy, buffer);
903        }
904
905        self.driver()
906            .half_duplex_read_async(data_mode, cmd, address, dummy, buffer)
907            .await
908    }
909
910    /// Half-duplex write.
911    ///
912    /// Transfers larger than the hardware FIFO are split into chunks. CS remains asserted across
913    /// chunks, but the clock pauses while the CPU prepares each subsequent chunk.
914    ///
915    /// This function aborts the transfer when its Future is dropped. Some amount of data may have
916    /// been transferred before the Future is dropped. Dropping the future may block for a short
917    /// while to ensure the transfer is aborted.
918    ///
919    /// # Errors
920    ///
921    /// [`Error::Unsupported`] will be returned for unsupported combinations of command, address,
922    /// dummy, and data modes.
923    #[cfg_attr(
924        esp32,
925        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))."
926    )]
927    #[instability::unstable]
928    pub async fn half_duplex_write_async(
929        &mut self,
930        data_mode: DataMode,
931        cmd: Command,
932        address: Address,
933        dummy: u8,
934        buffer: &[u8],
935    ) -> Result<(), Error> {
936        let _clock = SpiClockGuard::new(self.spi.info());
937
938        if self.use_blocking_transfer(buffer.len()) {
939            return self
940                .driver()
941                .half_duplex_write(data_mode, cmd, address, dummy, buffer);
942        }
943
944        self.driver()
945            .half_duplex_write_async(data_mode, cmd, address, dummy, buffer)
946            .await
947    }
948
949    // TODO: These inherent methods should be public
950
951    async fn read_async(&mut self, words: &mut [u8]) -> Result<(), Error> {
952        let _clock = SpiClockGuard::new(self.spi.info());
953
954        self.driver().setup_full_duplex()?;
955
956        if self.use_blocking_transfer(words.len()) {
957            return self.driver().read(words);
958        }
959
960        self.driver().read_async(words).await
961    }
962
963    async fn write_async(&mut self, words: &[u8]) -> Result<(), Error> {
964        let _clock = SpiClockGuard::new(self.spi.info());
965
966        self.driver().setup_full_duplex()?;
967
968        if self.use_blocking_transfer(words.len()) {
969            return self.driver().write(words);
970        }
971
972        self.driver().write_async(words).await
973    }
974}
975
976macro_rules! def_with_sio_pin {
977    ($fn:ident, $n:literal) => {
978        #[doc = concat!(" Assign the SIO", stringify!($n), " pin for the SPI instance.")]
979        #[doc = " "]
980        #[doc = " Enables both input and output functionality for the pin, and connects it"]
981        #[doc = concat!(" to the SIO", stringify!($n), " output and input signals.")]
982        #[instability::unstable]
983        pub fn $fn(mut self, sio: impl PeripheralInput<'d> + PeripheralOutput<'d>) -> Self {
984            self.spi.pins().sio_pins[$n] = self.connect_sio_pin(sio.into(), $n);
985
986            self
987        }
988    };
989}
990
991impl<'d, Dm> Spi<'d, Dm>
992where
993    Dm: DriverMode,
994{
995    fn connect_sio_pin(&self, pin: interconnect::OutputSignal<'d>, n: usize) -> PinGuard {
996        let in_signal = self.spi.info().sio_input(n);
997        let out_signal = self.spi.info().sio_output(n);
998
999        pin.apply_input_config(&InputConfig::default());
1000        pin.apply_output_config(&OutputConfig::default());
1001
1002        pin.set_input_enable(true);
1003        pin.set_output_enable(false);
1004
1005        in_signal.connect_to(&pin);
1006        pin.connect_with_guard(out_signal)
1007    }
1008
1009    fn connect_sio_output_pin(&self, pin: interconnect::OutputSignal<'d>, n: usize) -> PinGuard {
1010        let out_signal = self.spi.info().sio_output(n);
1011
1012        self.connect_output_pin(pin, out_signal)
1013    }
1014
1015    fn connect_output_pin(
1016        &self,
1017        pin: interconnect::OutputSignal<'d>,
1018        signal: OutputSignal,
1019    ) -> PinGuard {
1020        pin.apply_output_config(&OutputConfig::default());
1021        pin.set_output_enable(true); // TODO turn this bool into a Yes/No/PeripheralControl trio
1022
1023        pin.connect_with_guard(signal)
1024    }
1025
1026    #[procmacros::doc_replace]
1027    /// Assign the SCK (Serial Clock) pin for the SPI instance.
1028    ///
1029    /// Configures the specified pin to push-pull output and connects it to the
1030    /// SPI clock signal.
1031    ///
1032    /// Disconnects the previous pin that was assigned with `with_sck`.
1033    ///
1034    /// ## Example
1035    ///
1036    /// ```rust, no_run
1037    /// # {before_snippet}
1038    /// use esp_hal::spi::{
1039    ///     Mode,
1040    ///     master::{Config, Spi},
1041    /// };
1042    /// let mut spi = Spi::new(peripherals.SPI2, Config::default())?.with_sck(peripherals.GPIO0);
1043    ///
1044    /// # {after_snippet}
1045    /// ```
1046    pub fn with_sck(mut self, sclk: impl PeripheralOutput<'d>) -> Self {
1047        let info = self.spi.info();
1048        self.spi.pins().sclk_pin = self.connect_output_pin(sclk.into(), info.sclk);
1049
1050        self
1051    }
1052
1053    #[procmacros::doc_replace]
1054    /// Assign the MOSI (Master Out Slave In) pin for the SPI instance.
1055    ///
1056    /// Enables output functionality for the pin, and connects it as the MOSI
1057    /// signal. You want to use this for full-duplex SPI or
1058    /// if you intend to use [DataMode::SingleTwoDataLines].
1059    ///
1060    /// Disconnects the previous pin that was assigned with `with_mosi` or
1061    /// `with_sio0`.
1062    ///
1063    /// ## Example
1064    ///
1065    /// ```rust, no_run
1066    /// # {before_snippet}
1067    /// use esp_hal::spi::{
1068    ///     Mode,
1069    ///     master::{Config, Spi},
1070    /// };
1071    /// let mut spi = Spi::new(peripherals.SPI2, Config::default())?.with_mosi(peripherals.GPIO1);
1072    ///
1073    /// # {after_snippet}
1074    /// ```
1075    pub fn with_mosi(mut self, mosi: impl PeripheralOutput<'d>) -> Self {
1076        self.spi.pins().sio_pins[0] = self.connect_sio_output_pin(mosi.into(), 0);
1077        self
1078    }
1079
1080    #[procmacros::doc_replace]
1081    /// Assign the MISO (Master In Slave Out) pin for the SPI instance.
1082    ///
1083    /// Enables input functionality for the pin, and connects it to the MISO
1084    /// signal.
1085    ///
1086    /// You want to use this for full-duplex SPI or
1087    /// [DataMode::SingleTwoDataLines]
1088    ///
1089    /// ## Example
1090    ///
1091    /// ```rust, no_run
1092    /// # {before_snippet}
1093    /// use esp_hal::spi::{
1094    ///     Mode,
1095    ///     master::{Config, Spi},
1096    /// };
1097    /// let mut spi = Spi::new(peripherals.SPI2, Config::default())?.with_miso(peripherals.GPIO2);
1098    ///
1099    /// # {after_snippet}
1100    /// ```
1101    pub fn with_miso(self, miso: impl PeripheralInput<'d>) -> Self {
1102        let miso = miso.into();
1103
1104        miso.apply_input_config(&InputConfig::default());
1105        miso.set_input_enable(true);
1106
1107        self.driver().info.sio_input(1).connect_to(&miso);
1108
1109        self
1110    }
1111
1112    /// Assign the SIO0 pin for the SPI instance.
1113    ///
1114    /// Enables both input and output functionality for the pin, and connects it
1115    /// to the MOSI output signal and SIO0 input signal.
1116    ///
1117    /// Disconnects the previous pin that was assigned with `with_sio0` or
1118    /// `with_mosi`.
1119    ///
1120    /// Use this if any of the devices on the bus use half-duplex SPI.
1121    ///
1122    /// See also [Self::with_mosi] when you only need a one-directional MOSI
1123    /// signal.
1124    #[instability::unstable]
1125    pub fn with_sio0(mut self, mosi: impl PeripheralInput<'d> + PeripheralOutput<'d>) -> Self {
1126        self.spi.pins().sio_pins[0] = self.connect_sio_pin(mosi.into(), 0);
1127
1128        self
1129    }
1130
1131    /// Assign the SIO1/MISO pin for the SPI instance.
1132    ///
1133    /// Enables both input and output functionality for the pin, and connects it
1134    /// to the MISO input signal and SIO1 output signal.
1135    ///
1136    /// Disconnects the previous pin that was assigned with `with_sio1`.
1137    ///
1138    /// Use this if any of the devices on the bus use half-duplex SPI.
1139    ///
1140    /// See also [Self::with_miso] when you only need a one-directional MISO
1141    /// signal.
1142    #[instability::unstable]
1143    pub fn with_sio1(mut self, sio1: impl PeripheralInput<'d> + PeripheralOutput<'d>) -> Self {
1144        self.spi.pins().sio_pins[1] = self.connect_sio_pin(sio1.into(), 1);
1145
1146        self
1147    }
1148
1149    def_with_sio_pin!(with_sio2, 2);
1150    def_with_sio_pin!(with_sio3, 3);
1151
1152    #[cfg(spi_master_has_octal)]
1153    def_with_sio_pin!(with_sio4, 4);
1154
1155    #[cfg(spi_master_has_octal)]
1156    def_with_sio_pin!(with_sio5, 5);
1157
1158    #[cfg(spi_master_has_octal)]
1159    def_with_sio_pin!(with_sio6, 6);
1160
1161    #[cfg(spi_master_has_octal)]
1162    def_with_sio_pin!(with_sio7, 7);
1163
1164    /// Assign the CS (Chip Select) pin for the SPI instance.
1165    ///
1166    /// Configures the specified pin to push-pull output and connects it to the
1167    /// SPI CS signal.
1168    ///
1169    /// Disconnects the previous pin that was assigned with `with_cs`.
1170    ///
1171    /// # Current Stability Limitations
1172    /// The hardware chip select functionality is limited; only one CS line can
1173    /// be set, regardless of the total number available. There is no
1174    /// mechanism to select which CS line to use.
1175    #[instability::unstable]
1176    pub fn with_cs(mut self, cs: impl PeripheralOutput<'d>) -> Self {
1177        let info = self.spi.info();
1178        self.spi.pins().cs_pin = self.connect_output_pin(cs.into(), info.cs(0));
1179
1180        self
1181    }
1182
1183    #[doc_replace(
1184        "max_frequency" => {
1185            cfg(esp32h2) => "48MHz",
1186            _ => "80MHz",
1187        }
1188    )]
1189    /// Change the bus configuration.
1190    ///
1191    /// # Errors
1192    ///
1193    /// If frequency passed in config exceeds __max_frequency__ or is below 70kHz,
1194    /// [`ConfigError::FrequencyOutOfRange`] error will be returned.
1195    ///
1196    /// ## Example
1197    ///
1198    /// ```rust, no_run
1199    /// # {before_snippet}
1200    /// use esp_hal::spi::{
1201    ///     Mode,
1202    ///     master::{Config, Spi},
1203    /// };
1204    /// let mut spi = Spi::new(peripherals.SPI2, Config::default())?;
1205    ///
1206    /// spi.apply_config(&Config::default().with_frequency(Rate::from_khz(100)));
1207    /// #
1208    /// # {after_snippet}
1209    /// ```
1210    pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> {
1211        self.driver().apply_config(config)
1212    }
1213
1214    #[procmacros::doc_replace]
1215    /// Write bytes to SPI. After writing, flush is called to ensure all data
1216    /// has been transmitted.
1217    ///
1218    /// ## Example
1219    ///
1220    /// ```rust, no_run
1221    /// # {before_snippet}
1222    /// use esp_hal::spi::{
1223    ///     Mode,
1224    ///     master::{Config, Spi},
1225    /// };
1226    /// let mut spi = Spi::new(peripherals.SPI2, Config::default())?
1227    ///     .with_sck(peripherals.GPIO0)
1228    ///     .with_mosi(peripherals.GPIO1)
1229    ///     .with_miso(peripherals.GPIO2)
1230    ///     .into_async();
1231    ///
1232    /// let buffer = [0; 10];
1233    /// spi.write(&buffer)?;
1234    ///
1235    /// # {after_snippet}
1236    /// ```
1237    pub fn write(&mut self, words: &[u8]) -> Result<(), Error> {
1238        let _clock = SpiClockGuard::new(self.spi.info());
1239
1240        self.driver().setup_full_duplex()?;
1241        self.driver().write(words)
1242    }
1243
1244    #[procmacros::doc_replace]
1245    /// Read bytes from SPI. The provided slice is filled with data received
1246    /// from the slave.
1247    ///
1248    /// ## Example
1249    ///
1250    /// ```rust, no_run
1251    /// # {before_snippet}
1252    /// use esp_hal::spi::{
1253    ///     Mode,
1254    ///     master::{Config, Spi},
1255    /// };
1256    /// let mut spi = Spi::new(peripherals.SPI2, Config::default())?
1257    ///     .with_sck(peripherals.GPIO0)
1258    ///     .with_mosi(peripherals.GPIO1)
1259    ///     .with_miso(peripherals.GPIO2)
1260    ///     .into_async();
1261    ///
1262    /// let mut buffer = [0; 10];
1263    /// spi.read(&mut buffer)?;
1264    ///
1265    /// # {after_snippet}
1266    /// ```
1267    pub fn read(&mut self, words: &mut [u8]) -> Result<(), Error> {
1268        let _clock = SpiClockGuard::new(self.spi.info());
1269        self.driver().setup_full_duplex()?;
1270        self.driver().read(words)
1271    }
1272
1273    #[procmacros::doc_replace]
1274    /// Sends `words` to the slave. The received data will be written to
1275    /// `words`, overwriting its contents.
1276    ///
1277    /// ## Example
1278    ///
1279    /// ```rust, no_run
1280    /// # {before_snippet}
1281    /// use esp_hal::spi::{
1282    ///     Mode,
1283    ///     master::{Config, Spi},
1284    /// };
1285    /// let mut spi = Spi::new(peripherals.SPI2, Config::default())?
1286    ///     .with_sck(peripherals.GPIO0)
1287    ///     .with_mosi(peripherals.GPIO1)
1288    ///     .with_miso(peripherals.GPIO2)
1289    ///     .into_async();
1290    ///
1291    /// let mut buffer = [0; 10];
1292    /// spi.transfer(&mut buffer)?;
1293    ///
1294    /// # {after_snippet}
1295    /// ```
1296    pub fn transfer(&mut self, words: &mut [u8]) -> Result<(), Error> {
1297        let _clock = SpiClockGuard::new(self.spi.info());
1298        self.driver().setup_full_duplex()?;
1299        self.driver().transfer_in_place(words)
1300    }
1301
1302    /// Half-duplex read.
1303    ///
1304    /// Transfers larger than the hardware FIFO are split into chunks. CS remains asserted across
1305    /// chunks, but the clock pauses while the CPU prepares each subsequent chunk.
1306    ///
1307    /// # Errors
1308    ///
1309    /// [`Error::Unsupported`] will be returned if the buffer is empty (currently unsupported).
1310    /// `DataMode::Single` cannot be combined with any other [`DataMode`], otherwise
1311    /// [`Error::Unsupported`] will be returned.
1312    #[instability::unstable]
1313    pub fn half_duplex_read(
1314        &mut self,
1315        data_mode: DataMode,
1316        cmd: Command,
1317        address: Address,
1318        dummy: u8,
1319        buffer: &mut [u8],
1320    ) -> Result<(), Error> {
1321        let _clock = SpiClockGuard::new(self.spi.info());
1322        self.driver()
1323            .half_duplex_read(data_mode, cmd, address, dummy, buffer)
1324    }
1325
1326    /// Half-duplex write.
1327    ///
1328    /// Transfers larger than the hardware FIFO are split into chunks. CS remains asserted across
1329    /// chunks, but the clock pauses while the CPU prepares each subsequent chunk.
1330    ///
1331    /// # Errors
1332    ///
1333    /// [`Error::Unsupported`] will be returned for unsupported combinations of command, address,
1334    /// dummy, and data modes.
1335    #[cfg_attr(
1336        esp32,
1337        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))."
1338    )]
1339    #[instability::unstable]
1340    pub fn half_duplex_write(
1341        &mut self,
1342        data_mode: DataMode,
1343        cmd: Command,
1344        address: Address,
1345        dummy: u8,
1346        buffer: &[u8],
1347    ) -> Result<(), Error> {
1348        let _clock = SpiClockGuard::new(self.spi.info());
1349        self.driver()
1350            .half_duplex_write(data_mode, cmd, address, dummy, buffer)
1351    }
1352
1353    fn use_blocking_transfer(&self, transfer_size: usize) -> bool {
1354        let threshold = self
1355            .spi
1356            .state()
1357            .min_async_transfer_size
1358            .load(Ordering::Relaxed);
1359        threshold > 0 && transfer_size < threshold
1360    }
1361
1362    fn driver(&self) -> Driver {
1363        Driver {
1364            info: self.spi.info(),
1365            state: self.spi.state(),
1366        }
1367    }
1368}
1369
1370#[instability::unstable]
1371impl<Dm> embassy_embedded_hal::SetConfig for Spi<'_, Dm>
1372where
1373    Dm: DriverMode,
1374{
1375    type Config = Config;
1376    type ConfigError = ConfigError;
1377
1378    fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
1379        self.apply_config(config)
1380    }
1381}
1382
1383impl<Dm> embedded_hal::spi::ErrorType for Spi<'_, Dm>
1384where
1385    Dm: DriverMode,
1386{
1387    type Error = Error;
1388}
1389
1390impl<Dm> SpiBus for Spi<'_, Dm>
1391where
1392    Dm: DriverMode,
1393{
1394    fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
1395        self.read(words)
1396    }
1397
1398    fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
1399        self.write(words)
1400    }
1401
1402    fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
1403        let _clock = SpiClockGuard::new(self.spi.info());
1404        self.driver().setup_full_duplex()?;
1405
1406        if read.is_empty() {
1407            self.driver().write(write)
1408        } else if write.is_empty() {
1409            self.driver().read(read)
1410        } else {
1411            self.driver().transfer(read, write)
1412        }
1413    }
1414
1415    fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
1416        let _clock = SpiClockGuard::new(self.spi.info());
1417        self.driver().setup_full_duplex()?;
1418        self.driver().transfer_in_place(words)
1419    }
1420
1421    fn flush(&mut self) -> Result<(), Self::Error> {
1422        Ok(())
1423    }
1424}
1425
1426impl SpiBusAsync for Spi<'_, Async> {
1427    async fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
1428        self.read_async(words).await
1429    }
1430
1431    async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
1432        self.write_async(words).await
1433    }
1434
1435    async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
1436        let _clock = SpiClockGuard::new(self.spi.info());
1437
1438        self.driver().setup_full_duplex()?;
1439
1440        if self.use_blocking_transfer(read.len().max(write.len())) {
1441            return if read.is_empty() {
1442                self.driver().write(write)
1443            } else if write.is_empty() {
1444                self.driver().read(read)
1445            } else {
1446                self.driver().transfer(read, write)
1447            };
1448        }
1449
1450        if read.is_empty() {
1451            self.driver().write_async(write).await
1452        } else if write.is_empty() {
1453            self.driver().read_async(read).await
1454        } else {
1455            self.driver().transfer_async(read, write).await
1456        }
1457    }
1458
1459    async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
1460        self.transfer_in_place_async(words).await
1461    }
1462
1463    async fn flush(&mut self) -> Result<(), Self::Error> {
1464        Ok(())
1465    }
1466}
1467
1468/// SPI data mode
1469#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1470#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1471#[instability::unstable]
1472pub enum DataMode {
1473    /// 1 bit, two data lines. (MOSI, MISO)
1474    SingleTwoDataLines,
1475    /// 1 bit, 1 data line (SIO0)
1476    Single,
1477    /// 2 bits, two data lines. (SIO0, SIO1)
1478    Dual,
1479    /// 4 bit, 4 data lines. (SIO0 .. SIO3)
1480    Quad,
1481    #[cfg(spi_master_has_octal)]
1482    /// 8 bit, 8 data lines. (SIO0 .. SIO7)
1483    Octal,
1484}
1485
1486crate::any_peripheral! {
1487    /// Any SPI peripheral.
1488    pub peripheral AnySpi<'d> {
1489        #[cfg(spi_master_spi2)]
1490        Spi2(crate::peripherals::SPI2<'d>),
1491        #[cfg(spi_master_spi3)]
1492        Spi3(crate::peripherals::SPI3<'d>),
1493    }
1494}
1495
1496#[cfg(spi_master_supports_dma)]
1497with_spi_master_dma_engine! {
1498    ($engine:tt, $any_ch:ident) => {
1499        use crate::dma::DmaEligiblePeripheral;
1500
1501        impl<'d> DmaEligiblePeripheral<crate::dma::$any_ch<'d>> for AnySpi<'d> {
1502            fn dma_peripheral(&self) -> crate::dma::DmaPeripheral {
1503                any::delegate!(self, spi => { spi.dma_peripheral() })
1504            }
1505        }
1506    };
1507}
1508
1509impl QspiInstance for AnySpi<'_> {}
1510
1511impl Instance for AnySpi<'_> {
1512    #[inline]
1513    fn parts(&self) -> (&'static Info, &'static State) {
1514        any::delegate!(self, spi => { spi.parts() })
1515    }
1516}
1517
1518impl AnySpi<'_> {
1519    fn bind_peri_interrupt(&self, handler: InterruptHandler) {
1520        any::delegate!(self, spi => { spi.bind_peri_interrupt(handler) })
1521    }
1522
1523    fn disable_peri_interrupt_on_all_cores(&self) {
1524        any::delegate!(self, spi => { spi.disable_peri_interrupt_on_all_cores() })
1525    }
1526
1527    fn set_interrupt_handler(&self, handler: InterruptHandler) {
1528        self.disable_peri_interrupt_on_all_cores();
1529        self.bind_peri_interrupt(handler);
1530    }
1531}