1use 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#[derive(Debug, Hash, EnumSetType)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))]
75#[non_exhaustive]
76#[instability::unstable]
77pub enum SpiInterrupt {
78 TransferDone,
83
84 #[cfg(spi_master_has_dma_segmented_transfer)]
86 DmaSegmentedTransferDone,
87
88 #[cfg(spi_master_has_app_interrupts)]
90 App2,
91
92 #[cfg(spi_master_has_app_interrupts)]
94 App1,
95}
96
97const FIFO_SIZE: usize = property!("spi_master.fifo_size");
99
100const EMPTY_WRITE_PAD: u8 = 0x00;
102
103#[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 None,
114 _1Bit(u16, DataMode),
116 _2Bit(u16, DataMode),
118 _3Bit(u16, DataMode),
120 _4Bit(u16, DataMode),
122 _5Bit(u16, DataMode),
124 _6Bit(u16, DataMode),
126 _7Bit(u16, DataMode),
128 _8Bit(u16, DataMode),
130 _9Bit(u16, DataMode),
132 _10Bit(u16, DataMode),
134 _11Bit(u16, DataMode),
136 _12Bit(u16, DataMode),
138 _13Bit(u16, DataMode),
140 _14Bit(u16, DataMode),
142 _15Bit(u16, DataMode),
144 _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#[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 None,
231 _1Bit(u32, DataMode),
233 _2Bit(u32, DataMode),
235 _3Bit(u32, DataMode),
237 _4Bit(u32, DataMode),
239 _5Bit(u32, DataMode),
241 _6Bit(u32, DataMode),
243 _7Bit(u32, DataMode),
245 _8Bit(u32, DataMode),
247 _9Bit(u32, DataMode),
249 _10Bit(u32, DataMode),
251 _11Bit(u32, DataMode),
253 _12Bit(u32, DataMode),
255 _13Bit(u32, DataMode),
257 _14Bit(u32, DataMode),
259 _15Bit(u32, DataMode),
261 _16Bit(u32, DataMode),
263 _17Bit(u32, DataMode),
265 _18Bit(u32, DataMode),
267 _19Bit(u32, DataMode),
269 _20Bit(u32, DataMode),
271 _21Bit(u32, DataMode),
273 _22Bit(u32, DataMode),
275 _23Bit(u32, DataMode),
277 _24Bit(u32, DataMode),
279 _25Bit(u32, DataMode),
281 _26Bit(u32, DataMode),
283 _27Bit(u32, DataMode),
285 _28Bit(u32, DataMode),
287 _29Bit(u32, DataMode),
289 _30Bit(u32, DataMode),
291 _31Bit(u32, DataMode),
293 _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#[instability::unstable]
419pub use crate::soc::clocks::SpiFunctionClockConfig as ClockSource;
420
421#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, procmacros::BuilderLite)]
423#[cfg_attr(feature = "defmt", derive(defmt::Format))]
424#[non_exhaustive]
425pub struct Config {
426 #[builder_lite(skip)]
437 reg: Result<u32, ConfigError>,
438
439 #[builder_lite(skip_setter)]
441 frequency: Rate,
442
443 #[builder_lite(unstable)]
445 #[builder_lite(skip_setter)]
446 clock_source: ClockSource,
447
448 mode: Mode,
450
451 read_bit_order: BitOrder,
453
454 write_bit_order: BitOrder,
456
457 #[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 pub fn with_frequency(mut self, frequency: Rate) -> Self {
497 self.frequency = frequency;
498 self.reg = self.recalculate();
499
500 self
501 }
502
503 #[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 let source_freq = self.clock_source_freq_hz();
522
523 if self.frequency >= source_freq {
527 return Ok(1 << 31);
530 }
531
532 let (n, pre) = Self::divider_pair(source_freq.as_hz(), self.frequency.as_hz());
533
534 let l = n;
536
537 let h = (n / 2).max(1);
539
540 Ok((l - 1) | ((h - 1) << 6) | ((n - 1) << 12) | ((pre - 1) << 18)) }
545
546 fn divider_pair(source_freq_hz: u32, target_freq_hz: u32) -> (u32, u32) {
558 if target_freq_hz == 0 {
561 return (64, 16);
562 }
563
564 let min_divider = source_freq_hz.div_ceil(target_freq_hz).max(2);
567
568 if min_divider <= 64 {
572 return (min_divider, 1);
573 }
574
575 let mut best = (64, 16);
584 let mut best_divider = 64 * 16;
585
586 let mut pre = min_divider.div_ceil(64);
590 while pre <= 16 {
591 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 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 let max_divider = 16 * 64; 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#[non_exhaustive]
654#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
655#[cfg_attr(feature = "defmt", derive(defmt::Format))]
656pub enum ConfigError {
657 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#[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 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 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 #[instability::unstable]
779 pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
780 self.spi.set_interrupt_handler(handler);
781 }
782}
783
784#[instability::unstable]
785impl crate::interrupt::InterruptConfigurable for Spi<'_, Blocking> {
786 fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
790 self.set_interrupt_handler(handler);
791 }
792}
793
794impl<'d> Spi<'d, Async> {
795 pub fn into_blocking(self) -> Spi<'d, Blocking> {
800 self.spi.disable_peri_interrupt_on_all_cores();
801 Spi {
802 spi: self.spi,
803 _mode: PhantomData,
804 }
805 }
806
807 #[procmacros::doc_replace]
808 pub async fn flush_async(&mut self) -> Result<(), Error> {
831 Ok(())
832 }
833
834 #[procmacros::doc_replace]
835 pub async fn transfer_in_place_async(&mut self, words: &mut [u8]) -> Result<(), Error> {
861 let _clock = SpiClockGuard::new(self.spi.info());
862
863 self.driver().setup_full_duplex()?;
864
865 if self.use_blocking_transfer(words.len()) {
866 return self.driver().transfer_in_place(words);
867 }
868
869 self.driver().transfer_in_place_async(words).await
870 }
871
872 #[instability::unstable]
887 pub async fn half_duplex_read_async(
888 &mut self,
889 data_mode: DataMode,
890 cmd: Command,
891 address: Address,
892 dummy: u8,
893 buffer: &mut [u8],
894 ) -> Result<(), Error> {
895 let _clock = SpiClockGuard::new(self.spi.info());
896
897 if self.use_blocking_transfer(buffer.len()) {
898 return self
899 .driver()
900 .half_duplex_read(data_mode, cmd, address, dummy, buffer);
901 }
902
903 self.driver()
904 .half_duplex_read_async(data_mode, cmd, address, dummy, buffer)
905 .await
906 }
907
908 #[cfg_attr(
922 esp32,
923 doc = "Dummy phase configuration is currently not supported, only value `0` is valid (see issue [#2240](https://github.com/esp-rs/esp-hal/issues/2240))."
924 )]
925 #[instability::unstable]
926 pub async fn half_duplex_write_async(
927 &mut self,
928 data_mode: DataMode,
929 cmd: Command,
930 address: Address,
931 dummy: u8,
932 buffer: &[u8],
933 ) -> Result<(), Error> {
934 let _clock = SpiClockGuard::new(self.spi.info());
935
936 if self.use_blocking_transfer(buffer.len()) {
937 return self
938 .driver()
939 .half_duplex_write(data_mode, cmd, address, dummy, buffer);
940 }
941
942 self.driver()
943 .half_duplex_write_async(data_mode, cmd, address, dummy, buffer)
944 .await
945 }
946
947 async fn read_async(&mut self, words: &mut [u8]) -> Result<(), Error> {
950 let _clock = SpiClockGuard::new(self.spi.info());
951
952 self.driver().setup_full_duplex()?;
953
954 if self.use_blocking_transfer(words.len()) {
955 return self.driver().read(words);
956 }
957
958 self.driver().read_async(words).await
959 }
960
961 async fn write_async(&mut self, words: &[u8]) -> Result<(), Error> {
962 let _clock = SpiClockGuard::new(self.spi.info());
963
964 self.driver().setup_full_duplex()?;
965
966 if self.use_blocking_transfer(words.len()) {
967 return self.driver().write(words);
968 }
969
970 self.driver().write_async(words).await
971 }
972}
973
974macro_rules! def_with_sio_pin {
975 ($fn:ident, $n:literal) => {
976 #[doc = concat!(" Assign the SIO", stringify!($n), " pin for the SPI instance.")]
977 #[doc = " "]
978 #[doc = " Enables both input and output functionality for the pin, and connects it"]
979 #[doc = concat!(" to the SIO", stringify!($n), " output and input signals.")]
980 #[instability::unstable]
981 pub fn $fn(mut self, sio: impl PeripheralInput<'d> + PeripheralOutput<'d>) -> Self {
982 self.spi.pins().sio_pins[$n] = self.connect_sio_pin(sio.into(), $n);
983
984 self
985 }
986 };
987}
988
989impl<'d, Dm> Spi<'d, Dm>
990where
991 Dm: DriverMode,
992{
993 fn connect_sio_pin(&self, pin: interconnect::OutputSignal<'d>, n: usize) -> PinGuard {
994 let in_signal = self.spi.info().sio_input(n);
995 let out_signal = self.spi.info().sio_output(n);
996
997 pin.apply_input_config(&InputConfig::default());
998 pin.apply_output_config(&OutputConfig::default());
999
1000 pin.set_input_enable(true);
1001 pin.set_output_enable(false);
1002
1003 in_signal.connect_to(&pin);
1004 pin.connect_with_guard(out_signal)
1005 }
1006
1007 fn connect_sio_output_pin(&self, pin: interconnect::OutputSignal<'d>, n: usize) -> PinGuard {
1008 let out_signal = self.spi.info().sio_output(n);
1009
1010 self.connect_output_pin(pin, out_signal)
1011 }
1012
1013 fn connect_output_pin(
1014 &self,
1015 pin: interconnect::OutputSignal<'d>,
1016 signal: OutputSignal,
1017 ) -> PinGuard {
1018 pin.apply_output_config(&OutputConfig::default());
1019 pin.set_output_enable(true); pin.connect_with_guard(signal)
1022 }
1023
1024 #[procmacros::doc_replace]
1025 pub fn with_sck(mut self, sclk: impl PeripheralOutput<'d>) -> Self {
1045 let info = self.spi.info();
1046 self.spi.pins().sclk_pin = self.connect_output_pin(sclk.into(), info.sclk);
1047
1048 self
1049 }
1050
1051 #[procmacros::doc_replace]
1052 pub fn with_mosi(mut self, mosi: impl PeripheralOutput<'d>) -> Self {
1074 self.spi.pins().sio_pins[0] = self.connect_sio_output_pin(mosi.into(), 0);
1075 self
1076 }
1077
1078 #[procmacros::doc_replace]
1079 pub fn with_miso(self, miso: impl PeripheralInput<'d>) -> Self {
1100 let miso = miso.into();
1101
1102 miso.apply_input_config(&InputConfig::default());
1103 miso.set_input_enable(true);
1104
1105 self.driver().info.sio_input(1).connect_to(&miso);
1106
1107 self
1108 }
1109
1110 #[instability::unstable]
1123 pub fn with_sio0(mut self, mosi: impl PeripheralInput<'d> + PeripheralOutput<'d>) -> Self {
1124 self.spi.pins().sio_pins[0] = self.connect_sio_pin(mosi.into(), 0);
1125
1126 self
1127 }
1128
1129 #[instability::unstable]
1141 pub fn with_sio1(mut self, sio1: impl PeripheralInput<'d> + PeripheralOutput<'d>) -> Self {
1142 self.spi.pins().sio_pins[1] = self.connect_sio_pin(sio1.into(), 1);
1143
1144 self
1145 }
1146
1147 def_with_sio_pin!(with_sio2, 2);
1148 def_with_sio_pin!(with_sio3, 3);
1149
1150 #[cfg(spi_master_has_octal)]
1151 def_with_sio_pin!(with_sio4, 4);
1152
1153 #[cfg(spi_master_has_octal)]
1154 def_with_sio_pin!(with_sio5, 5);
1155
1156 #[cfg(spi_master_has_octal)]
1157 def_with_sio_pin!(with_sio6, 6);
1158
1159 #[cfg(spi_master_has_octal)]
1160 def_with_sio_pin!(with_sio7, 7);
1161
1162 #[instability::unstable]
1174 pub fn with_cs(mut self, cs: impl PeripheralOutput<'d>) -> Self {
1175 let info = self.spi.info();
1176 self.spi.pins().cs_pin = self.connect_output_pin(cs.into(), info.cs(0));
1177
1178 self
1179 }
1180
1181 #[doc_replace(
1182 "max_frequency" => {
1183 cfg(esp32h2) => "48MHz",
1184 _ => "80MHz",
1185 }
1186 )]
1187 pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> {
1209 self.driver().apply_config(config)
1210 }
1211
1212 #[procmacros::doc_replace]
1213 pub fn write(&mut self, words: &[u8]) -> Result<(), Error> {
1236 let _clock = SpiClockGuard::new(self.spi.info());
1237
1238 self.driver().setup_full_duplex()?;
1239 self.driver().write(words)
1240 }
1241
1242 #[procmacros::doc_replace]
1243 pub fn read(&mut self, words: &mut [u8]) -> Result<(), Error> {
1266 let _clock = SpiClockGuard::new(self.spi.info());
1267 self.driver().setup_full_duplex()?;
1268 self.driver().read(words)
1269 }
1270
1271 #[procmacros::doc_replace]
1272 pub fn transfer(&mut self, words: &mut [u8]) -> Result<(), Error> {
1295 let _clock = SpiClockGuard::new(self.spi.info());
1296 self.driver().setup_full_duplex()?;
1297 self.driver().transfer_in_place(words)
1298 }
1299
1300 #[instability::unstable]
1311 pub fn half_duplex_read(
1312 &mut self,
1313 data_mode: DataMode,
1314 cmd: Command,
1315 address: Address,
1316 dummy: u8,
1317 buffer: &mut [u8],
1318 ) -> Result<(), Error> {
1319 let _clock = SpiClockGuard::new(self.spi.info());
1320 self.driver()
1321 .half_duplex_read(data_mode, cmd, address, dummy, buffer)
1322 }
1323
1324 #[cfg_attr(
1334 esp32,
1335 doc = "Dummy phase configuration is currently not supported, only value `0` is valid (see issue [#2240](https://github.com/esp-rs/esp-hal/issues/2240))."
1336 )]
1337 #[instability::unstable]
1338 pub fn half_duplex_write(
1339 &mut self,
1340 data_mode: DataMode,
1341 cmd: Command,
1342 address: Address,
1343 dummy: u8,
1344 buffer: &[u8],
1345 ) -> Result<(), Error> {
1346 let _clock = SpiClockGuard::new(self.spi.info());
1347 self.driver()
1348 .half_duplex_write(data_mode, cmd, address, dummy, buffer)
1349 }
1350
1351 fn use_blocking_transfer(&self, transfer_size: usize) -> bool {
1352 let threshold = self
1353 .spi
1354 .state()
1355 .min_async_transfer_size
1356 .load(Ordering::Relaxed);
1357 threshold > 0 && transfer_size < threshold
1358 }
1359
1360 fn driver(&self) -> Driver {
1361 Driver {
1362 info: self.spi.info(),
1363 state: self.spi.state(),
1364 }
1365 }
1366}
1367
1368#[instability::unstable]
1369impl<Dm> embassy_embedded_hal::SetConfig for Spi<'_, Dm>
1370where
1371 Dm: DriverMode,
1372{
1373 type Config = Config;
1374 type ConfigError = ConfigError;
1375
1376 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
1377 self.apply_config(config)
1378 }
1379}
1380
1381impl<Dm> embedded_hal::spi::ErrorType for Spi<'_, Dm>
1382where
1383 Dm: DriverMode,
1384{
1385 type Error = Error;
1386}
1387
1388impl<Dm> SpiBus for Spi<'_, Dm>
1389where
1390 Dm: DriverMode,
1391{
1392 fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
1393 self.read(words)
1394 }
1395
1396 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
1397 self.write(words)
1398 }
1399
1400 fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
1401 let _clock = SpiClockGuard::new(self.spi.info());
1402 self.driver().setup_full_duplex()?;
1403
1404 if read.is_empty() {
1405 self.driver().write(write)
1406 } else if write.is_empty() {
1407 self.driver().read(read)
1408 } else {
1409 self.driver().transfer(read, write)
1410 }
1411 }
1412
1413 fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
1414 let _clock = SpiClockGuard::new(self.spi.info());
1415 self.driver().setup_full_duplex()?;
1416 self.driver().transfer_in_place(words)
1417 }
1418
1419 fn flush(&mut self) -> Result<(), Self::Error> {
1420 Ok(())
1421 }
1422}
1423
1424impl SpiBusAsync for Spi<'_, Async> {
1425 async fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
1426 self.read_async(words).await
1427 }
1428
1429 async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
1430 self.write_async(words).await
1431 }
1432
1433 async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
1434 let _clock = SpiClockGuard::new(self.spi.info());
1435
1436 self.driver().setup_full_duplex()?;
1437
1438 if self.use_blocking_transfer(read.len().max(write.len())) {
1439 return if read.is_empty() {
1440 self.driver().write(write)
1441 } else if write.is_empty() {
1442 self.driver().read(read)
1443 } else {
1444 self.driver().transfer(read, write)
1445 };
1446 }
1447
1448 if read.is_empty() {
1449 self.driver().write_async(write).await
1450 } else if write.is_empty() {
1451 self.driver().read_async(read).await
1452 } else {
1453 self.driver().transfer_async(read, write).await
1454 }
1455 }
1456
1457 async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
1458 self.transfer_in_place_async(words).await
1459 }
1460
1461 async fn flush(&mut self) -> Result<(), Self::Error> {
1462 Ok(())
1463 }
1464}
1465
1466#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1468#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1469#[instability::unstable]
1470pub enum DataMode {
1471 SingleTwoDataLines,
1473 Single,
1475 Dual,
1477 Quad,
1479 #[cfg(spi_master_has_octal)]
1480 Octal,
1482}
1483
1484crate::any_peripheral! {
1485 pub peripheral AnySpi<'d> {
1487 #[cfg(spi_master_spi2)]
1488 Spi2(crate::peripherals::SPI2<'d>),
1489 #[cfg(spi_master_spi3)]
1490 Spi3(crate::peripherals::SPI3<'d>),
1491 }
1492}
1493
1494#[cfg(spi_master_supports_dma)]
1495with_spi_master_dma_engine! {
1496 ($engine:tt, $any_ch:ident) => {
1497 use crate::dma::DmaEligiblePeripheral;
1498
1499 impl<'d> DmaEligiblePeripheral<crate::dma::$any_ch<'d>> for AnySpi<'d> {
1500 fn dma_peripheral(&self) -> crate::dma::DmaPeripheral {
1501 any::delegate!(self, spi => { spi.dma_peripheral() })
1502 }
1503 }
1504 };
1505}
1506
1507impl QspiInstance for AnySpi<'_> {}
1508
1509impl Instance for AnySpi<'_> {
1510 #[inline]
1511 fn parts(&self) -> (&'static Info, &'static State) {
1512 any::delegate!(self, spi => { spi.parts() })
1513 }
1514}
1515
1516impl AnySpi<'_> {
1517 fn bind_peri_interrupt(&self, handler: InterruptHandler) {
1518 any::delegate!(self, spi => { spi.bind_peri_interrupt(handler) })
1519 }
1520
1521 fn disable_peri_interrupt_on_all_cores(&self) {
1522 any::delegate!(self, spi => { spi.disable_peri_interrupt_on_all_cores() })
1523 }
1524
1525 fn set_interrupt_handler(&self, handler: InterruptHandler) {
1526 self.disable_peri_interrupt_on_all_cores();
1527 self.bind_peri_interrupt(handler);
1528 }
1529}