1#![doc = crate::before_snippet!()]
18#![cfg_attr(pdma, doc = "let dma_channel = peripherals.DMA_SPI2;")]
22#![cfg_attr(gdma, doc = "let dma_channel = peripherals.DMA_CH0;")]
23#![cfg_attr(esp32, doc = "- ESP32 only supports SPI mode 1 and 3.\n\n")]
65use core::marker::PhantomData;
73
74use super::{Error, Mode};
75use crate::{
76 dma::DmaEligible,
77 gpio::{
78 interconnect::{PeripheralInput, PeripheralOutput},
79 InputSignal,
80 NoPin,
81 OutputSignal,
82 },
83 pac::spi2::RegisterBlock,
84 peripheral::{Peripheral, PeripheralRef},
85 spi::AnySpi,
86 system::PeripheralGuard,
87 Blocking,
88 DriverMode,
89};
90
91const MAX_DMA_SIZE: usize = 32768 - 32;
92
93#[instability::unstable]
97pub struct Spi<'d, Dm: DriverMode> {
98 spi: PeripheralRef<'d, AnySpi>,
99 #[allow(dead_code)]
100 data_mode: Mode,
101 _mode: PhantomData<Dm>,
102 _guard: PeripheralGuard,
103}
104impl<'d> Spi<'d, Blocking> {
105 #[instability::unstable]
107 pub fn new(spi: impl Peripheral<P = impl Instance> + 'd, mode: Mode) -> Spi<'d, Blocking> {
108 crate::into_mapped_ref!(spi);
109
110 let guard = PeripheralGuard::new(spi.info().peripheral);
111
112 let this = Spi {
113 spi,
114 data_mode: mode,
115 _mode: PhantomData,
116 _guard: guard,
117 };
118
119 this.spi.info().init();
120 this.spi.info().set_data_mode(mode, false);
121
122 this.with_mosi(NoPin)
123 .with_miso(NoPin)
124 .with_sck(NoPin)
125 .with_cs(NoPin)
126 }
127
128 #[instability::unstable]
130 pub fn with_sck(self, sclk: impl Peripheral<P = impl PeripheralInput> + 'd) -> Self {
131 crate::into_mapped_ref!(sclk);
132 sclk.enable_input(true);
133 self.spi.info().sclk.connect_to(sclk);
134 self
135 }
136
137 #[instability::unstable]
139 pub fn with_mosi(self, mosi: impl Peripheral<P = impl PeripheralInput> + 'd) -> Self {
140 crate::into_mapped_ref!(mosi);
141 mosi.enable_input(true);
142 self.spi.info().mosi.connect_to(mosi);
143 self
144 }
145
146 #[instability::unstable]
148 pub fn with_miso(self, miso: impl Peripheral<P = impl PeripheralOutput> + 'd) -> Self {
149 crate::into_mapped_ref!(miso);
150 miso.set_to_push_pull_output();
151 self.spi.info().miso.connect_to(miso);
152 self
153 }
154
155 #[instability::unstable]
157 pub fn with_cs(self, cs: impl Peripheral<P = impl PeripheralInput> + 'd) -> Self {
158 crate::into_mapped_ref!(cs);
159 cs.enable_input(true);
160 self.spi.info().cs.connect_to(cs);
161 self
162 }
163}
164
165#[instability::unstable]
167pub mod dma {
168 use super::*;
169 use crate::{
170 dma::{
171 dma_private::{DmaSupport, DmaSupportRx, DmaSupportTx},
172 Channel,
173 ChannelRx,
174 ChannelTx,
175 DescriptorChain,
176 DmaChannelFor,
177 DmaDescriptor,
178 DmaTransferRx,
179 DmaTransferRxTx,
180 DmaTransferTx,
181 PeripheralDmaChannel,
182 PeripheralRxChannel,
183 PeripheralTxChannel,
184 ReadBuffer,
185 Rx,
186 Tx,
187 WriteBuffer,
188 },
189 DriverMode,
190 };
191
192 impl<'d> Spi<'d, Blocking> {
193 #[cfg_attr(esp32, doc = "\n\n**Note**: ESP32 only supports Mode 1 and 3.")]
196 #[instability::unstable]
197 pub fn with_dma<CH>(
198 self,
199 channel: impl Peripheral<P = CH> + 'd,
200 rx_descriptors: &'static mut [DmaDescriptor],
201 tx_descriptors: &'static mut [DmaDescriptor],
202 ) -> SpiDma<'d, Blocking>
203 where
204 CH: DmaChannelFor<AnySpi>,
205 {
206 self.spi.info().set_data_mode(self.data_mode, true);
207 SpiDma::new(
208 self.spi,
209 channel.map(|ch| ch.degrade()).into_ref(),
210 rx_descriptors,
211 tx_descriptors,
212 )
213 }
214 }
215
216 #[instability::unstable]
218 pub struct SpiDma<'d, Dm>
219 where
220 Dm: DriverMode,
221 {
222 pub(crate) spi: PeripheralRef<'d, AnySpi>,
223 pub(crate) channel: Channel<'d, Dm, PeripheralDmaChannel<AnySpi>>,
224 rx_chain: DescriptorChain,
225 tx_chain: DescriptorChain,
226 _guard: PeripheralGuard,
227 }
228
229 impl<Dm> core::fmt::Debug for SpiDma<'_, Dm>
230 where
231 Dm: DriverMode,
232 {
233 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
234 f.debug_struct("SpiDma").finish()
235 }
236 }
237
238 impl<Dm> DmaSupport for SpiDma<'_, Dm>
239 where
240 Dm: DriverMode,
241 {
242 fn peripheral_wait_dma(&mut self, is_rx: bool, is_tx: bool) {
243 while !((!is_tx || self.channel.tx.is_done())
244 && (!is_rx || self.channel.rx.is_done())
245 && !self.spi.info().is_bus_busy())
246 {}
247
248 self.spi.info().flush().ok();
249 }
250
251 fn peripheral_dma_stop(&mut self) {
252 unreachable!("unsupported")
253 }
254 }
255
256 impl<'d, Dm> DmaSupportTx for SpiDma<'d, Dm>
257 where
258 Dm: DriverMode,
259 {
260 type TX = ChannelTx<'d, Dm, PeripheralTxChannel<AnySpi>>;
261
262 fn tx(&mut self) -> &mut Self::TX {
263 &mut self.channel.tx
264 }
265
266 fn chain(&mut self) -> &mut DescriptorChain {
267 &mut self.tx_chain
268 }
269 }
270
271 impl<'d, Dm> DmaSupportRx for SpiDma<'d, Dm>
272 where
273 Dm: DriverMode,
274 {
275 type RX = ChannelRx<'d, Dm, PeripheralRxChannel<AnySpi>>;
276
277 fn rx(&mut self) -> &mut Self::RX {
278 &mut self.channel.rx
279 }
280
281 fn chain(&mut self) -> &mut DescriptorChain {
282 &mut self.rx_chain
283 }
284 }
285
286 impl<'d> SpiDma<'d, Blocking> {
287 fn new(
288 spi: PeripheralRef<'d, AnySpi>,
289 channel: PeripheralRef<'d, PeripheralDmaChannel<AnySpi>>,
290 rx_descriptors: &'static mut [DmaDescriptor],
291 tx_descriptors: &'static mut [DmaDescriptor],
292 ) -> Self {
293 let channel = Channel::new(channel);
294 channel.runtime_ensure_compatible(&spi);
295 let guard = PeripheralGuard::new(spi.info().peripheral);
296
297 Self {
298 spi,
299 channel,
300 rx_chain: DescriptorChain::new(rx_descriptors),
301 tx_chain: DescriptorChain::new(tx_descriptors),
302 _guard: guard,
303 }
304 }
305 }
306
307 impl<Dm> SpiDma<'_, Dm>
308 where
309 Dm: DriverMode,
310 {
311 fn driver(&self) -> DmaDriver {
312 DmaDriver {
313 info: self.spi.info(),
314 dma_peripheral: self.spi.dma_peripheral(),
315 }
316 }
317
318 #[instability::unstable]
325 pub fn write<'t, TXBUF>(
326 &'t mut self,
327 words: &'t TXBUF,
328 ) -> Result<DmaTransferTx<'t, Self>, Error>
329 where
330 TXBUF: ReadBuffer,
331 {
332 let (ptr, len) = unsafe { words.read_buffer() };
333
334 if len > MAX_DMA_SIZE {
335 return Err(Error::MaxDmaTransferSizeExceeded);
336 }
337
338 unsafe {
339 self.driver()
340 .start_transfer_dma(
341 &mut self.rx_chain,
342 &mut self.tx_chain,
343 core::ptr::null_mut(),
344 0,
345 ptr,
346 len,
347 &mut self.channel.rx,
348 &mut self.channel.tx,
349 )
350 .map(move |_| DmaTransferTx::new(self))
351 }
352 }
353
354 #[instability::unstable]
361 pub fn read<'t, RXBUF>(
362 &'t mut self,
363 words: &'t mut RXBUF,
364 ) -> Result<DmaTransferRx<'t, Self>, Error>
365 where
366 RXBUF: WriteBuffer,
367 {
368 let (ptr, len) = unsafe { words.write_buffer() };
369
370 if len > MAX_DMA_SIZE {
371 return Err(Error::MaxDmaTransferSizeExceeded);
372 }
373
374 unsafe {
375 self.driver()
376 .start_transfer_dma(
377 &mut self.rx_chain,
378 &mut self.tx_chain,
379 ptr,
380 len,
381 core::ptr::null(),
382 0,
383 &mut self.channel.rx,
384 &mut self.channel.tx,
385 )
386 .map(move |_| DmaTransferRx::new(self))
387 }
388 }
389
390 #[instability::unstable]
398 pub fn transfer<'t, RXBUF, TXBUF>(
399 &'t mut self,
400 read_buffer: &'t mut RXBUF,
401 words: &'t TXBUF,
402 ) -> Result<DmaTransferRxTx<'t, Self>, Error>
403 where
404 RXBUF: WriteBuffer,
405 TXBUF: ReadBuffer,
406 {
407 let (write_ptr, write_len) = unsafe { words.read_buffer() };
408 let (read_ptr, read_len) = unsafe { read_buffer.write_buffer() };
409
410 if write_len > MAX_DMA_SIZE || read_len > MAX_DMA_SIZE {
411 return Err(Error::MaxDmaTransferSizeExceeded);
412 }
413
414 unsafe {
415 self.driver()
416 .start_transfer_dma(
417 &mut self.rx_chain,
418 &mut self.tx_chain,
419 read_ptr,
420 read_len,
421 write_ptr,
422 write_len,
423 &mut self.channel.rx,
424 &mut self.channel.tx,
425 )
426 .map(move |_| DmaTransferRxTx::new(self))
427 }
428 }
429 }
430
431 struct DmaDriver {
432 info: &'static Info,
433 dma_peripheral: crate::dma::DmaPeripheral,
434 }
435
436 impl DmaDriver {
437 fn regs(&self) -> &RegisterBlock {
438 self.info.regs()
439 }
440
441 #[allow(clippy::too_many_arguments)]
442 unsafe fn start_transfer_dma<RX, TX>(
443 &self,
444 rx_chain: &mut DescriptorChain,
445 tx_chain: &mut DescriptorChain,
446 read_buffer_ptr: *mut u8,
447 read_buffer_len: usize,
448 write_buffer_ptr: *const u8,
449 write_buffer_len: usize,
450 rx: &mut RX,
451 tx: &mut TX,
452 ) -> Result<(), Error>
453 where
454 RX: Rx,
455 TX: Tx,
456 {
457 self.enable_dma();
458
459 self.info.reset_spi();
460
461 if read_buffer_len > 0 {
462 rx_chain.fill_for_rx(false, read_buffer_ptr, read_buffer_len)?;
463 rx.prepare_transfer_without_start(self.dma_peripheral, rx_chain)?;
464 }
465
466 if write_buffer_len > 0 {
467 tx_chain.fill_for_tx(false, write_buffer_ptr, write_buffer_len)?;
468 tx.prepare_transfer_without_start(self.dma_peripheral, tx_chain)?;
469 }
470
471 #[cfg(esp32)]
472 self.info
473 .prepare_length_and_lines(read_buffer_len, write_buffer_len);
474
475 self.reset_dma_before_usr_cmd();
476
477 #[cfg(not(esp32))]
478 self.regs()
479 .dma_conf()
480 .modify(|_, w| w.dma_slv_seg_trans_en().clear_bit());
481
482 self.clear_dma_interrupts();
483 self.info.setup_for_flush();
484 self.regs().cmd().modify(|_, w| w.usr().set_bit());
485
486 if read_buffer_len > 0 {
487 rx.start_transfer()?;
488 }
489
490 if write_buffer_len > 0 {
491 tx.start_transfer()?;
492 }
493
494 Ok(())
495 }
496
497 fn reset_dma_before_usr_cmd(&self) {
498 #[cfg(gdma)]
499 self.regs().dma_conf().modify(|_, w| {
500 w.rx_afifo_rst().set_bit();
501 w.buf_afifo_rst().set_bit();
502 w.dma_afifo_rst().set_bit()
503 });
504 }
505
506 fn enable_dma(&self) {
507 #[cfg(gdma)]
508 self.regs().dma_conf().modify(|_, w| {
509 w.dma_tx_ena().set_bit();
510 w.dma_rx_ena().set_bit();
511 w.rx_eof_en().clear_bit()
512 });
513
514 #[cfg(pdma)]
515 {
516 fn set_rst_bit(reg_block: &RegisterBlock, bit: bool) {
517 reg_block.dma_conf().modify(|_, w| {
518 w.in_rst().bit(bit);
519 w.out_rst().bit(bit);
520 w.ahbm_fifo_rst().bit(bit);
521 w.ahbm_rst().bit(bit)
522 });
523
524 #[cfg(esp32s2)]
525 reg_block
526 .dma_conf()
527 .modify(|_, w| w.dma_infifo_full_clr().bit(bit));
528 }
529 set_rst_bit(self.regs(), true);
530 set_rst_bit(self.regs(), false);
531 }
532 }
533
534 fn clear_dma_interrupts(&self) {
535 #[cfg(gdma)]
536 self.regs().dma_int_clr().write(|w| {
537 w.dma_infifo_full_err().clear_bit_by_one();
538 w.dma_outfifo_empty_err().clear_bit_by_one();
539 w.trans_done().clear_bit_by_one();
540 w.mst_rx_afifo_wfull_err().clear_bit_by_one();
541 w.mst_tx_afifo_rempty_err().clear_bit_by_one()
542 });
543
544 #[cfg(pdma)]
545 self.regs().dma_int_clr().write(|w| {
546 w.inlink_dscr_empty().clear_bit_by_one();
547 w.outlink_dscr_error().clear_bit_by_one();
548 w.inlink_dscr_error().clear_bit_by_one();
549 w.in_done().clear_bit_by_one();
550 w.in_err_eof().clear_bit_by_one();
551 w.in_suc_eof().clear_bit_by_one();
552 w.out_done().clear_bit_by_one();
553 w.out_eof().clear_bit_by_one();
554 w.out_total_eof().clear_bit_by_one()
555 });
556 }
557 }
558}
559
560#[doc(hidden)]
562pub trait Instance: Peripheral<P = Self> + Into<AnySpi> + 'static {
563 fn info(&self) -> &'static Info;
565}
566
567#[doc(hidden)]
569pub trait InstanceDma: Instance + DmaEligible {}
570
571impl InstanceDma for crate::peripherals::SPI2 {}
572#[cfg(spi3)]
573impl InstanceDma for crate::peripherals::SPI3 {}
574
575#[non_exhaustive]
577#[doc(hidden)]
578pub struct Info {
579 pub register_block: *const RegisterBlock,
583
584 pub peripheral: crate::system::Peripheral,
586
587 pub sclk: InputSignal,
589
590 pub mosi: InputSignal,
592
593 pub miso: OutputSignal,
595
596 pub cs: InputSignal,
598}
599
600impl Info {
601 #[instability::unstable]
603 pub fn regs(&self) -> &RegisterBlock {
604 unsafe { &*self.register_block }
605 }
606
607 fn reset_spi(&self) {
608 #[cfg(esp32)]
609 {
610 self.regs().slave().modify(|_, w| w.sync_reset().set_bit());
611 self.regs()
612 .slave()
613 .modify(|_, w| w.sync_reset().clear_bit());
614 }
615
616 #[cfg(not(esp32))]
617 {
618 self.regs().slave().modify(|_, w| w.soft_reset().set_bit());
619 self.regs()
620 .slave()
621 .modify(|_, w| w.soft_reset().clear_bit());
622 }
623 }
624
625 #[cfg(esp32)]
626 fn prepare_length_and_lines(&self, rx_len: usize, tx_len: usize) {
627 self.regs()
628 .slv_rdbuf_dlen()
629 .write(|w| unsafe { w.bits((rx_len as u32 * 8).saturating_sub(1)) });
630 self.regs()
631 .slv_wrbuf_dlen()
632 .write(|w| unsafe { w.bits((tx_len as u32 * 8).saturating_sub(1)) });
633
634 self.regs().user().modify(|_, w| {
636 w.usr_mosi().bit(rx_len > 0);
637 w.usr_miso().bit(tx_len > 0)
638 });
639 }
640
641 fn init(&self) {
643 self.regs().clock().write(|w| unsafe { w.bits(0) });
644 self.regs().user().write(|w| unsafe { w.bits(0) });
645 self.regs().ctrl().write(|w| unsafe { w.bits(0) });
646
647 self.regs().slave().write(|w| {
648 #[cfg(esp32)]
649 w.slv_wr_rd_buf_en().set_bit();
650
651 w.mode().set_bit()
652 });
653 self.reset_spi();
654
655 self.regs().user().modify(|_, w| {
656 w.doutdin().set_bit();
657 w.sio().clear_bit()
658 });
659
660 #[cfg(not(esp32))]
661 self.regs().misc().write(|w| unsafe { w.bits(0) });
662 }
663
664 fn set_data_mode(&self, data_mode: Mode, dma: bool) {
665 #[cfg(esp32)]
666 {
667 self.regs().pin().modify(|_, w| {
668 w.ck_idle_edge()
669 .bit(matches!(data_mode, Mode::_0 | Mode::_1))
670 });
671 self.regs()
672 .user()
673 .modify(|_, w| w.ck_i_edge().bit(matches!(data_mode, Mode::_1 | Mode::_2)));
674 self.regs().ctrl2().modify(|_, w| unsafe {
675 match data_mode {
676 Mode::_0 => {
677 w.miso_delay_mode().bits(0);
678 w.miso_delay_num().bits(0);
679 w.mosi_delay_mode().bits(2);
680 w.mosi_delay_num().bits(2)
681 }
682 Mode::_1 => {
683 w.miso_delay_mode().bits(2);
684 w.miso_delay_num().bits(0);
685 w.mosi_delay_mode().bits(0);
686 w.mosi_delay_num().bits(0)
687 }
688 Mode::_2 => {
689 w.miso_delay_mode().bits(0);
690 w.miso_delay_num().bits(0);
691 w.mosi_delay_mode().bits(1);
692 w.mosi_delay_num().bits(2)
693 }
694 Mode::_3 => {
695 w.miso_delay_mode().bits(1);
696 w.miso_delay_num().bits(0);
697 w.mosi_delay_mode().bits(0);
698 w.mosi_delay_num().bits(0)
699 }
700 }
701 });
702
703 if dma {
704 assert!(
705 matches!(data_mode, Mode::_1 | Mode::_3),
706 "Mode {:?} is not supported with DMA",
707 data_mode
708 );
709 }
710 }
711
712 #[cfg(not(esp32))]
713 {
714 _ = dma;
715 self.regs().user().modify(|_, w| {
716 w.tsck_i_edge()
717 .bit(matches!(data_mode, Mode::_1 | Mode::_2));
718 w.rsck_i_edge()
719 .bit(matches!(data_mode, Mode::_1 | Mode::_2))
720 });
721 cfg_if::cfg_if! {
722 if #[cfg(esp32s2)] {
723 let ctrl1_reg = self.regs().ctrl1();
724 } else {
725 let ctrl1_reg = self.regs().slave();
726 }
727 }
728 ctrl1_reg.modify(|_, w| {
729 w.clk_mode_13()
730 .bit(matches!(data_mode, Mode::_1 | Mode::_3))
731 });
732 }
733 }
734
735 fn is_bus_busy(&self) -> bool {
736 #[cfg(pdma)]
737 {
738 self.regs().slave().read().trans_done().bit_is_clear()
739 }
740 #[cfg(gdma)]
741 {
742 self.regs().dma_int_raw().read().trans_done().bit_is_clear()
743 }
744 }
745
746 fn flush(&self) -> Result<(), Error> {
748 while self.is_bus_busy() {
749 }
751 Ok(())
752 }
753
754 fn setup_for_flush(&self) {
757 #[cfg(pdma)]
758 self.regs()
759 .slave()
760 .modify(|_, w| w.trans_done().clear_bit());
761 #[cfg(gdma)]
762 self.regs()
763 .dma_int_clr()
764 .write(|w| w.trans_done().clear_bit_by_one());
765 }
766}
767
768impl PartialEq for Info {
769 fn eq(&self, other: &Self) -> bool {
770 self.register_block == other.register_block
771 }
772}
773
774unsafe impl Sync for Info {}
775
776macro_rules! spi_instance {
777 ($num:literal, $sclk:ident, $mosi:ident, $miso:ident, $cs:ident) => {
778 paste::paste! {
779 impl Instance for crate::peripherals::[<SPI $num>] {
780 #[inline(always)]
781 fn info(&self) -> &'static Info {
782 static INFO: Info = Info {
783 register_block: crate::peripherals::[<SPI $num>]::regs(),
784 peripheral: crate::system::Peripheral::[<Spi $num>],
785 sclk: InputSignal::$sclk,
786 mosi: InputSignal::$mosi,
787 miso: OutputSignal::$miso,
788 cs: InputSignal::$cs,
789 };
790
791 &INFO
792 }
793 }
794 }
795 };
796}
797
798cfg_if::cfg_if! {
799 if #[cfg(esp32)] {
800 #[cfg(spi2)]
801 spi_instance!(2, HSPICLK, HSPID, HSPIQ, HSPICS0);
802 #[cfg(spi3)]
803 spi_instance!(3, VSPICLK, VSPID, VSPIQ, VSPICS0);
804 } else {
805 #[cfg(spi2)]
806 spi_instance!(2, FSPICLK, FSPID, FSPIQ, FSPICS0);
807 #[cfg(spi3)]
808 spi_instance!(3, SPI3_CLK, SPI3_D, SPI3_Q, SPI3_CS0);
809 }
810}
811
812impl Instance for super::AnySpi {
813 delegate::delegate! {
814 to match &self.0 {
815 super::AnySpiInner::Spi2(spi) => spi,
816 #[cfg(spi3)]
817 super::AnySpiInner::Spi3(spi) => spi,
818 } {
819 fn info(&self) -> &'static Info;
820 }
821 }
822}
823
824impl InstanceDma for super::AnySpi {}