1#[cfg(spi_master_version = "1")]
2use core::cell::Cell;
3use core::{
4 cell::UnsafeCell,
5 future::Future,
6 mem::MaybeUninit,
7 pin::Pin,
8 sync::atomic::{AtomicUsize, Ordering},
9 task::{Context, Poll},
10};
11
12use enumset::{EnumSet, enum_set};
13
14use super::{
15 Address,
16 AnySpi,
17 Command,
18 Config,
19 ConfigError,
20 DataMode,
21 EMPTY_WRITE_PAD,
22 FIFO_SIZE,
23 SpiInterrupt,
24 SpiPinGuard,
25 any,
26};
27use crate::{
28 asynch::AtomicWaker,
29 clock::ll::SpiInstance,
30 gpio::{InputSignal, OutputSignal},
31 handler,
32 interrupt::InterruptHandler,
33 pac::spi2::RegisterBlock,
34 private::{self, DropGuard},
35 ram,
36 spi::{BitOrder, Error, Mode},
37 system::PeripheralGuard,
38};
39
40#[cfg_attr(spi_master_version = "1", path = "v1.rs")]
41#[cfg_attr(spi_master_version = "2", path = "v2.rs")]
42#[cfg_attr(spi_master_version = "3", path = "v3.rs")]
43mod version;
44
45#[derive(Debug)]
46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47pub(super) struct SpiWrapper<'d> {
48 pub(super) spi: AnySpi<'d>,
49 _guard: PeripheralGuard,
50}
51
52impl<'d> SpiWrapper<'d> {
53 pub(super) fn new(spi: impl Instance + 'd) -> Self {
54 let p = spi.info().peripheral;
55 let this = Self {
56 spi: spi.degrade(),
57 _guard: PeripheralGuard::new(p),
58 };
59
60 unsafe {
62 this.state()
63 .pins
64 .get()
65 .write(MaybeUninit::new(SpiPinGuard::new_unconnected()))
66 }
67
68 this
69 }
70
71 pub(super) fn info(&self) -> &'static Info {
72 self.spi.info()
73 }
74
75 pub(super) fn state(&self) -> &'static State {
76 self.spi.state()
77 }
78
79 pub(super) fn disable_peri_interrupt_on_all_cores(&self) {
80 self.spi.disable_peri_interrupt_on_all_cores();
81 }
82
83 pub(super) fn set_interrupt_handler(&self, handler: InterruptHandler) {
84 self.spi.set_interrupt_handler(handler);
85 }
86
87 pub(super) fn pins(&mut self) -> &mut SpiPinGuard {
88 unsafe {
89 self.state().pins()
91 }
92 }
93}
94
95impl Drop for SpiWrapper<'_> {
96 fn drop(&mut self) {
97 unsafe {
98 self.spi.state().deinit();
100 }
101 }
102}
103
104pub(super) struct SpiClockGuard {
105 clock: SpiInstance,
106}
107
108impl SpiClockGuard {
109 pub(super) fn new(spi: &Info) -> Self {
110 let clock = spi.clock_instance;
111 crate::clock::ll::ClockTree::with(|clocks| clock.request_function_clock(clocks));
112 Self { clock }
113 }
114}
115
116impl Drop for SpiClockGuard {
117 fn drop(&mut self) {
118 crate::clock::ll::ClockTree::with(|clocks| self.clock.release_function_clock(clocks));
119 }
120}
121
122pub trait Instance: private::Sealed + any::Degrade {
124 #[doc(hidden)]
125 fn parts(&self) -> (&'static Info, &'static State);
127
128 #[doc(hidden)]
130 #[inline(always)]
131 fn info(&self) -> &'static Info {
132 self.parts().0
133 }
134
135 #[doc(hidden)]
137 #[inline(always)]
138 fn state(&self) -> &'static State {
139 self.parts().1
140 }
141}
142
143#[doc(hidden)]
145pub trait QspiInstance: Instance {}
146
147#[doc(hidden)]
149#[non_exhaustive]
150#[allow(private_interfaces, reason = "Unstable details")]
151pub struct Info {
152 pub register_block: *const RegisterBlock,
156
157 pub peripheral: crate::system::Peripheral,
159
160 pub async_handler: InterruptHandler,
162
163 pub sclk: OutputSignal,
165
166 pub cs: &'static [OutputSignal],
168
169 pub sio_inputs: &'static [InputSignal],
170 pub sio_outputs: &'static [OutputSignal],
171
172 pub clock_instance: crate::soc::clocks::SpiInstance,
174}
175
176impl Info {
177 pub(super) fn cs(&self, n: usize) -> OutputSignal {
178 *unwrap!(self.cs.get(n), "CS{} is not defined", n)
179 }
180
181 pub(super) fn opt_sio_input(&self, n: usize) -> Option<InputSignal> {
182 self.sio_inputs.get(n).copied()
183 }
184
185 pub(super) fn opt_sio_output(&self, n: usize) -> Option<OutputSignal> {
186 self.sio_outputs.get(n).copied()
187 }
188
189 pub(super) fn sio_input(&self, n: usize) -> InputSignal {
190 unwrap!(self.opt_sio_input(n), "SIO{} is not defined", n)
191 }
192
193 pub(super) fn sio_output(&self, n: usize) -> OutputSignal {
194 unwrap!(self.opt_sio_output(n), "SIO{} is not defined", n)
195 }
196}
197
198pub(super) struct Driver {
199 pub(super) info: &'static Info,
200 pub(super) state: &'static State,
201}
202
203impl Driver {
205 pub(super) fn regs(&self) -> &RegisterBlock {
207 unsafe { &*self.info.register_block }
208 }
209
210 pub(super) fn abort_transfer(&self) {
211 version::abort_transfer(self);
212 self.update();
213 }
214
215 pub(super) fn init(&self) {
217 version::enable_peripheral_clock(self);
218
219 crate::soc::clocks::ClockTree::with(|clocks| {
220 #[cfg(soc_clock_node_spi_function_clock_is_configurable)]
221 self.info.clock_instance.configure_function_clock(
222 clocks,
223 crate::soc::clocks::SpiFunctionClockConfig::default(),
224 );
225 self.info.clock_instance.request_function_clock(clocks);
226
227 self.regs().user().modify(|_, w| {
228 w.usr_miso_highpart().clear_bit();
229 w.usr_mosi_highpart().clear_bit();
230 w.doutdin().set_bit();
231 w.usr_miso().set_bit();
232 w.usr_mosi().set_bit();
233 w.cs_hold().set_bit();
234 w.usr_dummy_idle().set_bit();
235 w.usr_addr().clear_bit();
236 w.usr_command().clear_bit()
237 });
238
239 version::init(self);
240 self.info.clock_instance.release_function_clock(clocks);
241 });
242
243 self.regs().slave().write(|w| unsafe { w.bits(0) });
244 }
245
246 fn init_spi_data_mode(
247 &self,
248 cmd_mode: DataMode,
249 address_mode: DataMode,
250 data_mode: DataMode,
251 ) -> Result<(), Error> {
252 version::init_spi_data_mode(self, cmd_mode, address_mode, data_mode)
253 }
254
255 #[cfg_attr(not(feature = "unstable"), allow(dead_code))]
257 pub(super) fn enable_listen(&self, interrupts: EnumSet<SpiInterrupt>, enable: bool) {
258 version::enable_listen(self, interrupts, enable);
259 }
260
261 #[cfg_attr(not(feature = "unstable"), allow(dead_code))]
263 pub(super) fn interrupts(&self) -> EnumSet<SpiInterrupt> {
264 version::interrupts(self)
265 }
266
267 pub(super) fn clear_interrupts(&self, interrupts: EnumSet<SpiInterrupt>) {
269 version::clear_interrupts(self, interrupts);
270 }
271
272 pub(super) fn apply_config(&self, config: &Config) -> Result<(), ConfigError> {
273 config.validate()?;
274
275 let raw = config.raw_clock_reg_value()?;
276 crate::soc::clocks::ClockTree::with(|clocks| {
277 #[cfg(soc_clock_node_spi_function_clock_is_configurable)]
278 self.info
279 .clock_instance
280 .configure_function_clock(clocks, config.clock_source);
281 self.info.clock_instance.request_function_clock(clocks);
282
283 self.regs().clock().write(|w| unsafe { w.bits(raw) });
284
285 self.set_bit_order(config.read_bit_order, config.write_bit_order);
286 self.set_data_mode(config.mode);
287
288 version::apply_config(self);
289 self.info.clock_instance.release_function_clock(clocks);
290 });
291
292 self.state
293 .min_async_transfer_size
294 .store(config.min_async_transfer_size, Ordering::Relaxed);
295
296 Ok(())
297 }
298
299 fn set_data_mode(&self, data_mode: Mode) {
300 version::set_data_mode(self, data_mode);
301 }
302
303 #[cfg(not(spi_master_bit_order_is_bool))]
304 fn set_bit_order(&self, read_order: BitOrder, write_order: BitOrder) {
305 let read_value = match read_order {
306 BitOrder::MsbFirst => 0,
307 BitOrder::LsbFirst => 1,
308 };
309 let write_value = match write_order {
310 BitOrder::MsbFirst => 0,
311 BitOrder::LsbFirst => 1,
312 };
313 self.regs().ctrl().modify(|_, w| unsafe {
314 w.rd_bit_order().bits(read_value);
315 w.wr_bit_order().bits(write_value);
316 w
317 });
318 }
319
320 #[cfg(spi_master_bit_order_is_bool)]
321 fn set_bit_order(&self, read_order: BitOrder, write_order: BitOrder) {
322 let read_value = match read_order {
323 BitOrder::MsbFirst => false,
324 BitOrder::LsbFirst => true,
325 };
326 let write_value = match write_order {
327 BitOrder::MsbFirst => false,
328 BitOrder::LsbFirst => true,
329 };
330 self.regs().ctrl().modify(|_, w| {
331 w.rd_bit_order().bit(read_value);
332 w.wr_bit_order().bit(write_value);
333 w
334 });
335 }
336
337 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
338 pub(super) fn fill_fifo(&self, chunk: &[u8]) {
339 let (chunks, rem) = chunk.as_chunks::<4>();
340 let mut w_iter = self.regs().w_iter();
341 for c in chunks {
342 if let Some(w_reg) = w_iter.next() {
343 let word = u32::from_le_bytes(*c);
344 w_reg.write(|w| w.buf().set(word));
345 }
346 }
347 if !rem.is_empty()
348 && let Some(w_reg) = w_iter.next()
349 {
350 let word = match rem.len() {
351 3 => (rem[0] as u32) | ((rem[1] as u32) << 8) | ((rem[2] as u32) << 16),
352 2 => (rem[0] as u32) | ((rem[1] as u32) << 8),
353 1 => rem[0] as u32,
354 _ => unreachable!(),
355 };
356 w_reg.write(|w| w.buf().set(word));
357 }
358 }
359
360 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
362 pub(super) fn write_one(&self, words: &[u8]) -> Result<(), Error> {
363 if words.len() > FIFO_SIZE {
364 return Err(Error::FifoSizeExeeded);
365 }
366 self.configure_datalen(0, words.len());
367 self.fill_fifo(words);
368 self.start_operation();
369 Ok(())
370 }
371
372 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
374 pub(super) fn write(&self, words: &[u8]) -> Result<(), Error> {
375 for chunk in words.chunks(FIFO_SIZE) {
376 self.write_one(chunk)?;
377 self.flush()?;
378 }
379 Ok(())
380 }
381
382 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
384 pub(super) async fn write_async(&self, words: &[u8]) -> Result<(), Error> {
385 for chunk in words.chunks(FIFO_SIZE) {
386 self.write_one(chunk)?;
387 self.flush_async().await;
388 }
389 Ok(())
390 }
391
392 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
398 pub(super) fn read(&self, words: &mut [u8]) -> Result<(), Error> {
399 let empty_array = [EMPTY_WRITE_PAD; FIFO_SIZE];
400
401 for chunk in words.chunks_mut(FIFO_SIZE) {
402 self.write_one(&empty_array[0..chunk.len()])?;
403 self.flush()?;
404 self.read_from_fifo(chunk)?;
405 }
406 Ok(())
407 }
408
409 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
414 pub(super) async fn read_async(&self, words: &mut [u8]) -> Result<(), Error> {
415 let empty_array = [EMPTY_WRITE_PAD; FIFO_SIZE];
416
417 for chunk in words.chunks_mut(FIFO_SIZE) {
418 self.write_one(&empty_array[0..chunk.len()])?;
419 self.flush_async().await;
420 self.read_from_fifo(chunk)?;
421 }
422 Ok(())
423 }
424
425 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
431 pub(super) fn read_from_fifo(&self, words: &mut [u8]) -> Result<(), Error> {
432 if words.len() > FIFO_SIZE {
433 return Err(Error::FifoSizeExeeded);
434 }
435
436 for (chunk, w_reg) in words.chunks_mut(4).zip(self.regs().w_iter()) {
437 let reg_val = w_reg.read().bits();
438 let bytes = reg_val.to_le_bytes();
439
440 let len = chunk.len();
441 chunk.copy_from_slice(&bytes[..len]);
442 }
443
444 Ok(())
445 }
446
447 pub(super) fn busy(&self) -> bool {
448 self.regs().cmd().read().usr().bit_is_set()
449 }
450
451 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
453 pub(super) fn flush_async(&self) -> impl Future<Output = ()> {
454 SpiFuture { driver: self }
455 }
456
457 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
459 pub(super) fn flush(&self) -> Result<(), Error> {
460 while self.busy() {
461 }
463 Ok(())
464 }
465
466 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
467 pub(super) fn transfer_in_place(&self, words: &mut [u8]) -> Result<(), Error> {
468 for chunk in words.chunks_mut(FIFO_SIZE) {
469 self.write_one(chunk)?;
470 self.flush()?;
471 self.read_from_fifo(chunk)?;
472 }
473
474 Ok(())
475 }
476
477 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
478 pub(super) fn transfer(&self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
479 let mut write_from = 0;
480 let mut read_from = 0;
481
482 loop {
483 let write_inc = core::cmp::min(FIFO_SIZE, write.len() - write_from);
485 let read_inc = core::cmp::min(FIFO_SIZE, read.len() - read_from);
487
488 if (write_inc == 0) && (read_inc == 0) {
489 break;
490 }
491
492 if write_inc < read_inc {
493 let mut empty = [EMPTY_WRITE_PAD; FIFO_SIZE];
495 empty[0..write_inc].copy_from_slice(&write[write_from..][..write_inc]);
496 self.write_one(&empty[..read_inc])?;
497 } else {
498 self.write_one(&write[write_from..][..write_inc])?;
499 }
500
501 self.flush()?;
502
503 if read_inc > 0 {
504 self.read_from_fifo(&mut read[read_from..][..read_inc])?;
505 }
506
507 write_from += write_inc;
508 read_from += read_inc;
509 }
510 Ok(())
511 }
512
513 fn prepare_half_duplex_chunk(&self, first: bool, last: bool) {
514 self.regs().user().modify(|_, w| {
515 if !first {
516 w.usr_command().clear_bit();
517 w.usr_addr().clear_bit();
518 w.usr_dummy().clear_bit();
519 w.cs_setup().clear_bit();
520 }
521 w.cs_hold().bit(!last)
522 });
523 version::set_cs_keep_active(self, !last);
524 }
525
526 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
532 pub(super) fn half_duplex_read(
533 &self,
534 data_mode: DataMode,
535 cmd: Command,
536 address: Address,
537 dummy: u8,
538 buffer: &mut [u8],
539 ) -> Result<(), Error> {
540 if buffer.is_empty() {
541 error!("Half-duplex mode does not support empty buffer");
542 return Err(Error::Unsupported);
543 }
544
545 self.setup_half_duplex(
546 false,
547 cmd,
548 address,
549 false,
550 dummy,
551 buffer.is_empty(),
552 data_mode,
553 )?;
554
555 let _keep_cs_guard = DropGuard::new((), |_| version::set_cs_keep_active(self, false));
556 let mut first = true;
557 let mut chunks = buffer.chunks_mut(FIFO_SIZE).peekable();
558 while let Some(chunk) = chunks.next() {
559 let last = chunks.peek().is_none();
560 self.prepare_half_duplex_chunk(first, last);
561 self.configure_datalen(chunk.len(), 0);
562 self.start_operation();
563 self.flush()?;
564 self.read_from_fifo(chunk)?;
565 first = false;
566 }
567 Ok(())
568 }
569
570 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
576 pub(super) fn half_duplex_write(
577 &self,
578 data_mode: DataMode,
579 cmd: Command,
580 address: Address,
581 dummy: u8,
582 buffer: &[u8],
583 ) -> Result<(), Error> {
584 cfg_select! {
585 all(spi_master_version = "1", spi_address_workaround) => {
586 let mut buffer = buffer;
587 let mut data_mode = data_mode;
588 let mut address = address;
589 let addr_bytes;
590 if buffer.is_empty() && !address.is_none() {
591 let bytes_to_write = address.width().div_ceil(8);
594 addr_bytes = address.value().to_be_bytes();
597 buffer = &addr_bytes[4 - bytes_to_write..][..bytes_to_write];
598 data_mode = address.mode();
599 address = Address::None;
600 }
601
602 if dummy > 0 {
603 error!("Dummy bits are not supported without data");
605 return Err(Error::Unsupported);
606 }
607 }
608 _ => {}
609 }
610
611 self.setup_half_duplex(
612 true,
613 cmd,
614 address,
615 false,
616 dummy,
617 buffer.is_empty(),
618 data_mode,
619 )?;
620
621 let _keep_cs_guard = DropGuard::new((), |_| version::set_cs_keep_active(self, false));
622 if buffer.is_empty() {
623 self.prepare_half_duplex_chunk(true, true);
624 self.start_operation();
625 self.flush()?;
626 } else {
627 let mut first = true;
628 let mut chunks = buffer.chunks(FIFO_SIZE).peekable();
629 while let Some(chunk) = chunks.next() {
630 let last = chunks.peek().is_none();
631 self.prepare_half_duplex_chunk(first, last);
632 self.configure_datalen(0, chunk.len());
633 self.fill_fifo(chunk);
634 self.start_operation();
635 self.flush()?;
636 first = false;
637 }
638 }
639 Ok(())
640 }
641
642 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
648 pub(super) async fn half_duplex_read_async(
649 &self,
650 data_mode: DataMode,
651 cmd: Command,
652 address: Address,
653 dummy: u8,
654 buffer: &mut [u8],
655 ) -> Result<(), Error> {
656 if buffer.is_empty() {
657 error!("Half-duplex mode does not support empty buffer");
658 return Err(Error::Unsupported);
659 }
660
661 self.setup_half_duplex(
662 false,
663 cmd,
664 address,
665 false,
666 dummy,
667 buffer.is_empty(),
668 data_mode,
669 )?;
670
671 let _keep_cs_guard = DropGuard::new((), |_| version::set_cs_keep_active(self, false));
672 let mut first = true;
673 let mut chunks = buffer.chunks_mut(FIFO_SIZE).peekable();
674 while let Some(chunk) = chunks.next() {
675 let last = chunks.peek().is_none();
676 self.prepare_half_duplex_chunk(first, last);
677 self.configure_datalen(chunk.len(), 0);
678 self.start_operation();
679
680 let cancel_on_drop = DropGuard::new((), |_| {
681 self.abort_transfer();
682 let _ = self.flush();
683 });
684 self.flush_async().await;
685 cancel_on_drop.defuse();
686
687 self.read_from_fifo(chunk)?;
688 first = false;
689 }
690 Ok(())
691 }
692
693 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
699 pub(super) async fn half_duplex_write_async(
700 &self,
701 data_mode: DataMode,
702 cmd: Command,
703 address: Address,
704 dummy: u8,
705 buffer: &[u8],
706 ) -> Result<(), Error> {
707 cfg_select! {
708 all(spi_master_version = "1", spi_address_workaround) => {
709 let mut buffer = buffer;
710 let mut data_mode = data_mode;
711 let mut address = address;
712 let addr_bytes;
713 if buffer.is_empty() && !address.is_none() {
714 let bytes_to_write = address.width().div_ceil(8);
717 addr_bytes = address.value().to_be_bytes();
720 buffer = &addr_bytes[4 - bytes_to_write..][..bytes_to_write];
721 data_mode = address.mode();
722 address = Address::None;
723 }
724
725 if dummy > 0 {
726 error!("Dummy bits are not supported without data");
728 return Err(Error::Unsupported);
729 }
730 }
731 _ => {}
732 }
733
734 self.setup_half_duplex(
735 true,
736 cmd,
737 address,
738 false,
739 dummy,
740 buffer.is_empty(),
741 data_mode,
742 )?;
743
744 let _keep_cs_guard = DropGuard::new((), |_| version::set_cs_keep_active(self, false));
745 if buffer.is_empty() {
746 self.prepare_half_duplex_chunk(true, true);
747 self.start_operation();
748
749 let cancel_on_drop = DropGuard::new((), |_| {
750 self.abort_transfer();
751 let _ = self.flush();
752 });
753 self.flush_async().await;
754 cancel_on_drop.defuse();
755 } else {
756 let mut first = true;
757 let mut chunks = buffer.chunks(FIFO_SIZE).peekable();
758 while let Some(chunk) = chunks.next() {
759 let last = chunks.peek().is_none();
760 self.prepare_half_duplex_chunk(first, last);
761 self.configure_datalen(0, chunk.len());
762 self.fill_fifo(chunk);
763 self.start_operation();
764
765 let cancel_on_drop = DropGuard::new((), |_| {
766 self.abort_transfer();
767 let _ = self.flush();
768 });
769 self.flush_async().await;
770 cancel_on_drop.defuse();
771
772 first = false;
773 }
774 }
775 Ok(())
776 }
777
778 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
779 pub(super) async fn transfer_in_place_async(&self, words: &mut [u8]) -> Result<(), Error> {
780 for chunk in words.chunks_mut(FIFO_SIZE) {
781 let cancel_on_drop = DropGuard::new((), |_| {
784 self.abort_transfer();
785 let _ = self.flush();
786 });
787 let res = self.write_one(chunk);
788 self.flush_async().await;
789 cancel_on_drop.defuse();
790 res?;
791
792 self.read_from_fifo(chunk)?;
793 }
794
795 Ok(())
796 }
797
798 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
799 pub(super) async fn transfer_async(&self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
800 let mut write_from = 0;
801 let mut read_from = 0;
802
803 loop {
804 let write_inc = core::cmp::min(FIFO_SIZE, write.len() - write_from);
806 let read_inc = core::cmp::min(FIFO_SIZE, read.len() - read_from);
808
809 if (write_inc == 0) && (read_inc == 0) {
810 break;
811 }
812
813 self.flush_async().await;
814
815 if write_inc < read_inc {
816 let mut empty = [EMPTY_WRITE_PAD; FIFO_SIZE];
818 empty[0..write_inc].copy_from_slice(&write[write_from..][..write_inc]);
819 self.write_one(&empty[..read_inc])?;
820 } else {
821 self.write_one(&write[write_from..][..write_inc])?;
822 }
823
824 self.flush_async().await;
825
826 if read_inc > 0 {
827 self.read_from_fifo(&mut read[read_from..][..read_inc])?;
828 }
829
830 write_from += write_inc;
831 read_from += read_inc;
832 }
833 Ok(())
834 }
835
836 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
837 pub(super) fn start_operation(&self) {
838 self.update();
839 self.clear_interrupts(SpiInterrupt::TransferDone.into());
840 self.regs().cmd().modify(|_, w| w.usr().set_bit());
841 }
842
843 pub(super) fn setup_full_duplex(&self) -> Result<(), Error> {
844 self.regs().user().modify(|_, w| {
845 w.usr_miso().set_bit();
846 w.usr_mosi().set_bit();
847 w.doutdin().set_bit();
848 w.usr_dummy().clear_bit();
849 w.sio().clear_bit()
850 });
851
852 self.init_spi_data_mode(
853 DataMode::SingleTwoDataLines,
854 DataMode::SingleTwoDataLines,
855 DataMode::SingleTwoDataLines,
856 )?;
857
858 version::setup_full_duplex(self);
859
860 Ok(())
861 }
862
863 #[expect(clippy::too_many_arguments)]
864 pub(super) fn setup_half_duplex(
865 &self,
866 is_write: bool,
867 cmd: Command,
868 address: Address,
869 dummy_idle: bool,
870 dummy: u8,
871 no_mosi_miso: bool,
872 data_mode: DataMode,
873 ) -> Result<(), Error> {
874 self.init_spi_data_mode(cmd.mode(), address.mode(), data_mode)?;
875
876 let dummy = version::prepare_half_duplex(self, is_write, dummy);
877
878 let reg_block = self.regs();
879 reg_block.user().modify(|_, w| {
880 w.usr_miso_highpart().clear_bit();
881 w.usr_mosi_highpart().clear_bit();
882 w.sio().bit(data_mode == DataMode::Single);
884 w.doutdin().clear_bit();
885 w.usr_miso().bit(!is_write && !no_mosi_miso);
886 w.usr_mosi().bit(is_write && !no_mosi_miso);
887 w.cs_hold().set_bit();
888 w.usr_dummy_idle().bit(dummy_idle);
889 w.usr_dummy().bit(dummy != 0);
890 w.usr_addr().bit(!address.is_none());
891 w.usr_command().bit(!cmd.is_none())
892 });
893
894 version::setup_half_duplex(self);
895
896 reg_block.slave().write(|w| unsafe { w.bits(0) });
897
898 self.update();
899
900 self.set_up_common_phases(cmd, address, dummy);
902
903 Ok(())
904 }
905
906 pub(super) fn set_up_common_phases(&self, cmd: Command, address: Address, dummy: u8) {
907 let reg_block = self.regs();
908 if !cmd.is_none() {
909 reg_block.user2().modify(|_, w| unsafe {
910 w.usr_command_bitlen().bits((cmd.width() - 1) as u8);
911 w.usr_command_value().bits(cmd.value())
912 });
913 }
914
915 if !address.is_none() {
916 reg_block
917 .user1()
918 .modify(|_, w| unsafe { w.usr_addr_bitlen().bits((address.width() - 1) as u8) });
919
920 version::write_address(self, address.value() << (32 - address.width()));
921 }
922
923 if dummy > 0 {
924 reg_block
925 .user1()
926 .modify(|_, w| unsafe { w.usr_dummy_cyclelen().bits(dummy - 1) });
927 }
928 }
929
930 pub(super) fn update(&self) {
931 cfg_select! {
932 spi_master_version = "3" => {
933 let reg_block = self.regs();
934
935 reg_block.cmd().modify(|_, w| w.update().set_bit());
936
937 while reg_block.cmd().read().update().bit_is_set() {
938 }
940 }
941 _ => {
942 }
944 }
945 }
946
947 pub(super) fn configure_datalen(&self, rx_len_bytes: usize, tx_len_bytes: usize) {
948 let rx_len = rx_len_bytes as u32 * 8;
949 let tx_len = tx_len_bytes as u32 * 8;
950
951 version::configure_datalen(self, rx_len.saturating_sub(1), tx_len.saturating_sub(1));
952 }
953}
954
955impl PartialEq for Info {
956 fn eq(&self, other: &Self) -> bool {
957 core::ptr::eq(self.register_block, other.register_block)
958 }
959}
960
961unsafe impl Sync for Info {}
962
963for_each_spi_master! {
964 ($peri:ident, $sys:ident, $sclk:ident [$($cs:ident),+] [$($sio:ident),*] $(, $is_qspi:tt)?) => {
965 impl Instance for crate::peripherals::$peri<'_> {
966 #[inline(always)]
967 fn parts(&self) -> (&'static Info, &'static State) {
968 #[handler]
969 #[ram]
970 fn irq_handler() {
971 handle_async(&INFO, &STATE)
972 }
973
974 static INFO: Info = Info {
975 register_block: crate::peripherals::$peri::ptr(),
976 peripheral: crate::system::Peripheral::$sys,
977 async_handler: irq_handler,
978 sclk: OutputSignal::$sclk,
979 cs: &[$(OutputSignal::$cs),+],
980 sio_inputs: &[$(InputSignal::$sio),*],
981 sio_outputs: &[$(OutputSignal::$sio),*],
982 clock_instance: crate::soc::clocks::SpiInstance::$sys,
983 };
984
985 static STATE: State = State {
986 waker: AtomicWaker::new(),
987 pins: UnsafeCell::new(MaybeUninit::uninit()),
988 min_async_transfer_size: AtomicUsize::new(0),
989
990 #[cfg(spi_master_version = "1")]
991 esp32_hack: Esp32Hack {
992 timing_miso_delay: Cell::new(None),
993 extra_dummy: Cell::new(0),
994 },
995 };
996
997 (&INFO, &STATE)
998 }
999 }
1000
1001 $(
1002 $crate::ignore!($is_qspi);
1004 impl QspiInstance for crate::peripherals::$peri<'_> {}
1005 )?
1006 };
1007}
1008
1009#[doc(hidden)]
1010pub struct State {
1011 pub(super) waker: AtomicWaker,
1012 pins: UnsafeCell<MaybeUninit<SpiPinGuard>>,
1013 pub(super) min_async_transfer_size: AtomicUsize,
1014
1015 #[cfg(spi_master_version = "1")]
1016 esp32_hack: Esp32Hack,
1017}
1018
1019impl State {
1020 #[allow(
1028 clippy::mut_from_ref,
1029 reason = "Safety requirements ensure this is okay"
1030 )]
1031 pub(super) unsafe fn pins(&self) -> &mut SpiPinGuard {
1032 unsafe { (&mut *self.pins.get()).assume_init_mut() }
1033 }
1034
1035 unsafe fn deinit(&self) {
1036 unsafe {
1037 let mut old = self.pins.get().replace(MaybeUninit::uninit());
1038 old.assume_init_drop();
1039 }
1040 }
1041}
1042
1043#[cfg(spi_master_version = "1")]
1044pub(super) struct Esp32Hack {
1045 timing_miso_delay: Cell<Option<u8>>,
1046 extra_dummy: Cell<u8>,
1047}
1048
1049unsafe impl Sync for State {}
1050
1051#[ram]
1052pub(super) fn handle_async(info: &'static Info, state: &'static State) {
1053 let driver = Driver { info, state };
1054 if driver.interrupts().contains(SpiInterrupt::TransferDone) {
1055 driver.enable_listen(SpiInterrupt::TransferDone.into(), false);
1056 state.waker.wake();
1057 }
1058}
1059
1060#[must_use = "futures do nothing unless you `.await` or poll them"]
1061struct SpiFuture<'a> {
1062 driver: &'a Driver,
1063}
1064
1065impl SpiFuture<'_> {
1066 const EVENTS: EnumSet<SpiInterrupt> = enum_set!(SpiInterrupt::TransferDone);
1067}
1068
1069impl Future for SpiFuture<'_> {
1070 type Output = ();
1071
1072 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
1073 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1074 if !self.driver.busy() {
1075 self.driver.clear_interrupts(Self::EVENTS);
1076 return Poll::Ready(());
1077 }
1078
1079 self.driver.state.waker.register(cx.waker());
1080 self.driver.enable_listen(Self::EVENTS, true);
1081
1082 if self.driver.busy() {
1087 Poll::Pending
1088 } else {
1089 self.driver.clear_interrupts(Self::EVENTS);
1090 Poll::Ready(())
1091 }
1092 }
1093}
1094
1095impl Drop for SpiFuture<'_> {
1096 fn drop(&mut self) {
1097 self.driver.enable_listen(Self::EVENTS, false);
1098 }
1099}