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}