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)]
415 pub(super) async fn read_async(&self, words: &mut [u8]) -> Result<(), Error> {
416 let empty_array = [EMPTY_WRITE_PAD; FIFO_SIZE];
417
418 for chunk in words.chunks_mut(FIFO_SIZE) {
419 self.write_one(&empty_array[0..chunk.len()])?;
420 self.flush_async().await;
421 self.read_from_fifo(chunk)?;
422 }
423 Ok(())
424 }
425
426 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
433 pub(super) fn read_from_fifo(&self, words: &mut [u8]) -> Result<(), Error> {
434 if words.len() > FIFO_SIZE {
435 return Err(Error::FifoSizeExeeded);
436 }
437
438 for (chunk, w_reg) in words.chunks_mut(4).zip(self.regs().w_iter()) {
439 let reg_val = w_reg.read().bits();
440 let bytes = reg_val.to_le_bytes();
441
442 let len = chunk.len();
443 chunk.copy_from_slice(&bytes[..len]);
444 }
445
446 Ok(())
447 }
448
449 pub(super) fn busy(&self) -> bool {
450 self.regs().cmd().read().usr().bit_is_set()
451 }
452
453 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
455 pub(super) fn flush_async(&self) -> impl Future<Output = ()> {
456 SpiFuture { driver: self }
457 }
458
459 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
461 pub(super) fn flush(&self) -> Result<(), Error> {
462 while self.busy() {
463 }
465 Ok(())
466 }
467
468 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
469 pub(super) fn transfer_in_place(&self, words: &mut [u8]) -> Result<(), Error> {
470 for chunk in words.chunks_mut(FIFO_SIZE) {
471 self.write_one(chunk)?;
472 self.flush()?;
473 self.read_from_fifo(chunk)?;
474 }
475
476 Ok(())
477 }
478
479 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
480 pub(super) fn transfer(&self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
481 let mut write_from = 0;
482 let mut read_from = 0;
483
484 loop {
485 let write_inc = core::cmp::min(FIFO_SIZE, write.len() - write_from);
487 let read_inc = core::cmp::min(FIFO_SIZE, read.len() - read_from);
489
490 if (write_inc == 0) && (read_inc == 0) {
491 break;
492 }
493
494 if write_inc < read_inc {
495 let mut empty = [EMPTY_WRITE_PAD; FIFO_SIZE];
497 empty[0..write_inc].copy_from_slice(&write[write_from..][..write_inc]);
498 self.write_one(&empty[..read_inc])?;
499 } else {
500 self.write_one(&write[write_from..][..write_inc])?;
501 }
502
503 self.flush()?;
504
505 if read_inc > 0 {
506 self.read_from_fifo(&mut read[read_from..][..read_inc])?;
507 }
508
509 write_from += write_inc;
510 read_from += read_inc;
511 }
512 Ok(())
513 }
514
515 fn prepare_half_duplex_chunk(&self, first: bool, last: bool) {
516 self.regs().user().modify(|_, w| {
517 if !first {
518 w.usr_command().clear_bit();
519 w.usr_addr().clear_bit();
520 w.usr_dummy().clear_bit();
521 w.cs_setup().clear_bit();
522 }
523 w.cs_hold().bit(!last)
524 });
525 version::set_cs_keep_active(self, !last);
526 }
527
528 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
534 pub(super) fn half_duplex_read(
535 &self,
536 data_mode: DataMode,
537 cmd: Command,
538 address: Address,
539 dummy: u8,
540 buffer: &mut [u8],
541 ) -> Result<(), Error> {
542 if buffer.is_empty() {
543 error!("Half-duplex mode does not support empty buffer");
544 return Err(Error::Unsupported);
545 }
546
547 self.setup_half_duplex(
548 false,
549 cmd,
550 address,
551 false,
552 dummy,
553 buffer.is_empty(),
554 data_mode,
555 )?;
556
557 let _keep_cs_guard = DropGuard::new((), |_| version::set_cs_keep_active(self, false));
558 let mut first = true;
559 let mut chunks = buffer.chunks_mut(FIFO_SIZE).peekable();
560 while let Some(chunk) = chunks.next() {
561 let last = chunks.peek().is_none();
562 self.prepare_half_duplex_chunk(first, last);
563 self.configure_datalen(chunk.len(), 0);
564 self.start_operation();
565 self.flush()?;
566 self.read_from_fifo(chunk)?;
567 first = false;
568 }
569 Ok(())
570 }
571
572 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
578 pub(super) fn half_duplex_write(
579 &self,
580 data_mode: DataMode,
581 cmd: Command,
582 address: Address,
583 dummy: u8,
584 buffer: &[u8],
585 ) -> Result<(), Error> {
586 cfg_select! {
587 all(spi_master_version = "1", spi_address_workaround) => {
588 let mut buffer = buffer;
589 let mut data_mode = data_mode;
590 let mut address = address;
591 let addr_bytes;
592 if buffer.is_empty() && !address.is_none() {
593 let bytes_to_write = address.width().div_ceil(8);
596 addr_bytes = address.value().to_be_bytes();
599 buffer = &addr_bytes[4 - bytes_to_write..][..bytes_to_write];
600 data_mode = address.mode();
601 address = Address::None;
602 }
603
604 if dummy > 0 {
605 error!("Dummy bits are not supported without data");
607 return Err(Error::Unsupported);
608 }
609 }
610 _ => {}
611 }
612
613 self.setup_half_duplex(
614 true,
615 cmd,
616 address,
617 false,
618 dummy,
619 buffer.is_empty(),
620 data_mode,
621 )?;
622
623 let _keep_cs_guard = DropGuard::new((), |_| version::set_cs_keep_active(self, false));
624 if buffer.is_empty() {
625 self.prepare_half_duplex_chunk(true, true);
626 self.start_operation();
627 self.flush()?;
628 } else {
629 let mut first = true;
630 let mut chunks = buffer.chunks(FIFO_SIZE).peekable();
631 while let Some(chunk) = chunks.next() {
632 let last = chunks.peek().is_none();
633 self.prepare_half_duplex_chunk(first, last);
634 self.configure_datalen(0, chunk.len());
635 self.fill_fifo(chunk);
636 self.start_operation();
637 self.flush()?;
638 first = false;
639 }
640 }
641 Ok(())
642 }
643
644 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
650 pub(super) async fn half_duplex_read_async(
651 &self,
652 data_mode: DataMode,
653 cmd: Command,
654 address: Address,
655 dummy: u8,
656 buffer: &mut [u8],
657 ) -> Result<(), Error> {
658 if buffer.is_empty() {
659 error!("Half-duplex mode does not support empty buffer");
660 return Err(Error::Unsupported);
661 }
662
663 self.setup_half_duplex(
664 false,
665 cmd,
666 address,
667 false,
668 dummy,
669 buffer.is_empty(),
670 data_mode,
671 )?;
672
673 let _keep_cs_guard = DropGuard::new((), |_| version::set_cs_keep_active(self, false));
674 let mut first = true;
675 let mut chunks = buffer.chunks_mut(FIFO_SIZE).peekable();
676 while let Some(chunk) = chunks.next() {
677 let last = chunks.peek().is_none();
678 self.prepare_half_duplex_chunk(first, last);
679 self.configure_datalen(chunk.len(), 0);
680 self.start_operation();
681
682 let cancel_on_drop = DropGuard::new((), |_| {
683 self.abort_transfer();
684 let _ = self.flush();
685 });
686 self.flush_async().await;
687 cancel_on_drop.defuse();
688
689 self.read_from_fifo(chunk)?;
690 first = false;
691 }
692 Ok(())
693 }
694
695 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
701 pub(super) async fn half_duplex_write_async(
702 &self,
703 data_mode: DataMode,
704 cmd: Command,
705 address: Address,
706 dummy: u8,
707 buffer: &[u8],
708 ) -> Result<(), Error> {
709 cfg_select! {
710 all(spi_master_version = "1", spi_address_workaround) => {
711 let mut buffer = buffer;
712 let mut data_mode = data_mode;
713 let mut address = address;
714 let addr_bytes;
715 if buffer.is_empty() && !address.is_none() {
716 let bytes_to_write = address.width().div_ceil(8);
719 addr_bytes = address.value().to_be_bytes();
722 buffer = &addr_bytes[4 - bytes_to_write..][..bytes_to_write];
723 data_mode = address.mode();
724 address = Address::None;
725 }
726
727 if dummy > 0 {
728 error!("Dummy bits are not supported without data");
730 return Err(Error::Unsupported);
731 }
732 }
733 _ => {}
734 }
735
736 self.setup_half_duplex(
737 true,
738 cmd,
739 address,
740 false,
741 dummy,
742 buffer.is_empty(),
743 data_mode,
744 )?;
745
746 let _keep_cs_guard = DropGuard::new((), |_| version::set_cs_keep_active(self, false));
747 if buffer.is_empty() {
748 self.prepare_half_duplex_chunk(true, true);
749 self.start_operation();
750
751 let cancel_on_drop = DropGuard::new((), |_| {
752 self.abort_transfer();
753 let _ = self.flush();
754 });
755 self.flush_async().await;
756 cancel_on_drop.defuse();
757 } else {
758 let mut first = true;
759 let mut chunks = buffer.chunks(FIFO_SIZE).peekable();
760 while let Some(chunk) = chunks.next() {
761 let last = chunks.peek().is_none();
762 self.prepare_half_duplex_chunk(first, last);
763 self.configure_datalen(0, chunk.len());
764 self.fill_fifo(chunk);
765 self.start_operation();
766
767 let cancel_on_drop = DropGuard::new((), |_| {
768 self.abort_transfer();
769 let _ = self.flush();
770 });
771 self.flush_async().await;
772 cancel_on_drop.defuse();
773
774 first = false;
775 }
776 }
777 Ok(())
778 }
779
780 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
781 pub(super) async fn transfer_in_place_async(&self, words: &mut [u8]) -> Result<(), Error> {
782 for chunk in words.chunks_mut(FIFO_SIZE) {
783 let cancel_on_drop = DropGuard::new((), |_| {
786 self.abort_transfer();
787 let _ = self.flush();
788 });
789 let res = self.write_one(chunk);
790 self.flush_async().await;
791 cancel_on_drop.defuse();
792 res?;
793
794 self.read_from_fifo(chunk)?;
795 }
796
797 Ok(())
798 }
799
800 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
801 pub(super) async fn transfer_async(&self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
802 let mut write_from = 0;
803 let mut read_from = 0;
804
805 loop {
806 let write_inc = core::cmp::min(FIFO_SIZE, write.len() - write_from);
808 let read_inc = core::cmp::min(FIFO_SIZE, read.len() - read_from);
810
811 if (write_inc == 0) && (read_inc == 0) {
812 break;
813 }
814
815 self.flush_async().await;
816
817 if write_inc < read_inc {
818 let mut empty = [EMPTY_WRITE_PAD; FIFO_SIZE];
820 empty[0..write_inc].copy_from_slice(&write[write_from..][..write_inc]);
821 self.write_one(&empty[..read_inc])?;
822 } else {
823 self.write_one(&write[write_from..][..write_inc])?;
824 }
825
826 self.flush_async().await;
827
828 if read_inc > 0 {
829 self.read_from_fifo(&mut read[read_from..][..read_inc])?;
830 }
831
832 write_from += write_inc;
833 read_from += read_inc;
834 }
835 Ok(())
836 }
837
838 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
839 pub(super) fn start_operation(&self) {
840 self.update();
841 self.clear_interrupts(SpiInterrupt::TransferDone.into());
842 self.regs().cmd().modify(|_, w| w.usr().set_bit());
843 }
844
845 pub(super) fn setup_full_duplex(&self) -> Result<(), Error> {
846 self.regs().user().modify(|_, w| {
847 w.usr_miso().set_bit();
848 w.usr_mosi().set_bit();
849 w.doutdin().set_bit();
850 w.usr_dummy().clear_bit();
851 w.sio().clear_bit()
852 });
853
854 self.init_spi_data_mode(
855 DataMode::SingleTwoDataLines,
856 DataMode::SingleTwoDataLines,
857 DataMode::SingleTwoDataLines,
858 )?;
859
860 version::setup_full_duplex(self);
861
862 Ok(())
863 }
864
865 #[expect(clippy::too_many_arguments)]
866 pub(super) fn setup_half_duplex(
867 &self,
868 is_write: bool,
869 cmd: Command,
870 address: Address,
871 dummy_idle: bool,
872 dummy: u8,
873 no_mosi_miso: bool,
874 data_mode: DataMode,
875 ) -> Result<(), Error> {
876 self.init_spi_data_mode(cmd.mode(), address.mode(), data_mode)?;
877
878 let dummy = version::prepare_half_duplex(self, is_write, dummy);
879
880 let reg_block = self.regs();
881 reg_block.user().modify(|_, w| {
882 w.usr_miso_highpart().clear_bit();
883 w.usr_mosi_highpart().clear_bit();
884 w.sio().bit(data_mode == DataMode::Single);
886 w.doutdin().clear_bit();
887 w.usr_miso().bit(!is_write && !no_mosi_miso);
888 w.usr_mosi().bit(is_write && !no_mosi_miso);
889 w.cs_hold().set_bit();
890 w.usr_dummy_idle().bit(dummy_idle);
891 w.usr_dummy().bit(dummy != 0);
892 w.usr_addr().bit(!address.is_none());
893 w.usr_command().bit(!cmd.is_none())
894 });
895
896 version::setup_half_duplex(self);
897
898 reg_block.slave().write(|w| unsafe { w.bits(0) });
899
900 self.update();
901
902 self.set_up_common_phases(cmd, address, dummy);
904
905 Ok(())
906 }
907
908 pub(super) fn set_up_common_phases(&self, cmd: Command, address: Address, dummy: u8) {
909 let reg_block = self.regs();
910 if !cmd.is_none() {
911 reg_block.user2().modify(|_, w| unsafe {
912 w.usr_command_bitlen().bits((cmd.width() - 1) as u8);
913 w.usr_command_value().bits(cmd.value())
914 });
915 }
916
917 if !address.is_none() {
918 reg_block
919 .user1()
920 .modify(|_, w| unsafe { w.usr_addr_bitlen().bits((address.width() - 1) as u8) });
921
922 version::write_address(self, address.value() << (32 - address.width()));
923 }
924
925 if dummy > 0 {
926 reg_block
927 .user1()
928 .modify(|_, w| unsafe { w.usr_dummy_cyclelen().bits(dummy - 1) });
929 }
930 }
931
932 pub(super) fn update(&self) {
933 cfg_select! {
934 spi_master_version = "3" => {
935 let reg_block = self.regs();
936
937 reg_block.cmd().modify(|_, w| w.update().set_bit());
938
939 while reg_block.cmd().read().update().bit_is_set() {
940 }
942 }
943 _ => {
944 }
946 }
947 }
948
949 pub(super) fn configure_datalen(&self, rx_len_bytes: usize, tx_len_bytes: usize) {
950 let rx_len = rx_len_bytes as u32 * 8;
951 let tx_len = tx_len_bytes as u32 * 8;
952
953 version::configure_datalen(self, rx_len.saturating_sub(1), tx_len.saturating_sub(1));
954 }
955}
956
957impl PartialEq for Info {
958 fn eq(&self, other: &Self) -> bool {
959 core::ptr::eq(self.register_block, other.register_block)
960 }
961}
962
963unsafe impl Sync for Info {}
964
965for_each_spi_master! {
966 ($peri:ident, $sys:ident, $sclk:ident [$($cs:ident),+] [$($sio:ident),*] $(, $is_qspi:tt)?) => {
967 impl Instance for crate::peripherals::$peri<'_> {
968 #[inline(always)]
969 fn parts(&self) -> (&'static Info, &'static State) {
970 #[handler]
971 #[ram]
972 fn irq_handler() {
973 handle_async(&INFO, &STATE)
974 }
975
976 static INFO: Info = Info {
977 register_block: crate::peripherals::$peri::ptr(),
978 peripheral: crate::system::Peripheral::$sys,
979 async_handler: irq_handler,
980 sclk: OutputSignal::$sclk,
981 cs: &[$(OutputSignal::$cs),+],
982 sio_inputs: &[$(InputSignal::$sio),*],
983 sio_outputs: &[$(OutputSignal::$sio),*],
984 clock_instance: crate::soc::clocks::SpiInstance::$sys,
985 };
986
987 static STATE: State = State {
988 waker: AtomicWaker::new(),
989 pins: UnsafeCell::new(MaybeUninit::uninit()),
990 min_async_transfer_size: AtomicUsize::new(0),
991
992 #[cfg(spi_master_version = "1")]
993 esp32_hack: Esp32Hack {
994 timing_miso_delay: Cell::new(None),
995 extra_dummy: Cell::new(0),
996 },
997 };
998
999 (&INFO, &STATE)
1000 }
1001 }
1002
1003 $(
1004 $crate::ignore!($is_qspi);
1006 impl QspiInstance for crate::peripherals::$peri<'_> {}
1007 )?
1008 };
1009}
1010
1011#[doc(hidden)]
1012pub struct State {
1013 pub(super) waker: AtomicWaker,
1014 pins: UnsafeCell<MaybeUninit<SpiPinGuard>>,
1015 pub(super) min_async_transfer_size: AtomicUsize,
1016
1017 #[cfg(spi_master_version = "1")]
1018 esp32_hack: Esp32Hack,
1019}
1020
1021impl State {
1022 #[allow(
1030 clippy::mut_from_ref,
1031 reason = "Safety requirements ensure this is okay"
1032 )]
1033 pub(super) unsafe fn pins(&self) -> &mut SpiPinGuard {
1034 unsafe { (&mut *self.pins.get()).assume_init_mut() }
1035 }
1036
1037 unsafe fn deinit(&self) {
1038 unsafe {
1039 let mut old = self.pins.get().replace(MaybeUninit::uninit());
1040 old.assume_init_drop();
1041 }
1042 }
1043}
1044
1045#[cfg(spi_master_version = "1")]
1046pub(super) struct Esp32Hack {
1047 timing_miso_delay: Cell<Option<u8>>,
1048 extra_dummy: Cell<u8>,
1049}
1050
1051unsafe impl Sync for State {}
1052
1053#[ram]
1054pub(super) fn handle_async(info: &'static Info, state: &'static State) {
1055 let driver = Driver { info, state };
1056 if driver.interrupts().contains(SpiInterrupt::TransferDone) {
1057 driver.enable_listen(SpiInterrupt::TransferDone.into(), false);
1058 state.waker.wake();
1059 }
1060}
1061
1062#[must_use = "futures do nothing unless you `.await` or poll them"]
1063struct SpiFuture<'a> {
1064 driver: &'a Driver,
1065}
1066
1067impl SpiFuture<'_> {
1068 const EVENTS: EnumSet<SpiInterrupt> = enum_set!(SpiInterrupt::TransferDone);
1069}
1070
1071impl Future for SpiFuture<'_> {
1072 type Output = ();
1073
1074 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
1075 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1076 if !self.driver.busy() {
1077 self.driver.clear_interrupts(Self::EVENTS);
1078 return Poll::Ready(());
1079 }
1080
1081 self.driver.state.waker.register(cx.waker());
1082 self.driver.enable_listen(Self::EVENTS, true);
1083
1084 if self.driver.busy() {
1089 Poll::Pending
1090 } else {
1091 self.driver.clear_interrupts(Self::EVENTS);
1092 Poll::Ready(())
1093 }
1094 }
1095}
1096
1097impl Drop for SpiFuture<'_> {
1098 fn drop(&mut self) {
1099 self.driver.enable_listen(Self::EVENTS, false);
1100 }
1101}