aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/sdmmc
diff options
context:
space:
mode:
authorAnton Lazarev <[email protected]>2025-03-26 23:26:11 -0700
committerAnton Lazarev <[email protected]>2025-03-31 12:47:41 -0700
commit0a231505d8225f3f36f39b0be1ded4304fb7ccca (patch)
treef9021b5e5622ec84e55ea9fdb32ac5442c42fdb3 /embassy-stm32/src/sdmmc
parentb92eb948b5de521205e3a8bb81548662c7fc5c1d (diff)
support 8 lane data bus
Diffstat (limited to 'embassy-stm32/src/sdmmc')
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs162
1 files changed, 158 insertions, 4 deletions
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index f92c0260b..a0c3573a9 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -145,6 +145,8 @@ pub enum Error {
145 Crc, 145 Crc,
146 /// No card inserted. 146 /// No card inserted.
147 NoCard, 147 NoCard,
148 /// 8-lane buses are not supported for SD cards.
149 BusWidth,
148 /// Bad clock supplied to the SDMMC peripheral. 150 /// Bad clock supplied to the SDMMC peripheral.
149 BadClock, 151 BadClock,
150 /// Signaling switch failed. 152 /// Signaling switch failed.
@@ -365,6 +367,10 @@ pub struct Sdmmc<'d, T: Instance> {
365 d1: Option<Peri<'d, AnyPin>>, 367 d1: Option<Peri<'d, AnyPin>>,
366 d2: Option<Peri<'d, AnyPin>>, 368 d2: Option<Peri<'d, AnyPin>>,
367 d3: Option<Peri<'d, AnyPin>>, 369 d3: Option<Peri<'d, AnyPin>>,
370 d4: Option<Peri<'d, AnyPin>>,
371 d5: Option<Peri<'d, AnyPin>>,
372 d6: Option<Peri<'d, AnyPin>>,
373 d7: Option<Peri<'d, AnyPin>>,
368 374
369 config: Config, 375 config: Config,
370 /// Current clock to card 376 /// Current clock to card
@@ -413,6 +419,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
413 None, 419 None,
414 None, 420 None,
415 None, 421 None,
422 None,
423 None,
424 None,
425 None,
416 config, 426 config,
417 ) 427 )
418 } 428 }
@@ -448,6 +458,60 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
448 Some(d1.into()), 458 Some(d1.into()),
449 Some(d2.into()), 459 Some(d2.into()),
450 Some(d3.into()), 460 Some(d3.into()),
461 None,
462 None,
463 None,
464 None,
465 config,
466 )
467 }
468}
469
470#[cfg(sdmmc_v1)]
471impl<'d, T: Instance> Sdmmc<'d, T> {
472 /// Create a new SDMMC driver, with 8 data lanes.
473 pub fn new_8bit(
474 sdmmc: Peri<'d, T>,
475 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
476 dma: Peri<'d, impl SdmmcDma<T>>,
477 clk: Peri<'d, impl CkPin<T>>,
478 cmd: Peri<'d, impl CmdPin<T>>,
479 d0: Peri<'d, impl D0Pin<T>>,
480 d1: Peri<'d, impl D1Pin<T>>,
481 d2: Peri<'d, impl D2Pin<T>>,
482 d3: Peri<'d, impl D3Pin<T>>,
483 d4: Peri<'d, impl D4Pin<T>>,
484 d5: Peri<'d, impl D5Pin<T>>,
485 d6: Peri<'d, impl D6Pin<T>>,
486 d7: Peri<'d, impl D7Pin<T>>,
487 config: Config,
488 ) -> Self {
489 critical_section::with(|_| {
490 clk.set_as_af(clk.af_num(), CLK_AF);
491 cmd.set_as_af(cmd.af_num(), CMD_AF);
492 d0.set_as_af(d0.af_num(), DATA_AF);
493 d1.set_as_af(d1.af_num(), DATA_AF);
494 d2.set_as_af(d2.af_num(), DATA_AF);
495 d3.set_as_af(d3.af_num(), DATA_AF);
496 d4.set_as_af(d4.af_num(), DATA_AF);
497 d5.set_as_af(d5.af_num(), DATA_AF);
498 d6.set_as_af(d6.af_num(), DATA_AF);
499 d7.set_as_af(d7.af_num(), DATA_AF);
500 });
501
502 Self::new_inner(
503 sdmmc,
504 new_dma_nonopt!(dma),
505 clk.into(),
506 cmd.into(),
507 d0.into(),
508 Some(d1.into()),
509 Some(d2.into()),
510 Some(d3.into()),
511 Some(d4.into()),
512 Some(d5.into()),
513 Some(d6.into()),
514 Some(d7.into()),
451 config, 515 config,
452 ) 516 )
453 } 517 }
@@ -470,7 +534,20 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
470 d0.set_as_af(d0.af_num(), DATA_AF); 534 d0.set_as_af(d0.af_num(), DATA_AF);
471 }); 535 });
472 536
473 Self::new_inner(sdmmc, clk.into(), cmd.into(), d0.into(), None, None, None, config) 537 Self::new_inner(
538 sdmmc,
539 clk.into(),
540 cmd.into(),
541 d0.into(),
542 None,
543 None,
544 None,
545 None,
546 None,
547 None,
548 None,
549 config,
550 )
474 } 551 }
475 552
476 /// Create a new SDMMC driver, with 4 data lanes. 553 /// Create a new SDMMC driver, with 4 data lanes.
@@ -502,6 +579,58 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
502 Some(d1.into()), 579 Some(d1.into()),
503 Some(d2.into()), 580 Some(d2.into()),
504 Some(d3.into()), 581 Some(d3.into()),
582 None,
583 None,
584 None,
585 None,
586 config,
587 )
588 }
589}
590
591#[cfg(sdmmc_v2)]
592impl<'d, T: Instance> Sdmmc<'d, T> {
593 /// Create a new SDMMC driver, with 8 data lanes.
594 pub fn new_8bit(
595 sdmmc: Peri<'d, T>,
596 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
597 clk: Peri<'d, impl CkPin<T>>,
598 cmd: Peri<'d, impl CmdPin<T>>,
599 d0: Peri<'d, impl D0Pin<T>>,
600 d1: Peri<'d, impl D1Pin<T>>,
601 d2: Peri<'d, impl D2Pin<T>>,
602 d3: Peri<'d, impl D3Pin<T>>,
603 d4: Peri<'d, impl D4Pin<T>>,
604 d5: Peri<'d, impl D5Pin<T>>,
605 d6: Peri<'d, impl D6Pin<T>>,
606 d7: Peri<'d, impl D7Pin<T>>,
607 config: Config,
608 ) -> Self {
609 critical_section::with(|_| {
610 clk.set_as_af(clk.af_num(), CLK_AF);
611 cmd.set_as_af(cmd.af_num(), CMD_AF);
612 d0.set_as_af(d0.af_num(), DATA_AF);
613 d1.set_as_af(d1.af_num(), DATA_AF);
614 d2.set_as_af(d2.af_num(), DATA_AF);
615 d3.set_as_af(d3.af_num(), DATA_AF);
616 d4.set_as_af(d4.af_num(), DATA_AF);
617 d5.set_as_af(d5.af_num(), DATA_AF);
618 d6.set_as_af(d6.af_num(), DATA_AF);
619 d7.set_as_af(d7.af_num(), DATA_AF);
620 });
621
622 Self::new_inner(
623 sdmmc,
624 clk.into(),
625 cmd.into(),
626 d0.into(),
627 Some(d1.into()),
628 Some(d2.into()),
629 Some(d3.into()),
630 Some(d4.into()),
631 Some(d5.into()),
632 Some(d6.into()),
633 Some(d7.into()),
505 config, 634 config,
506 ) 635 )
507 } 636 }
@@ -517,6 +646,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
517 d1: Option<Peri<'d, AnyPin>>, 646 d1: Option<Peri<'d, AnyPin>>,
518 d2: Option<Peri<'d, AnyPin>>, 647 d2: Option<Peri<'d, AnyPin>>,
519 d3: Option<Peri<'d, AnyPin>>, 648 d3: Option<Peri<'d, AnyPin>>,
649 d4: Option<Peri<'d, AnyPin>>,
650 d5: Option<Peri<'d, AnyPin>>,
651 d6: Option<Peri<'d, AnyPin>>,
652 d7: Option<Peri<'d, AnyPin>>,
520 config: Config, 653 config: Config,
521 ) -> Self { 654 ) -> Self {
522 rcc::enable_and_reset::<T>(); 655 rcc::enable_and_reset::<T>();
@@ -555,6 +688,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
555 d1, 688 d1,
556 d2, 689 d2,
557 d3, 690 d3,
691 d4,
692 d5,
693 d6,
694 d7,
558 695
559 config, 696 config,
560 clock: SD_INIT_FREQ, 697 clock: SD_INIT_FREQ,
@@ -1039,6 +1176,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
1039impl<'d, T: Instance> Sdmmc<'d, T> { 1176impl<'d, T: Instance> Sdmmc<'d, T> {
1040 /// Initializes card (if present) and sets the bus at the specified frequency. 1177 /// Initializes card (if present) and sets the bus at the specified frequency.
1041 pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> { 1178 pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> {
1179 if self.d7.is_some() {
1180 return Err(Error::BusWidth);
1181 }
1182
1042 let regs = T::regs(); 1183 let regs = T::regs();
1043 let ker_ck = T::frequency(); 1184 let ker_ck = T::frequency();
1044 1185
@@ -1419,9 +1560,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
1419 let regs = T::regs(); 1560 let regs = T::regs();
1420 let ker_ck = T::frequency(); 1561 let ker_ck = T::frequency();
1421 1562
1422 let bus_width = match self.d3.is_some() { 1563 let bus_width = match (self.d3.is_some(), self.d7.is_some()) {
1423 true => BusWidth::Four, 1564 (true, true) => BusWidth::Eight,
1424 false => BusWidth::One, 1565 (true, false) => BusWidth::Four,
1566 _ => BusWidth::One,
1425 }; 1567 };
1426 1568
1427 // While the SD/SDIO card or eMMC is in identification mode, 1569 // While the SD/SDIO card or eMMC is in identification mode,
@@ -1613,6 +1755,18 @@ impl<'d, T: Instance> Drop for Sdmmc<'d, T> {
1613 if let Some(x) = &mut self.d3 { 1755 if let Some(x) = &mut self.d3 {
1614 x.set_as_disconnected(); 1756 x.set_as_disconnected();
1615 } 1757 }
1758 if let Some(x) = &mut self.d4 {
1759 x.set_as_disconnected();
1760 }
1761 if let Some(x) = &mut self.d5 {
1762 x.set_as_disconnected();
1763 }
1764 if let Some(x) = &mut self.d6 {
1765 x.set_as_disconnected();
1766 }
1767 if let Some(x) = &mut self.d7 {
1768 x.set_as_disconnected();
1769 }
1616 }); 1770 });
1617 } 1771 }
1618} 1772}