1use core::{
2 cell::{Cell, UnsafeCell},
3 cmp::min,
4 mem::{ManuallyDrop, MaybeUninit},
5 sync::atomic::{Ordering, fence},
6};
7
8#[cfg(feature = "unstable")]
9use embedded_hal::spi::{ErrorType, SpiBus};
10#[cfg(place_spi_master_driver_in_ram)]
11use procmacros::ram;
12
13use super::*;
14use crate::{
15 dma::{
16 Channel,
17 DmaChannelFor,
18 DmaDescriptor,
19 DmaEligible,
20 DmaRxBuf,
21 DmaRxBuffer,
22 DmaTxBuf,
23 DmaTxBuffer,
24 PeripheralDmaChannel,
25 asynch::DmaRxFuture,
26 },
27 private::DropGuard,
28 spi::DmaError,
29};
30
31const MAX_DMA_SIZE: usize = 32736;
32
33impl<'d> Spi<'d, Blocking> {
34 #[doc_replace(
35 "dma_channel" => {
36 cfg(any(esp32, esp32s2)) => "DMA_SPI2",
37 _ => "DMA_CH0",
38 }
39 )]
40 #[instability::unstable]
71 pub fn with_dma(self, channel: impl DmaChannelFor<AnySpi<'d>>) -> SpiDma<'d, Blocking> {
72 SpiDma::new(self, channel.degrade())
73 }
74}
75
76#[doc_replace(
77 "dma_channel" => {
78 cfg(any(esp32, esp32s2)) => "DMA_SPI2",
79 _ => "DMA_CH0",
80 }
81)]
82#[cfg_attr(feature = "defmt", derive(defmt::Format))]
116pub struct SpiDma<'d, Dm>
117where
118 Dm: DriverMode,
119{
120 spi: SpiWrapper<'d>,
121 pub(crate) channel: Channel<Dm, PeripheralDmaChannel<AnySpi<'d>>>,
122}
123
124impl<Dm> crate::private::Sealed for SpiDma<'_, Dm> where Dm: DriverMode {}
125
126impl<'d> SpiDma<'d, Blocking> {
127 #[instability::unstable]
129 pub fn into_async(self) -> SpiDma<'d, Async> {
130 self.spi
131 .set_interrupt_handler(self.spi.info().async_handler);
132 SpiDma {
133 spi: self.spi,
134 channel: self.channel.into_async(),
135 }
136 }
137
138 pub(super) fn new(
139 spi_driver: Spi<'d, Blocking>,
140 channel: PeripheralDmaChannel<AnySpi<'d>>,
141 ) -> Self {
142 let spi = spi_driver.spi;
143
144 let channel = Channel::new(channel);
145 channel.runtime_ensure_compatible(&spi.spi);
146
147 for_each_spi_master!((all $($inst:tt),*) => {
148 const SPI_NUM: usize = 0 $(+ { stringify!($inst); 1 })*;
149 };);
150 let id = if spi.info() == unsafe { crate::peripherals::SPI2::steal().info() } {
151 0
152 } else {
153 1
154 };
155
156 let state = spi.spi.dma_state();
157
158 state.tx_transfer_in_progress.set(false);
159 state.rx_transfer_in_progress.set(false);
160
161 static mut TX_DESCRIPTORS: [[DmaDescriptor; 1]; SPI_NUM] =
162 [[DmaDescriptor::EMPTY]; SPI_NUM];
163 static mut RX_DESCRIPTORS: [[DmaDescriptor; 1]; SPI_NUM] =
164 [[DmaDescriptor::EMPTY]; SPI_NUM];
165
166 let empty_rx_buffer = unwrap!(DmaRxBuf::new(unsafe { &mut RX_DESCRIPTORS[id] }, &mut []));
167
168 cfg_if::cfg_if! {
169 if #[cfg(all(esp32, spi_address_workaround))] {
170 static mut BUFFERS: [[u32; 1]; SPI_NUM] = [[0]; SPI_NUM];
171 let buffer = crate::dma::as_mut_byte_array!(BUFFERS[id], 4);
172 let empty_tx_buffer = unwrap!(DmaTxBuf::new(unsafe { &mut TX_DESCRIPTORS[id] }, buffer));
173 } else {
174 let empty_tx_buffer = unwrap!(DmaTxBuf::new(unsafe { &mut TX_DESCRIPTORS[id] }, &mut []));
175 }
176 }
177
178 unsafe { (&mut *state.empty_tx_buffer.get()).write(empty_tx_buffer) };
180 unsafe { (&mut *state.empty_rx_buffer.get()).write(empty_rx_buffer) };
181
182 Self { spi, channel }
183 }
184
185 #[instability::unstable]
187 pub fn listen(&mut self, interrupts: impl Into<EnumSet<SpiInterrupt>>) {
188 self.driver().enable_listen(interrupts.into(), true);
189 }
190
191 #[instability::unstable]
193 pub fn unlisten(&mut self, interrupts: impl Into<EnumSet<SpiInterrupt>>) {
194 self.driver().enable_listen(interrupts.into(), false);
195 }
196
197 #[instability::unstable]
199 pub fn interrupts(&mut self) -> EnumSet<SpiInterrupt> {
200 self.driver().interrupts()
201 }
202
203 #[instability::unstable]
205 pub fn clear_interrupts(&mut self, interrupts: impl Into<EnumSet<SpiInterrupt>>) {
206 self.driver().clear_interrupts(interrupts.into());
207 }
208
209 #[cfg_attr(
210 not(multi_core),
211 doc = "Registers an interrupt handler for the peripheral."
212 )]
213 #[cfg_attr(
214 multi_core,
215 doc = "Registers an interrupt handler for the peripheral on the current core."
216 )]
217 #[doc = ""]
218 #[instability::unstable]
229 pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
230 self.spi.set_interrupt_handler(handler);
231 }
232}
233
234impl<'d> SpiDma<'d, Async> {
235 #[instability::unstable]
237 pub fn into_blocking(self) -> SpiDma<'d, Blocking> {
238 self.spi.disable_peri_interrupt_on_all_cores();
239 SpiDma {
240 spi: self.spi,
241 channel: self.channel.into_blocking(),
242 }
243 }
244
245 async fn wait_for_idle_async(&mut self) {
246 if self.dma_driver().state.rx_transfer_in_progress.get() {
247 _ = DmaRxFuture::new(&mut self.channel.rx).await;
248 self.dma_driver().state.rx_transfer_in_progress.set(false);
249 }
250
251 struct Fut(Driver);
252 impl Fut {
253 const DONE_EVENTS: EnumSet<SpiInterrupt> =
254 enumset::enum_set!(SpiInterrupt::TransferDone);
255 }
256 impl Future for Fut {
257 type Output = ();
258
259 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
260 if !self.0.interrupts().is_disjoint(Self::DONE_EVENTS) {
261 #[cfg(any(esp32, esp32s2))]
262 if self.0.busy() {
264 cx.waker().wake_by_ref();
265 return Poll::Pending;
266 }
267
268 self.0.clear_interrupts(Self::DONE_EVENTS);
269 return Poll::Ready(());
270 }
271
272 self.0.state.waker.register(cx.waker());
273 self.0.enable_listen(Self::DONE_EVENTS, true);
274 Poll::Pending
275 }
276 }
277 impl Drop for Fut {
278 fn drop(&mut self) {
279 self.0.enable_listen(Self::DONE_EVENTS, false);
280 }
281 }
282
283 if !self.is_done() {
284 Fut(self.driver()).await;
285 }
286
287 if self.dma_driver().state.tx_transfer_in_progress.get() {
288 if !self.channel.tx.is_done() {
290 self.channel.tx.stop_transfer();
291 }
292 self.dma_driver().state.tx_transfer_in_progress.set(false);
293 }
294 }
295}
296
297impl<Dm> core::fmt::Debug for SpiDma<'_, Dm>
298where
299 Dm: DriverMode + core::fmt::Debug,
300{
301 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
306 f.debug_struct("SpiDma").field("spi", &self.spi).finish()
307 }
308}
309
310#[instability::unstable]
311impl crate::interrupt::InterruptConfigurable for SpiDma<'_, Blocking> {
312 fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
316 self.set_interrupt_handler(handler);
317 }
318}
319
320impl<Dm> SpiDma<'_, Dm>
321where
322 Dm: DriverMode,
323{
324 fn spi(&self) -> &SpiWrapper<'_> {
325 &self.spi
326 }
327
328 fn driver(&self) -> Driver {
329 Driver {
330 info: self.spi.info(),
331 state: self.spi.state(),
332 }
333 }
334
335 fn dma_driver(&self) -> DmaDriver {
336 DmaDriver {
337 driver: self.driver(),
338 dma_peripheral: self.spi().dma_peripheral(),
339 state: self.spi().dma_state(),
340 }
341 }
342
343 fn is_done(&self) -> bool {
344 if self.driver().busy() {
345 return false;
346 }
347 if self.dma_driver().state.rx_transfer_in_progress.get() {
348 if !self.channel.rx.is_done() && !self.channel.rx.has_dscr_empty_error() {
356 return false;
357 }
358 }
359 true
360 }
361
362 fn wait_for_idle(&mut self) {
363 while !self.is_done() {
364 }
366 self.dma_driver().state.rx_transfer_in_progress.set(false);
367 self.dma_driver().state.tx_transfer_in_progress.set(false);
368 fence(Ordering::Acquire);
369 }
370
371 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
376 unsafe fn start_transfer_dma<RX: DmaRxBuffer, TX: DmaTxBuffer>(
377 &mut self,
378 full_duplex: bool,
379 bytes_to_read: usize,
380 bytes_to_write: usize,
381 rx_buffer: &mut RX,
382 tx_buffer: &mut TX,
383 ) -> Result<(), Error> {
384 if bytes_to_read > MAX_DMA_SIZE || bytes_to_write > MAX_DMA_SIZE {
385 return Err(Error::MaxDmaTransferSizeExceeded);
386 }
387
388 self.dma_driver()
389 .state
390 .rx_transfer_in_progress
391 .set(bytes_to_read > 0);
392 self.dma_driver()
393 .state
394 .tx_transfer_in_progress
395 .set(bytes_to_write > 0);
396 unsafe {
397 self.dma_driver().start_transfer_dma(
398 full_duplex,
399 bytes_to_read,
400 bytes_to_write,
401 rx_buffer,
402 tx_buffer,
403 &mut self.channel,
404 )
405 }
406 }
407
408 #[cfg(all(esp32, spi_address_workaround))]
413 unsafe fn set_up_address_workaround(
414 &mut self,
415 cmd: Command,
416 address: Address,
417 dummy: u8,
418 ) -> Result<(), Error> {
419 if dummy > 0 {
420 error!("Dummy bits are not supported when there is no data to write");
422 return Err(Error::Unsupported);
423 }
424
425 let buffer = unsafe { self.spi.dma_state().empty_tx_buffer() };
426
427 let bytes_to_write = address.width().div_ceil(8);
428 let addr_bytes = address.value().to_be_bytes();
431 let addr_bytes = &addr_bytes[4 - bytes_to_write..][..bytes_to_write];
432 buffer.fill(addr_bytes);
433
434 self.driver().setup_half_duplex(
435 true,
436 cmd,
437 Address::None,
438 false,
439 dummy,
440 bytes_to_write == 0,
441 address.mode(),
442 )?;
443
444 let empty_rx_buffer = unsafe { self.dma_driver().empty_rx_buffer() };
445
446 unsafe { self.start_transfer_dma(false, 0, bytes_to_write, empty_rx_buffer, buffer) }
447 }
448
449 fn cancel_transfer(&mut self) {
450 let state = self.dma_driver().state;
451 if state.tx_transfer_in_progress.get() || state.rx_transfer_in_progress.get() {
452 self.dma_driver().abort_transfer();
453
454 if state.tx_transfer_in_progress.get() {
456 self.channel.tx.stop_transfer();
457 state.tx_transfer_in_progress.set(false);
458 }
459 if state.rx_transfer_in_progress.get() {
460 self.channel.rx.stop_transfer();
461 state.rx_transfer_in_progress.set(false);
462 }
463 }
464 }
465}
466
467#[instability::unstable]
468impl<Dm> embassy_embedded_hal::SetConfig for SpiDma<'_, Dm>
469where
470 Dm: DriverMode,
471{
472 type Config = Config;
473 type ConfigError = ConfigError;
474
475 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
476 self.apply_config(config)
477 }
478}
479
480#[instability::unstable]
485pub struct SpiDmaTransfer<'d, Dm, Buf>
486where
487 Dm: DriverMode,
488{
489 spi_dma: ManuallyDrop<SpiDma<'d, Dm>>,
490 dma_buf: ManuallyDrop<Buf>,
491}
492
493impl<Buf> SpiDmaTransfer<'_, Async, Buf> {
494 #[instability::unstable]
498 pub async fn wait_for_done(&mut self) {
499 self.spi_dma.wait_for_idle_async().await;
500 }
501}
502
503impl<'d, Dm, Buf> SpiDmaTransfer<'d, Dm, Buf>
504where
505 Dm: DriverMode,
506{
507 fn new(spi_dma: SpiDma<'d, Dm>, dma_buf: Buf) -> Self {
508 Self {
509 spi_dma: ManuallyDrop::new(spi_dma),
510 dma_buf: ManuallyDrop::new(dma_buf),
511 }
512 }
513
514 pub fn is_done(&self) -> bool {
519 self.spi_dma.is_done()
520 }
521
522 #[instability::unstable]
527 pub fn wait(mut self) -> (SpiDma<'d, Dm>, Buf) {
528 self.spi_dma.wait_for_idle();
529 let retval = unsafe {
530 (
531 ManuallyDrop::take(&mut self.spi_dma),
532 ManuallyDrop::take(&mut self.dma_buf),
533 )
534 };
535 core::mem::forget(self);
536 retval
537 }
538
539 #[instability::unstable]
541 pub fn cancel(&mut self) {
542 if !self.spi_dma.is_done() {
543 self.spi_dma.cancel_transfer();
544 }
545 }
546}
547
548impl<Dm, Buf> Drop for SpiDmaTransfer<'_, Dm, Buf>
549where
550 Dm: DriverMode,
551{
552 fn drop(&mut self) {
553 if !self.is_done() {
554 self.spi_dma.cancel_transfer();
555 self.spi_dma.wait_for_idle();
556 }
557
558 unsafe {
559 ManuallyDrop::drop(&mut self.spi_dma);
560 ManuallyDrop::drop(&mut self.dma_buf);
561 }
562 }
563}
564
565impl<'d, Dm> SpiDma<'d, Dm>
566where
567 Dm: DriverMode,
568{
569 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
574 unsafe fn start_dma_write(
575 &mut self,
576 bytes_to_write: usize,
577 buffer: &mut impl DmaTxBuffer,
578 ) -> Result<(), Error> {
579 let empty_rx_buffer = unsafe { self.dma_driver().empty_rx_buffer() };
580
581 unsafe { self.start_dma_transfer(0, bytes_to_write, empty_rx_buffer, buffer) }
582 }
583
584 #[instability::unstable]
590 pub fn with_buffers(self, dma_rx_buf: DmaRxBuf, dma_tx_buf: DmaTxBuf) -> SpiDmaBus<'d, Dm> {
591 SpiDmaBus::new(self, dma_rx_buf, dma_tx_buf)
592 }
593
594 #[allow(clippy::type_complexity)]
600 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
601 #[instability::unstable]
602 pub fn write<TX: DmaTxBuffer>(
603 mut self,
604 bytes_to_write: usize,
605 mut buffer: TX,
606 ) -> Result<SpiDmaTransfer<'d, Dm, TX>, (Error, Self, TX)> {
607 self.wait_for_idle();
608 if let Err(e) = self.driver().setup_full_duplex() {
609 return Err((e, self, buffer));
610 };
611 match unsafe { self.start_dma_write(bytes_to_write, &mut buffer) } {
612 Ok(_) => Ok(SpiDmaTransfer::new(self, buffer)),
613 Err(e) => Err((e, self, buffer)),
614 }
615 }
616
617 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
622 unsafe fn start_dma_read(
623 &mut self,
624 bytes_to_read: usize,
625 buffer: &mut impl DmaRxBuffer,
626 ) -> Result<(), Error> {
627 let empty_tx_buffer = unsafe { self.dma_driver().empty_tx_buffer() };
628
629 unsafe { self.start_dma_transfer(bytes_to_read, 0, buffer, empty_tx_buffer) }
630 }
631
632 #[allow(clippy::type_complexity)]
638 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
639 #[instability::unstable]
640 pub fn read<RX: DmaRxBuffer>(
641 mut self,
642 bytes_to_read: usize,
643 mut buffer: RX,
644 ) -> Result<SpiDmaTransfer<'d, Dm, RX>, (Error, Self, RX)> {
645 self.wait_for_idle();
646 if let Err(e) = self.driver().setup_full_duplex() {
647 return Err((e, self, buffer));
648 };
649 match unsafe { self.start_dma_read(bytes_to_read, &mut buffer) } {
650 Ok(_) => Ok(SpiDmaTransfer::new(self, buffer)),
651 Err(e) => Err((e, self, buffer)),
652 }
653 }
654
655 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
660 unsafe fn start_dma_transfer(
661 &mut self,
662 bytes_to_read: usize,
663 bytes_to_write: usize,
664 rx_buffer: &mut impl DmaRxBuffer,
665 tx_buffer: &mut impl DmaTxBuffer,
666 ) -> Result<(), Error> {
667 unsafe {
668 self.start_transfer_dma(true, bytes_to_read, bytes_to_write, rx_buffer, tx_buffer)
669 }
670 }
671
672 #[allow(clippy::type_complexity)]
678 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
679 #[instability::unstable]
680 pub fn transfer<RX: DmaRxBuffer, TX: DmaTxBuffer>(
681 mut self,
682 bytes_to_read: usize,
683 mut rx_buffer: RX,
684 bytes_to_write: usize,
685 mut tx_buffer: TX,
686 ) -> Result<SpiDmaTransfer<'d, Dm, (RX, TX)>, (Error, Self, RX, TX)> {
687 self.wait_for_idle();
688 if let Err(e) = self.driver().setup_full_duplex() {
689 return Err((e, self, rx_buffer, tx_buffer));
690 };
691 match unsafe {
692 self.start_dma_transfer(
693 bytes_to_read,
694 bytes_to_write,
695 &mut rx_buffer,
696 &mut tx_buffer,
697 )
698 } {
699 Ok(_) => Ok(SpiDmaTransfer::new(self, (rx_buffer, tx_buffer))),
700 Err(e) => Err((e, self, rx_buffer, tx_buffer)),
701 }
702 }
703
704 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
709 unsafe fn start_half_duplex_read(
710 &mut self,
711 data_mode: DataMode,
712 cmd: Command,
713 address: Address,
714 dummy: u8,
715 bytes_to_read: usize,
716 buffer: &mut impl DmaRxBuffer,
717 ) -> Result<(), Error> {
718 self.driver().setup_half_duplex(
719 false,
720 cmd,
721 address,
722 false,
723 dummy,
724 bytes_to_read == 0,
725 data_mode,
726 )?;
727
728 let empty_tx_buffer = unsafe { self.dma_driver().empty_tx_buffer() };
729
730 unsafe { self.start_transfer_dma(false, bytes_to_read, 0, buffer, empty_tx_buffer) }
731 }
732
733 #[allow(clippy::type_complexity)]
735 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
736 #[instability::unstable]
737 pub fn half_duplex_read<RX: DmaRxBuffer>(
738 mut self,
739 data_mode: DataMode,
740 cmd: Command,
741 address: Address,
742 dummy: u8,
743 bytes_to_read: usize,
744 mut buffer: RX,
745 ) -> Result<SpiDmaTransfer<'d, Dm, RX>, (Error, Self, RX)> {
746 self.wait_for_idle();
747
748 match unsafe {
749 self.start_half_duplex_read(data_mode, cmd, address, dummy, bytes_to_read, &mut buffer)
750 } {
751 Ok(_) => Ok(SpiDmaTransfer::new(self, buffer)),
752 Err(e) => Err((e, self, buffer)),
753 }
754 }
755
756 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
761 unsafe fn start_half_duplex_write(
762 &mut self,
763 data_mode: DataMode,
764 cmd: Command,
765 address: Address,
766 dummy: u8,
767 bytes_to_write: usize,
768 buffer: &mut impl DmaTxBuffer,
769 ) -> Result<(), Error> {
770 #[cfg(all(esp32, spi_address_workaround))]
771 {
772 if bytes_to_write == 0 && address.mode() != DataMode::SingleTwoDataLines {
775 return unsafe { self.set_up_address_workaround(cmd, address, dummy) };
776 }
777 }
778
779 self.driver().setup_half_duplex(
780 true,
781 cmd,
782 address,
783 false,
784 dummy,
785 bytes_to_write == 0,
786 data_mode,
787 )?;
788
789 let empty_rx_buffer = unsafe { self.dma_driver().empty_rx_buffer() };
790
791 unsafe { self.start_transfer_dma(false, 0, bytes_to_write, empty_rx_buffer, buffer) }
792 }
793
794 #[allow(clippy::type_complexity)]
796 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
797 #[instability::unstable]
798 pub fn half_duplex_write<TX: DmaTxBuffer>(
799 mut self,
800 data_mode: DataMode,
801 cmd: Command,
802 address: Address,
803 dummy: u8,
804 bytes_to_write: usize,
805 mut buffer: TX,
806 ) -> Result<SpiDmaTransfer<'d, Dm, TX>, (Error, Self, TX)> {
807 self.wait_for_idle();
808
809 match unsafe {
810 self.start_half_duplex_write(
811 data_mode,
812 cmd,
813 address,
814 dummy,
815 bytes_to_write,
816 &mut buffer,
817 )
818 } {
819 Ok(_) => Ok(SpiDmaTransfer::new(self, buffer)),
820 Err(e) => Err((e, self, buffer)),
821 }
822 }
823
824 #[cfg_attr(not(esp32h2), doc = " 80MHz")]
830 #[cfg_attr(esp32h2, doc = " 48MHz")]
831 #[instability::unstable]
834 pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> {
835 self.driver().apply_config(config)
836 }
837}
838
839#[derive(Debug)]
844#[cfg_attr(feature = "defmt", derive(defmt::Format))]
845#[instability::unstable]
846pub struct SpiDmaBus<'d, Dm>
847where
848 Dm: DriverMode,
849{
850 spi_dma: SpiDma<'d, Dm>,
851 rx_buf: DmaRxBuf,
852 tx_buf: DmaTxBuf,
853}
854
855impl<Dm> crate::private::Sealed for SpiDmaBus<'_, Dm> where Dm: DriverMode {}
856
857impl<'d> SpiDmaBus<'d, Blocking> {
858 #[instability::unstable]
860 pub fn into_async(self) -> SpiDmaBus<'d, Async> {
861 SpiDmaBus {
862 spi_dma: self.spi_dma.into_async(),
863 rx_buf: self.rx_buf,
864 tx_buf: self.tx_buf,
865 }
866 }
867
868 #[instability::unstable]
870 pub fn listen(&mut self, interrupts: impl Into<EnumSet<SpiInterrupt>>) {
871 self.spi_dma.listen(interrupts.into());
872 }
873
874 #[instability::unstable]
876 pub fn unlisten(&mut self, interrupts: impl Into<EnumSet<SpiInterrupt>>) {
877 self.spi_dma.unlisten(interrupts.into());
878 }
879
880 #[instability::unstable]
882 pub fn interrupts(&mut self) -> EnumSet<SpiInterrupt> {
883 self.spi_dma.interrupts()
884 }
885
886 #[instability::unstable]
888 pub fn clear_interrupts(&mut self, interrupts: impl Into<EnumSet<SpiInterrupt>>) {
889 self.spi_dma.clear_interrupts(interrupts.into());
890 }
891}
892
893impl<'d> SpiDmaBus<'d, Async> {
894 #[instability::unstable]
896 pub fn into_blocking(self) -> SpiDmaBus<'d, Blocking> {
897 SpiDmaBus {
898 spi_dma: self.spi_dma.into_blocking(),
899 rx_buf: self.rx_buf,
900 tx_buf: self.tx_buf,
901 }
902 }
903
904 #[instability::unstable]
906 pub async fn read_async(&mut self, words: &mut [u8]) -> Result<(), Error> {
907 self.spi_dma.wait_for_idle_async().await;
908 self.spi_dma.driver().setup_full_duplex()?;
909 let chunk_size = self.rx_buf.capacity();
910
911 let empty_tx_buffer = unsafe { self.spi_dma.dma_driver().empty_tx_buffer() };
912
913 for chunk in words.chunks_mut(chunk_size) {
914 let mut spi = DropGuard::new(&mut self.spi_dma, |spi| spi.cancel_transfer());
915
916 unsafe { spi.start_dma_transfer(chunk.len(), 0, &mut self.rx_buf, empty_tx_buffer)? };
917
918 spi.wait_for_idle_async().await;
919
920 chunk.copy_from_slice(&self.rx_buf.as_slice()[..chunk.len()]);
921
922 spi.defuse();
923 }
924
925 Ok(())
926 }
927
928 #[instability::unstable]
930 pub async fn write_async(&mut self, words: &[u8]) -> Result<(), Error> {
931 self.spi_dma.wait_for_idle_async().await;
932 self.spi_dma.driver().setup_full_duplex()?;
933
934 let empty_rx_buffer = unsafe { self.spi_dma.dma_driver().empty_rx_buffer() };
935
936 let mut spi = DropGuard::new(&mut self.spi_dma, |spi| spi.cancel_transfer());
937 let chunk_size = self.tx_buf.capacity();
938
939 for chunk in words.chunks(chunk_size) {
940 self.tx_buf.as_mut_slice()[..chunk.len()].copy_from_slice(chunk);
941
942 unsafe { spi.start_dma_transfer(0, chunk.len(), empty_rx_buffer, &mut self.tx_buf)? };
943
944 spi.wait_for_idle_async().await;
945 }
946 spi.defuse();
947
948 Ok(())
949 }
950
951 #[instability::unstable]
954 pub async fn transfer_async(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
955 self.spi_dma.wait_for_idle_async().await;
956 self.spi_dma.driver().setup_full_duplex()?;
957
958 let mut spi = DropGuard::new(&mut self.spi_dma, |spi| spi.cancel_transfer());
959 let chunk_size = min(self.tx_buf.capacity(), self.rx_buf.capacity());
960
961 let common_length = min(read.len(), write.len());
962 let (read_common, read_remainder) = read.split_at_mut(common_length);
963 let (write_common, write_remainder) = write.split_at(common_length);
964
965 for (read_chunk, write_chunk) in read_common
966 .chunks_mut(chunk_size)
967 .zip(write_common.chunks(chunk_size))
968 {
969 self.tx_buf.as_mut_slice()[..write_chunk.len()].copy_from_slice(write_chunk);
970
971 unsafe {
972 spi.start_dma_transfer(
973 read_chunk.len(),
974 write_chunk.len(),
975 &mut self.rx_buf,
976 &mut self.tx_buf,
977 )?;
978 }
979 spi.wait_for_idle_async().await;
980
981 read_chunk.copy_from_slice(&self.rx_buf.as_slice()[..read_chunk.len()]);
982 }
983
984 spi.defuse();
985
986 if !read_remainder.is_empty() {
987 self.read_async(read_remainder).await
988 } else if !write_remainder.is_empty() {
989 self.write_async(write_remainder).await
990 } else {
991 Ok(())
992 }
993 }
994
995 #[instability::unstable]
998 pub async fn transfer_in_place_async(&mut self, words: &mut [u8]) -> Result<(), Error> {
999 self.spi_dma.wait_for_idle_async().await;
1000 self.spi_dma.driver().setup_full_duplex()?;
1001
1002 let mut spi = DropGuard::new(&mut self.spi_dma, |spi| spi.cancel_transfer());
1003 for chunk in words.chunks_mut(self.tx_buf.capacity()) {
1004 self.tx_buf.as_mut_slice()[..chunk.len()].copy_from_slice(chunk);
1005
1006 unsafe {
1007 spi.start_dma_transfer(
1008 chunk.len(),
1009 chunk.len(),
1010 &mut self.rx_buf,
1011 &mut self.tx_buf,
1012 )?;
1013 }
1014 spi.wait_for_idle_async().await;
1015 chunk.copy_from_slice(&self.rx_buf.as_slice()[..chunk.len()]);
1016 }
1017
1018 spi.defuse();
1019
1020 Ok(())
1021 }
1022}
1023
1024impl<'d, Dm> SpiDmaBus<'d, Dm>
1025where
1026 Dm: DriverMode,
1027{
1028 pub fn new(spi_dma: SpiDma<'d, Dm>, rx_buf: DmaRxBuf, tx_buf: DmaTxBuf) -> Self {
1031 Self {
1032 spi_dma,
1033 rx_buf,
1034 tx_buf,
1035 }
1036 }
1037
1038 #[instability::unstable]
1040 pub fn split(mut self) -> (SpiDma<'d, Dm>, DmaRxBuf, DmaTxBuf) {
1041 self.wait_for_idle();
1042 (self.spi_dma, self.rx_buf, self.tx_buf)
1043 }
1044
1045 fn wait_for_idle(&mut self) {
1046 self.spi_dma.wait_for_idle();
1047 }
1048
1049 #[cfg_attr(not(esp32h2), doc = " 80MHz")]
1055 #[cfg_attr(esp32h2, doc = " 48MHz")]
1056 #[instability::unstable]
1059 pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> {
1060 self.spi_dma.apply_config(config)
1061 }
1062
1063 #[instability::unstable]
1065 pub fn read(&mut self, words: &mut [u8]) -> Result<(), Error> {
1066 self.wait_for_idle();
1067 self.spi_dma.driver().setup_full_duplex()?;
1068
1069 let empty_tx_buffer = unsafe { self.spi_dma.dma_driver().empty_tx_buffer() };
1070
1071 for chunk in words.chunks_mut(self.rx_buf.capacity()) {
1072 unsafe {
1073 self.spi_dma.start_dma_transfer(
1074 chunk.len(),
1075 0,
1076 &mut self.rx_buf,
1077 empty_tx_buffer,
1078 )?;
1079 }
1080
1081 self.wait_for_idle();
1082 chunk.copy_from_slice(&self.rx_buf.as_slice()[..chunk.len()]);
1083 }
1084
1085 Ok(())
1086 }
1087
1088 #[instability::unstable]
1090 pub fn write(&mut self, words: &[u8]) -> Result<(), Error> {
1091 self.wait_for_idle();
1092 self.spi_dma.driver().setup_full_duplex()?;
1093 let empty_rx_buffer = unsafe { self.spi_dma.dma_driver().empty_rx_buffer() };
1094
1095 for chunk in words.chunks(self.tx_buf.capacity()) {
1096 self.tx_buf.as_mut_slice()[..chunk.len()].copy_from_slice(chunk);
1097
1098 unsafe {
1099 self.spi_dma.start_dma_transfer(
1100 0,
1101 chunk.len(),
1102 empty_rx_buffer,
1103 &mut self.tx_buf,
1104 )?;
1105 }
1106
1107 self.wait_for_idle();
1108 }
1109
1110 Ok(())
1111 }
1112
1113 #[instability::unstable]
1115 pub fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
1116 self.wait_for_idle();
1117 self.spi_dma.driver().setup_full_duplex()?;
1118 let chunk_size = min(self.tx_buf.capacity(), self.rx_buf.capacity());
1119
1120 let common_length = min(read.len(), write.len());
1121 let (read_common, read_remainder) = read.split_at_mut(common_length);
1122 let (write_common, write_remainder) = write.split_at(common_length);
1123
1124 for (read_chunk, write_chunk) in read_common
1125 .chunks_mut(chunk_size)
1126 .zip(write_common.chunks(chunk_size))
1127 {
1128 self.tx_buf.as_mut_slice()[..write_chunk.len()].copy_from_slice(write_chunk);
1129
1130 unsafe {
1131 self.spi_dma.start_dma_transfer(
1132 read_chunk.len(),
1133 write_chunk.len(),
1134 &mut self.rx_buf,
1135 &mut self.tx_buf,
1136 )?;
1137 }
1138 self.wait_for_idle();
1139
1140 read_chunk.copy_from_slice(&self.rx_buf.as_slice()[..read_chunk.len()]);
1141 }
1142
1143 if !read_remainder.is_empty() {
1144 self.read(read_remainder)
1145 } else if !write_remainder.is_empty() {
1146 self.write(write_remainder)
1147 } else {
1148 Ok(())
1149 }
1150 }
1151
1152 #[instability::unstable]
1154 pub fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Error> {
1155 self.wait_for_idle();
1156 self.spi_dma.driver().setup_full_duplex()?;
1157 let chunk_size = min(self.tx_buf.capacity(), self.rx_buf.capacity());
1158
1159 for chunk in words.chunks_mut(chunk_size) {
1160 self.tx_buf.as_mut_slice()[..chunk.len()].copy_from_slice(chunk);
1161
1162 unsafe {
1163 self.spi_dma.start_dma_transfer(
1164 chunk.len(),
1165 chunk.len(),
1166 &mut self.rx_buf,
1167 &mut self.tx_buf,
1168 )?;
1169 }
1170 self.wait_for_idle();
1171 chunk.copy_from_slice(&self.rx_buf.as_slice()[..chunk.len()]);
1172 }
1173
1174 Ok(())
1175 }
1176
1177 #[instability::unstable]
1179 pub fn half_duplex_read(
1180 &mut self,
1181 data_mode: DataMode,
1182 cmd: Command,
1183 address: Address,
1184 dummy: u8,
1185 buffer: &mut [u8],
1186 ) -> Result<(), Error> {
1187 if buffer.len() > self.rx_buf.capacity() {
1188 return Err(Error::from(DmaError::Overflow));
1189 }
1190 self.wait_for_idle();
1191
1192 unsafe {
1193 self.spi_dma.start_half_duplex_read(
1194 data_mode,
1195 cmd,
1196 address,
1197 dummy,
1198 buffer.len(),
1199 &mut self.rx_buf,
1200 )?;
1201 }
1202
1203 self.wait_for_idle();
1204
1205 buffer.copy_from_slice(&self.rx_buf.as_slice()[..buffer.len()]);
1206
1207 Ok(())
1208 }
1209
1210 #[instability::unstable]
1212 pub fn half_duplex_write(
1213 &mut self,
1214 data_mode: DataMode,
1215 cmd: Command,
1216 address: Address,
1217 dummy: u8,
1218 buffer: &[u8],
1219 ) -> Result<(), Error> {
1220 if buffer.len() > self.tx_buf.capacity() {
1221 return Err(Error::from(DmaError::Overflow));
1222 }
1223 self.wait_for_idle();
1224 self.tx_buf.as_mut_slice()[..buffer.len()].copy_from_slice(buffer);
1225
1226 unsafe {
1227 self.spi_dma.start_half_duplex_write(
1228 data_mode,
1229 cmd,
1230 address,
1231 dummy,
1232 buffer.len(),
1233 &mut self.tx_buf,
1234 )?;
1235 }
1236
1237 self.wait_for_idle();
1238
1239 Ok(())
1240 }
1241}
1242
1243#[instability::unstable]
1244impl crate::interrupt::InterruptConfigurable for SpiDmaBus<'_, Blocking> {
1245 fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
1249 self.spi_dma.set_interrupt_handler(handler);
1250 }
1251}
1252
1253#[instability::unstable]
1254impl<Dm> embassy_embedded_hal::SetConfig for SpiDmaBus<'_, Dm>
1255where
1256 Dm: DriverMode,
1257{
1258 type Config = Config;
1259 type ConfigError = ConfigError;
1260
1261 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
1262 self.apply_config(config)
1263 }
1264}
1265
1266pub(super) struct DmaDriver {
1267 driver: Driver,
1268 dma_peripheral: crate::dma::DmaPeripheral,
1269 state: &'static DmaState,
1270}
1271
1272impl DmaDriver {
1273 unsafe fn empty_rx_buffer(&self) -> &'static mut DmaRxBuf {
1274 unsafe { self.state.empty_rx_buffer() }
1275 }
1276
1277 unsafe fn empty_tx_buffer(&self) -> &'static mut DmaTxBuf {
1278 unsafe { self.state.empty_tx_buffer() }
1279 }
1280
1281 fn abort_transfer(&self) {
1282 self.driver.configure_datalen(1, 1);
1289 self.driver.update();
1290 }
1291
1292 fn regs(&self) -> &RegisterBlock {
1293 self.driver.regs()
1294 }
1295
1296 #[cfg_attr(place_spi_master_driver_in_ram, ram)]
1297 unsafe fn start_transfer_dma<Dm: DriverMode>(
1298 &self,
1299 _full_duplex: bool,
1300 rx_len: usize,
1301 tx_len: usize,
1302 rx_buffer: &mut impl DmaRxBuffer,
1303 tx_buffer: &mut impl DmaTxBuffer,
1304 channel: &mut Channel<Dm, PeripheralDmaChannel<AnySpi<'_>>>,
1305 ) -> Result<(), Error> {
1306 #[cfg(esp32s2)]
1307 {
1308 self.regs().dma_out_link().write(|w| unsafe { w.bits(0) });
1310 self.regs().dma_in_link().write(|w| unsafe { w.bits(0) });
1311 }
1312
1313 self.driver.configure_datalen(rx_len, tx_len);
1314
1315 self.regs()
1317 .user()
1318 .modify(|_, w| w.usr_miso().bit(rx_len > 0).usr_mosi().bit(tx_len > 0));
1319
1320 self.enable_dma();
1321
1322 if rx_len > 0 {
1323 unsafe {
1324 channel
1325 .rx
1326 .prepare_transfer(self.dma_peripheral, rx_buffer)
1327 .and_then(|_| channel.rx.start_transfer())?;
1328 }
1329 } else {
1330 #[cfg(esp32)]
1331 {
1332 if _full_duplex {
1335 self.regs()
1336 .dma_in_link()
1337 .modify(|_, w| unsafe { w.inlink_addr().bits(0) });
1338 self.regs()
1339 .dma_in_link()
1340 .modify(|_, w| w.inlink_start().set_bit());
1341 }
1342 }
1343 }
1344 if tx_len > 0 {
1345 unsafe {
1346 channel
1347 .tx
1348 .prepare_transfer(self.dma_peripheral, tx_buffer)
1349 .and_then(|_| channel.tx.start_transfer())?;
1350 }
1351 }
1352
1353 #[cfg(dma_kind = "gdma")]
1354 self.reset_dma();
1355
1356 self.driver.start_operation();
1357
1358 Ok(())
1359 }
1360
1361 fn enable_dma(&self) {
1362 #[cfg(dma_kind = "gdma")]
1363 self.regs().dma_conf().modify(|_, w| {
1365 w.dma_tx_ena().set_bit();
1366 w.dma_rx_ena().set_bit()
1367 });
1368
1369 #[cfg(dma_kind = "pdma")]
1370 self.reset_dma();
1371 }
1372
1373 fn reset_dma(&self) {
1374 #[cfg(dma_kind = "pdma")]
1375 self.regs().dma_conf().toggle(|w, bit| {
1376 w.out_rst().bit(bit);
1377 w.in_rst().bit(bit);
1378 w.ahbm_fifo_rst().bit(bit);
1379 w.ahbm_rst().bit(bit)
1380 });
1381
1382 #[cfg(dma_kind = "gdma")]
1383 self.regs().dma_conf().toggle(|w, bit| {
1384 w.rx_afifo_rst().bit(bit);
1385 w.buf_afifo_rst().bit(bit);
1386 w.dma_afifo_rst().bit(bit)
1387 });
1388
1389 self.clear_dma_interrupts();
1390 }
1391
1392 #[cfg(dma_kind = "gdma")]
1393 fn clear_dma_interrupts(&self) {
1394 self.regs().dma_int_clr().write(|w| {
1395 w.dma_infifo_full_err().clear_bit_by_one();
1396 w.dma_outfifo_empty_err().clear_bit_by_one();
1397 w.trans_done().clear_bit_by_one();
1398 w.mst_rx_afifo_wfull_err().clear_bit_by_one();
1399 w.mst_tx_afifo_rempty_err().clear_bit_by_one()
1400 });
1401 }
1402
1403 #[cfg(dma_kind = "pdma")]
1404 fn clear_dma_interrupts(&self) {
1405 self.regs().dma_int_clr().write(|w| {
1406 w.inlink_dscr_empty().clear_bit_by_one();
1407 w.outlink_dscr_error().clear_bit_by_one();
1408 w.inlink_dscr_error().clear_bit_by_one();
1409 w.in_done().clear_bit_by_one();
1410 w.in_err_eof().clear_bit_by_one();
1411 w.in_suc_eof().clear_bit_by_one();
1412 w.out_done().clear_bit_by_one();
1413 w.out_eof().clear_bit_by_one();
1414 w.out_total_eof().clear_bit_by_one()
1415 });
1416 }
1417}
1418
1419impl<'d> DmaEligible for AnySpi<'d> {
1420 #[cfg(dma_kind = "gdma")]
1421 type Dma = crate::dma::AnyGdmaChannel<'d>;
1422 #[cfg(dma_kind = "pdma")]
1423 type Dma = crate::dma::AnySpiDmaChannel<'d>;
1424
1425 fn dma_peripheral(&self) -> crate::dma::DmaPeripheral {
1426 let (info, _state) = self.dma_parts();
1427 info.dma_peripheral
1428 }
1429}
1430
1431#[instability::unstable]
1432impl embedded_hal_async::spi::SpiBus for SpiDmaBus<'_, Async> {
1433 async fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
1434 self.read_async(words).await
1435 }
1436
1437 async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
1438 self.write_async(words).await
1439 }
1440
1441 async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
1442 self.transfer_async(read, write).await
1443 }
1444
1445 async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
1446 self.transfer_in_place_async(words).await
1447 }
1448
1449 async fn flush(&mut self) -> Result<(), Self::Error> {
1450 Ok(())
1452 }
1453}
1454
1455#[instability::unstable]
1456impl<Dm> ErrorType for SpiDmaBus<'_, Dm>
1457where
1458 Dm: DriverMode,
1459{
1460 type Error = Error;
1461}
1462
1463#[instability::unstable]
1464impl<Dm> SpiBus for SpiDmaBus<'_, Dm>
1465where
1466 Dm: DriverMode,
1467{
1468 fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
1469 self.read(words)
1470 }
1471
1472 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
1473 self.write(words)
1474 }
1475
1476 fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
1477 self.transfer(read, write)
1478 }
1479
1480 fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
1481 self.transfer_in_place(words)
1482 }
1483
1484 fn flush(&mut self) -> Result<(), Self::Error> {
1485 Ok(())
1487 }
1488}
1489
1490struct DmaInfo {
1491 dma_peripheral: crate::dma::DmaPeripheral,
1492}
1493struct DmaState {
1494 tx_transfer_in_progress: Cell<bool>,
1495 rx_transfer_in_progress: Cell<bool>,
1496
1497 empty_rx_buffer: UnsafeCell<MaybeUninit<DmaRxBuf>>,
1498 empty_tx_buffer: UnsafeCell<MaybeUninit<DmaTxBuf>>,
1499}
1500
1501impl DmaState {
1502 #[allow(
1508 clippy::mut_from_ref,
1509 reason = "Safety requirements ensure this is okay"
1510 )]
1511 unsafe fn empty_rx_buffer(&self) -> &mut DmaRxBuf {
1512 unsafe { (&mut *self.empty_rx_buffer.get()).assume_init_mut() }
1513 }
1514
1515 #[allow(
1521 clippy::mut_from_ref,
1522 reason = "Safety requirements ensure this is okay"
1523 )]
1524 unsafe fn empty_tx_buffer(&self) -> &mut DmaTxBuf {
1525 unsafe { (&mut *self.empty_tx_buffer.get()).assume_init_mut() }
1526 }
1527}
1528
1529unsafe impl Sync for DmaState {}
1532
1533for_each_spi_master!(
1534 (all $( ($peri:ident, $sys:ident, $sclk:ident $_cs:tt $_sio:tt $(, $is_qspi:tt)?)),* ) => {
1535 impl AnySpi<'_> {
1536 #[inline(always)]
1537 fn dma_parts(&self) -> (&'static DmaInfo, &'static DmaState) {
1538 match &self.0 {
1539 $(
1540 super::any::Inner::$sys(_spi) => {
1541 static DMA_INFO: DmaInfo = DmaInfo {
1542 dma_peripheral: crate::dma::DmaPeripheral::$sys,
1543 };
1544
1545 static DMA_STATE: DmaState = DmaState {
1546 tx_transfer_in_progress: Cell::new(false),
1547 rx_transfer_in_progress: Cell::new(false),
1548
1549 empty_rx_buffer: UnsafeCell::new(MaybeUninit::uninit()),
1550 empty_tx_buffer: UnsafeCell::new(MaybeUninit::uninit()),
1551 };
1552
1553 (&DMA_INFO, &DMA_STATE)
1554 }
1555 )*
1556 }
1557 }
1558
1559 #[inline(always)]
1560 fn dma_state(&self) -> &'static DmaState {
1561 let (_, state) = self.dma_parts();
1562 state
1563 }
1564
1565 #[inline(always)]
1566 fn dma_info(&self) -> &'static DmaInfo {
1567 let (info, _) = self.dma_parts();
1568 info
1569 }
1570 }
1571 };
1572);
1573
1574impl SpiWrapper<'_> {
1575 fn dma_state(&self) -> &'static DmaState {
1576 self.spi.dma_state()
1577 }
1578
1579 #[inline(always)]
1580 fn dma_peripheral(&self) -> crate::dma::DmaPeripheral {
1581 self.spi.dma_peripheral()
1582 }
1583}