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