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