aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs1183
-rw-r--r--examples/stm32f4/src/bin/sdmmc.rs13
-rw-r--r--tests/stm32/Cargo.toml43
-rw-r--r--tests/stm32/gen_test.py44
-rw-r--r--tests/stm32/src/bin/sdmmc.rs148
5 files changed, 757 insertions, 674 deletions
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index ac00b5176..23ece3a2a 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -41,7 +41,7 @@ impl Default for Signalling {
41} 41}
42 42
43#[repr(align(4))] 43#[repr(align(4))]
44#[derive(Debug, Clone)] 44#[derive(Debug, Clone, PartialEq, Eq)]
45#[cfg_attr(feature = "defmt", derive(defmt::Format))] 45#[cfg_attr(feature = "defmt", derive(defmt::Format))]
46pub struct DataBlock(pub [u8; 512]); 46pub struct DataBlock(pub [u8; 512]);
47 47
@@ -61,7 +61,7 @@ impl DerefMut for DataBlock {
61 61
62/// Errors 62/// Errors
63#[non_exhaustive] 63#[non_exhaustive]
64#[derive(Debug, Copy, Clone)] 64#[derive(Debug, Copy, Clone, PartialEq, Eq)]
65#[cfg_attr(feature = "defmt", derive(defmt::Format))] 65#[cfg_attr(feature = "defmt", derive(defmt::Format))]
66pub enum Error { 66pub enum Error {
67 Timeout, 67 Timeout,
@@ -135,57 +135,53 @@ enum Response {
135 Long = 3, 135 Long = 3,
136} 136}
137 137
138cfg_if::cfg_if! { 138/// Calculate clock divisor. Returns a SDMMC_CK less than or equal to
139 if #[cfg(sdmmc_v1)] { 139/// `sdmmc_ck` in Hertz.
140 /// Calculate clock divisor. Returns a SDMMC_CK less than or equal to 140///
141 /// `sdmmc_ck` in Hertz. 141/// Returns `(bypass, clk_div, clk_f)`, where `bypass` enables clock divisor bypass (only sdmmc_v1),
142 /// 142/// `clk_div` is the divisor register value and `clk_f` is the resulting new clock frequency.
143 /// Returns `(bypass, clk_div, clk_f)`, where `bypass` enables clock divisor bypass (only sdmmc_v1), 143#[cfg(sdmmc_v1)]
144 /// `clk_div` is the divisor register value and `clk_f` is the resulting new clock frequency. 144fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(bool, u8, Hertz), Error> {
145 fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(bool, u8, Hertz), Error> { 145 // sdmmc_v1 maximum clock is 50 MHz
146 // sdmmc_v1 maximum clock is 50 MHz 146 if sdmmc_ck > 50_000_000 {
147 if sdmmc_ck > 50_000_000 { 147 return Err(Error::BadClock);
148 return Err(Error::BadClock); 148 }
149 }
150 149
151 // bypass divisor 150 // bypass divisor
152 if ker_ck.0 <= sdmmc_ck { 151 if ker_ck.0 <= sdmmc_ck {
153 return Ok((true, 0, ker_ck)); 152 return Ok((true, 0, ker_ck));
154 } 153 }
155 154
156 // `ker_ck / sdmmc_ck` rounded up 155 // `ker_ck / sdmmc_ck` rounded up
157 let clk_div = match (ker_ck.0 + sdmmc_ck - 1) / sdmmc_ck { 156 let clk_div = match (ker_ck.0 + sdmmc_ck - 1) / sdmmc_ck {
158 0 | 1 => Ok(0), 157 0 | 1 => Ok(0),
159 x @ 2..=258 => { 158 x @ 2..=258 => Ok((x - 2) as u8),
160 Ok((x - 2) as u8) 159 _ => Err(Error::BadClock),
161 } 160 }?;
162 _ => Err(Error::BadClock),
163 }?;
164 161
165 // SDIO_CK frequency = SDIOCLK / [CLKDIV + 2] 162 // SDIO_CK frequency = SDIOCLK / [CLKDIV + 2]
166 let clk_f = Hertz(ker_ck.0 / (clk_div as u32 + 2)); 163 let clk_f = Hertz(ker_ck.0 / (clk_div as u32 + 2));
167 Ok((false, clk_div, clk_f)) 164 Ok((false, clk_div, clk_f))
168 } 165}
169 } else if #[cfg(sdmmc_v2)] { 166
170 /// Calculate clock divisor. Returns a SDMMC_CK less than or equal to 167/// Calculate clock divisor. Returns a SDMMC_CK less than or equal to
171 /// `sdmmc_ck` in Hertz. 168/// `sdmmc_ck` in Hertz.
172 /// 169///
173 /// Returns `(bypass, clk_div, clk_f)`, where `bypass` enables clock divisor bypass (only sdmmc_v1), 170/// Returns `(bypass, clk_div, clk_f)`, where `bypass` enables clock divisor bypass (only sdmmc_v1),
174 /// `clk_div` is the divisor register value and `clk_f` is the resulting new clock frequency. 171/// `clk_div` is the divisor register value and `clk_f` is the resulting new clock frequency.
175 fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(bool, u16, Hertz), Error> { 172#[cfg(sdmmc_v2)]
176 // `ker_ck / sdmmc_ck` rounded up 173fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(bool, u16, Hertz), Error> {
177 match (ker_ck.0 + sdmmc_ck - 1) / sdmmc_ck { 174 // `ker_ck / sdmmc_ck` rounded up
178 0 | 1 => Ok((false, 0, ker_ck)), 175 match (ker_ck.0 + sdmmc_ck - 1) / sdmmc_ck {
179 x @ 2..=2046 => { 176 0 | 1 => Ok((false, 0, ker_ck)),
180 // SDMMC_CK frequency = SDMMCCLK / [CLKDIV + 2] 177 x @ 2..=2046 => {
181 let clk_div = ((x + 1) / 2) as u16; 178 // SDMMC_CK frequency = SDMMCCLK / [CLKDIV * 2]
182 let clk = Hertz(ker_ck.0 / (clk_div as u32 * 2)); 179 let clk_div = ((x + 1) / 2) as u16;
183 180 let clk = Hertz(ker_ck.0 / (clk_div as u32 * 2));
184 Ok((false, clk_div, clk)) 181
185 } 182 Ok((false, clk_div, clk))
186 _ => Err(Error::BadClock),
187 }
188 } 183 }
184 _ => Err(Error::BadClock),
189 } 185 }
190} 186}
191 187
@@ -208,9 +204,10 @@ impl Default for Config {
208} 204}
209 205
210/// Sdmmc device 206/// Sdmmc device
211pub struct Sdmmc<'d, T: Instance, Dma = NoDma> { 207pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> {
212 _peri: PeripheralRef<'d, T>, 208 _peri: PeripheralRef<'d, T>,
213 irq: PeripheralRef<'d, T::Interrupt>, 209 irq: PeripheralRef<'d, T::Interrupt>,
210 #[allow(unused)]
214 dma: PeripheralRef<'d, Dma>, 211 dma: PeripheralRef<'d, Dma>,
215 212
216 clk: PeripheralRef<'d, AnyPin>, 213 clk: PeripheralRef<'d, AnyPin>,
@@ -309,49 +306,6 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
309 config, 306 config,
310 ) 307 )
311 } 308 }
312
313 fn new_inner(
314 sdmmc: impl Peripheral<P = T> + 'd,
315 irq: impl Peripheral<P = T::Interrupt> + 'd,
316 dma: impl Peripheral<P = Dma> + 'd,
317 clk: PeripheralRef<'d, AnyPin>,
318 cmd: PeripheralRef<'d, AnyPin>,
319 d0: PeripheralRef<'d, AnyPin>,
320 d1: Option<PeripheralRef<'d, AnyPin>>,
321 d2: Option<PeripheralRef<'d, AnyPin>>,
322 d3: Option<PeripheralRef<'d, AnyPin>>,
323 config: Config,
324 ) -> Self {
325 into_ref!(sdmmc, irq, dma);
326
327 T::enable();
328 T::reset();
329
330 let inner = T::inner();
331 unsafe { inner.new_inner() };
332
333 irq.set_handler(Self::on_interrupt);
334 irq.unpend();
335 irq.enable();
336
337 Self {
338 _peri: sdmmc,
339 irq,
340 dma,
341
342 clk,
343 cmd,
344 d0,
345 d1,
346 d2,
347 d3,
348
349 config,
350 clock: SD_INIT_FREQ,
351 signalling: Default::default(),
352 card: None,
353 }
354 }
355} 309}
356 310
357#[cfg(sdmmc_v2)] 311#[cfg(sdmmc_v2)]
@@ -379,6 +333,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
379 Self::new_inner( 333 Self::new_inner(
380 sdmmc, 334 sdmmc,
381 irq, 335 irq,
336 NoDma.into_ref(),
382 clk.map_into(), 337 clk.map_into(),
383 cmd.map_into(), 338 cmd.map_into(),
384 d0.map_into(), 339 d0.map_into(),
@@ -421,6 +376,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
421 Self::new_inner( 376 Self::new_inner(
422 sdmmc, 377 sdmmc,
423 irq, 378 irq,
379 NoDma.into_ref(),
424 clk.map_into(), 380 clk.map_into(),
425 cmd.map_into(), 381 cmd.map_into(),
426 d0.map_into(), 382 d0.map_into(),
@@ -430,10 +386,13 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
430 config, 386 config,
431 ) 387 )
432 } 388 }
389}
433 390
391impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
434 fn new_inner( 392 fn new_inner(
435 sdmmc: impl Peripheral<P = T> + 'd, 393 sdmmc: impl Peripheral<P = T> + 'd,
436 irq: impl Peripheral<P = T::Interrupt> + 'd, 394 irq: impl Peripheral<P = T::Interrupt> + 'd,
395 dma: impl Peripheral<P = Dma> + 'd,
437 clk: PeripheralRef<'d, AnyPin>, 396 clk: PeripheralRef<'d, AnyPin>,
438 cmd: PeripheralRef<'d, AnyPin>, 397 cmd: PeripheralRef<'d, AnyPin>,
439 d0: PeripheralRef<'d, AnyPin>, 398 d0: PeripheralRef<'d, AnyPin>,
@@ -442,22 +401,41 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
442 d3: Option<PeripheralRef<'d, AnyPin>>, 401 d3: Option<PeripheralRef<'d, AnyPin>>,
443 config: Config, 402 config: Config,
444 ) -> Self { 403 ) -> Self {
445 into_ref!(sdmmc, irq); 404 into_ref!(sdmmc, irq, dma);
446 405
447 T::enable(); 406 T::enable();
448 T::reset(); 407 T::reset();
449 408
450 let inner = T::inner();
451 unsafe { inner.new_inner() };
452
453 irq.set_handler(Self::on_interrupt); 409 irq.set_handler(Self::on_interrupt);
454 irq.unpend(); 410 irq.unpend();
455 irq.enable(); 411 irq.enable();
456 412
413 let regs = T::regs();
414 unsafe {
415 regs.clkcr().write(|w| {
416 w.set_pwrsav(false);
417 w.set_negedge(false);
418
419 // Hardware flow control is broken on SDIOv1 and causes clock glitches, which result in CRC errors.
420 // See chip erratas for more details.
421 #[cfg(sdmmc_v1)]
422 w.set_hwfc_en(false);
423 #[cfg(sdmmc_v2)]
424 w.set_hwfc_en(true);
425
426 #[cfg(sdmmc_v1)]
427 w.set_clken(true);
428 });
429
430 // Power off, writen 00: Clock to the card is stopped;
431 // D[7:0], CMD, and CK are driven high.
432 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8));
433 }
434
457 Self { 435 Self {
458 _peri: sdmmc, 436 _peri: sdmmc,
459 irq, 437 irq,
460 dma: NoDma.into_ref(), 438 dma,
461 439
462 clk, 440 clk,
463 cmd, 441 cmd,
@@ -472,509 +450,80 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
472 card: None, 450 card: None,
473 } 451 }
474 } 452 }
475}
476
477impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
478 #[inline(always)]
479 pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> {
480 let inner = T::inner();
481 let freq = freq.into();
482
483 let bus_width = match self.d3.is_some() {
484 true => BusWidth::Four,
485 false => BusWidth::One,
486 };
487
488 inner
489 .init_card(
490 freq,
491 bus_width,
492 &mut self.card,
493 &mut self.signalling,
494 T::kernel_clk(),
495 &mut self.clock,
496 T::state(),
497 self.config.data_transfer_timeout,
498 &mut *self.dma,
499 )
500 .await
501 }
502
503 #[inline(always)]
504 pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> {
505 let card_capacity = self.card()?.card_type;
506 let inner = T::inner();
507 let state = T::state();
508
509 // NOTE(unsafe) DataBlock uses align 4
510 let buf = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) };
511 inner
512 .read_block(
513 block_idx,
514 buf,
515 card_capacity,
516 state,
517 self.config.data_transfer_timeout,
518 &mut *self.dma,
519 )
520 .await
521 }
522
523 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> {
524 let card = self.card.as_mut().ok_or(Error::NoCard)?;
525 let inner = T::inner();
526 let state = T::state();
527
528 // NOTE(unsafe) DataBlock uses align 4
529 let buf = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) };
530 inner
531 .write_block(
532 block_idx,
533 buf,
534 card,
535 state,
536 self.config.data_transfer_timeout,
537 &mut *self.dma,
538 )
539 .await
540 }
541
542 /// Get a reference to the initialized card
543 ///
544 /// # Errors
545 ///
546 /// Returns Error::NoCard if [`init_card`](#method.init_card)
547 /// has not previously succeeded
548 #[inline(always)]
549 pub fn card(&self) -> Result<&Card, Error> {
550 self.card.as_ref().ok_or(Error::NoCard)
551 }
552
553 /// Get the current SDMMC bus clock
554 pub fn clock(&self) -> Hertz {
555 self.clock
556 }
557
558 #[inline(always)]
559 fn on_interrupt(_: *mut ()) {
560 let regs = T::inner();
561 let state = T::state();
562
563 regs.data_interrupts(false);
564 state.wake();
565 }
566}
567
568impl<'d, T: Instance, Dma> Drop for Sdmmc<'d, T, Dma> {
569 fn drop(&mut self) {
570 self.irq.disable();
571 let inner = T::inner();
572 unsafe { inner.on_drop() };
573
574 critical_section::with(|_| unsafe {
575 self.clk.set_as_disconnected();
576 self.cmd.set_as_disconnected();
577 self.d0.set_as_disconnected();
578 if let Some(x) = &mut self.d1 {
579 x.set_as_disconnected();
580 }
581 if let Some(x) = &mut self.d2 {
582 x.set_as_disconnected();
583 }
584 if let Some(x) = &mut self.d3 {
585 x.set_as_disconnected();
586 }
587 });
588 }
589}
590
591pub struct SdmmcInner(pub(crate) RegBlock);
592
593impl SdmmcInner {
594 /// # Safety
595 ///
596 /// Access to `regs` registers should be exclusive
597 unsafe fn new_inner(&self) {
598 let regs = self.0;
599
600 regs.clkcr().write(|w| {
601 w.set_pwrsav(false);
602 w.set_negedge(false);
603
604 // Hardware flow control is broken on SDIOv1 and causes clock glitches, which result in CRC errors.
605 // See chip erratas for more details.
606 #[cfg(sdmmc_v1)]
607 w.set_hwfc_en(false);
608 #[cfg(sdmmc_v2)]
609 w.set_hwfc_en(true);
610
611 #[cfg(sdmmc_v1)]
612 w.set_clken(true);
613 });
614
615 // Power off, writen 00: Clock to the card is stopped;
616 // D[7:0], CMD, and CK are driven high.
617 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8));
618 }
619
620 /// Initializes card (if present) and sets the bus at the
621 /// specified frequency.
622 #[allow(clippy::too_many_arguments)]
623 async fn init_card<T: Instance, Dma: SdmmcDma<T>>(
624 &self,
625 freq: Hertz,
626 bus_width: BusWidth,
627 old_card: &mut Option<Card>,
628 signalling: &mut Signalling,
629 ker_ck: Hertz,
630 clock: &mut Hertz,
631 waker_reg: &AtomicWaker,
632 data_transfer_timeout: u32,
633 dma: &mut Dma,
634 ) -> Result<(), Error> {
635 let regs = self.0;
636
637 // NOTE(unsafe) We have exclusive access to the peripheral
638 unsafe {
639 // While the SD/SDIO card or eMMC is in identification mode,
640 // the SDMMC_CK frequency must be no more than 400 kHz.
641 let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
642 *clock = init_clock;
643
644 // CPSMACT and DPSMACT must be 0 to set WIDBUS
645 self.wait_idle();
646
647 regs.clkcr().modify(|w| {
648 w.set_widbus(0);
649 w.set_clkdiv(clkdiv);
650 #[cfg(sdmmc_v1)]
651 w.set_bypass(_bypass);
652 });
653
654 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
655 self.cmd(Cmd::idle(), false)?;
656
657 // Check if cards supports CMD8 (with pattern)
658 self.cmd(Cmd::hs_send_ext_csd(0x1AA), false)?;
659 let r1 = regs.respr(0).read().cardstatus();
660
661 let mut card = if r1 == 0x1AA {
662 // Card echoed back the pattern. Must be at least v2
663 Card::default()
664 } else {
665 return Err(Error::UnsupportedCardVersion);
666 };
667
668 let ocr = loop {
669 // Signal that next command is a app command
670 self.cmd(Cmd::app_cmd(0), false)?; // CMD55
671
672 let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32
673 | CmdAppOper::HIGH_CAPACITY as u32
674 | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32;
675
676 // Initialize card
677 match self.cmd(Cmd::app_op_cmd(arg), false) {
678 // ACMD41
679 Ok(_) => (),
680 Err(Error::Crc) => (),
681 Err(err) => return Err(err),
682 }
683 let ocr: OCR = regs.respr(0).read().cardstatus().into();
684 if !ocr.is_busy() {
685 // Power up done
686 break ocr;
687 }
688 };
689
690 if ocr.high_capacity() {
691 // Card is SDHC or SDXC or SDUC
692 card.card_type = CardCapacity::SDHC;
693 } else {
694 card.card_type = CardCapacity::SDSC;
695 }
696 card.ocr = ocr;
697
698 self.cmd(Cmd::all_send_cid(), false)?; // CMD2
699 let cid0 = regs.respr(0).read().cardstatus() as u128;
700 let cid1 = regs.respr(1).read().cardstatus() as u128;
701 let cid2 = regs.respr(2).read().cardstatus() as u128;
702 let cid3 = regs.respr(3).read().cardstatus() as u128;
703 let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
704 card.cid = cid.into();
705
706 self.cmd(Cmd::send_rel_addr(), false)?;
707 card.rca = regs.respr(0).read().cardstatus() >> 16;
708
709 self.cmd(Cmd::send_csd(card.rca << 16), false)?;
710 let csd0 = regs.respr(0).read().cardstatus() as u128;
711 let csd1 = regs.respr(1).read().cardstatus() as u128;
712 let csd2 = regs.respr(2).read().cardstatus() as u128;
713 let csd3 = regs.respr(3).read().cardstatus() as u128;
714 let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
715 card.csd = csd.into();
716
717 self.select_card(Some(&card))?;
718
719 self.get_scr(&mut card, waker_reg, data_transfer_timeout, dma).await?;
720
721 // Set bus width
722 let (width, acmd_arg) = match bus_width {
723 BusWidth::Eight => unimplemented!(),
724 BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2),
725 _ => (BusWidth::One, 0),
726 };
727 self.cmd(Cmd::app_cmd(card.rca << 16), false)?;
728 self.cmd(Cmd::cmd6(acmd_arg), false)?;
729
730 // CPSMACT and DPSMACT must be 0 to set WIDBUS
731 self.wait_idle();
732
733 regs.clkcr().modify(|w| {
734 w.set_widbus(match width {
735 BusWidth::One => 0,
736 BusWidth::Four => 1,
737 BusWidth::Eight => 2,
738 _ => panic!("Invalid Bus Width"),
739 })
740 });
741
742 // Set Clock
743 if freq.0 <= 25_000_000 {
744 // Final clock frequency
745 self.clkcr_set_clkdiv(freq.0, width, ker_ck, clock)?;
746 } else {
747 // Switch to max clock for SDR12
748 self.clkcr_set_clkdiv(25_000_000, width, ker_ck, clock)?;
749 }
750
751 // Read status
752 self.read_sd_status(&mut card, waker_reg, data_transfer_timeout, dma)
753 .await?;
754
755 if freq.0 > 25_000_000 {
756 // Switch to SDR25
757 *signalling = self
758 .switch_signalling_mode(Signalling::SDR25, waker_reg, data_transfer_timeout, dma)
759 .await?;
760
761 if *signalling == Signalling::SDR25 {
762 // Set final clock frequency
763 self.clkcr_set_clkdiv(freq.0, width, ker_ck, clock)?;
764
765 if self.read_status(&card)?.state() != CurrentState::Transfer {
766 return Err(Error::SignalingSwitchFailed);
767 }
768 }
769 }
770 // Read status after signalling change
771 self.read_sd_status(&mut card, waker_reg, data_transfer_timeout, dma)
772 .await?;
773 old_card.replace(card);
774 }
775
776 Ok(())
777 }
778
779 async fn read_block<T: Instance, Dma: SdmmcDma<T>>(
780 &self,
781 block_idx: u32,
782 buffer: &mut [u32; 128],
783 capacity: CardCapacity,
784 waker_reg: &AtomicWaker,
785 data_transfer_timeout: u32,
786 dma: &mut Dma,
787 ) -> Result<(), Error> {
788 // Always read 1 block of 512 bytes
789 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
790 let address = match capacity {
791 CardCapacity::SDSC => block_idx * 512,
792 _ => block_idx,
793 };
794 self.cmd(Cmd::set_block_length(512), false)?; // CMD16
795
796 let regs = self.0;
797 let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
798
799 unsafe {
800 self.prepare_datapath_read(buffer as *mut [u32; 128], 512, 9, data_transfer_timeout, dma);
801 self.data_interrupts(true);
802 }
803 self.cmd(Cmd::read_single_block(address), true)?;
804
805 let res = poll_fn(|cx| {
806 waker_reg.register(cx.waker());
807 let status = unsafe { regs.star().read() };
808
809 if status.dcrcfail() {
810 return Poll::Ready(Err(Error::Crc));
811 } else if status.dtimeout() {
812 return Poll::Ready(Err(Error::Timeout));
813 } else if status.dataend() {
814 return Poll::Ready(Ok(()));
815 }
816 Poll::Pending
817 })
818 .await;
819 self.clear_interrupt_flags();
820
821 if res.is_ok() {
822 on_drop.defuse();
823 self.stop_datapath();
824 }
825 res
826 }
827
828 async fn write_block<T: Instance, Dma: SdmmcDma<T>>(
829 &self,
830 block_idx: u32,
831 buffer: &[u32; 128],
832 card: &mut Card,
833 waker_reg: &AtomicWaker,
834 data_transfer_timeout: u32,
835 dma: &mut Dma,
836 ) -> Result<(), Error> {
837 // Always read 1 block of 512 bytes
838 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
839 let address = match card.card_type {
840 CardCapacity::SDSC => block_idx * 512,
841 _ => block_idx,
842 };
843 self.cmd(Cmd::set_block_length(512), false)?; // CMD16
844
845 let regs = self.0;
846 let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
847
848 // sdmmc_v1 uses different cmd/dma order than v2, but only for writes
849 #[cfg(sdmmc_v1)]
850 self.cmd(Cmd::write_single_block(address), true)?;
851
852 unsafe {
853 self.prepare_datapath_write(buffer as *const [u32; 128], 512, 9, data_transfer_timeout, dma);
854 self.data_interrupts(true);
855 }
856
857 #[cfg(sdmmc_v2)]
858 self.cmd(Cmd::write_single_block(address), true)?;
859
860 let res = poll_fn(|cx| {
861 waker_reg.register(cx.waker());
862 let status = unsafe { regs.star().read() };
863
864 if status.dcrcfail() {
865 return Poll::Ready(Err(Error::Crc));
866 } else if status.dtimeout() {
867 return Poll::Ready(Err(Error::Timeout));
868 } else if status.dataend() {
869 return Poll::Ready(Ok(()));
870 }
871 Poll::Pending
872 })
873 .await;
874 self.clear_interrupt_flags();
875
876 match res {
877 Ok(_) => {
878 on_drop.defuse();
879 self.stop_datapath();
880
881 // TODO: Make this configurable
882 let mut timeout: u32 = 0x00FF_FFFF;
883
884 // Try to read card status (ACMD13)
885 while timeout > 0 {
886 match self.read_sd_status(card, waker_reg, data_transfer_timeout, dma).await {
887 Ok(_) => return Ok(()),
888 Err(Error::Timeout) => (), // Try again
889 Err(e) => return Err(e),
890 }
891 timeout -= 1;
892 }
893 Err(Error::SoftwareTimeout)
894 }
895 Err(e) => Err(e),
896 }
897 }
898 453
899 /// Data transfer is in progress 454 /// Data transfer is in progress
900 #[inline(always)] 455 #[inline(always)]
901 fn data_active(&self) -> bool { 456 fn data_active() -> bool {
902 let regs = self.0; 457 let regs = T::regs();
903 458
904 // NOTE(unsafe) Atomic read with no side-effects 459 // NOTE(unsafe) Atomic read with no side-effects
905 unsafe { 460 unsafe {
906 let status = regs.star().read(); 461 let status = regs.star().read();
907 cfg_if::cfg_if! { 462 #[cfg(sdmmc_v1)]
908 if #[cfg(sdmmc_v1)] { 463 return status.rxact() || status.txact();
909 status.rxact() || status.txact() 464 #[cfg(sdmmc_v2)]
910 } else if #[cfg(sdmmc_v2)] { 465 return status.dpsmact();
911 status.dpsmact()
912 }
913 }
914 } 466 }
915 } 467 }
916 468
917 /// Coammand transfer is in progress 469 /// Coammand transfer is in progress
918 #[inline(always)] 470 #[inline(always)]
919 fn cmd_active(&self) -> bool { 471 fn cmd_active() -> bool {
920 let regs = self.0; 472 let regs = T::regs();
921 473
922 // NOTE(unsafe) Atomic read with no side-effects 474 // NOTE(unsafe) Atomic read with no side-effects
923 unsafe { 475 unsafe {
924 let status = regs.star().read(); 476 let status = regs.star().read();
925 cfg_if::cfg_if! { 477 #[cfg(sdmmc_v1)]
926 if #[cfg(sdmmc_v1)] { 478 return status.cmdact();
927 status.cmdact() 479 #[cfg(sdmmc_v2)]
928 } else if #[cfg(sdmmc_v2)] { 480 return status.cpsmact();
929 status.cpsmact()
930 }
931 }
932 } 481 }
933 } 482 }
934 483
935 /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) 484 /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2)
936 #[inline(always)] 485 #[inline(always)]
937 fn wait_idle(&self) { 486 fn wait_idle() {
938 while self.data_active() || self.cmd_active() {} 487 while Self::data_active() || Self::cmd_active() {}
939 } 488 }
940 489
941 /// # Safety 490 /// # Safety
942 /// 491 ///
943 /// `buffer` must be valid for the whole transfer and word aligned 492 /// `buffer` must be valid for the whole transfer and word aligned
944 unsafe fn prepare_datapath_read<T: Instance, Dma: SdmmcDma<T>>( 493 unsafe fn prepare_datapath_read(&mut self, buffer: *mut [u32], length_bytes: u32, block_size: u8) {
945 &self,
946 buffer: *mut [u32],
947 length_bytes: u32,
948 block_size: u8,
949 data_transfer_timeout: u32,
950 #[allow(unused_variables)] dma: &mut Dma,
951 ) {
952 assert!(block_size <= 14, "Block size up to 2^14 bytes"); 494 assert!(block_size <= 14, "Block size up to 2^14 bytes");
953 let regs = self.0; 495 let regs = T::regs();
954 496
955 // Command AND Data state machines must be idle 497 // Command AND Data state machines must be idle
956 self.wait_idle(); 498 Self::wait_idle();
957 self.clear_interrupt_flags(); 499 Self::clear_interrupt_flags();
958 500
959 // NOTE(unsafe) We have exclusive access to the regisers 501 // NOTE(unsafe) We have exclusive access to the regisers
960 502
961 regs.dtimer().write(|w| w.set_datatime(data_transfer_timeout)); 503 regs.dtimer()
504 .write(|w| w.set_datatime(self.config.data_transfer_timeout));
962 regs.dlenr().write(|w| w.set_datalength(length_bytes)); 505 regs.dlenr().write(|w| w.set_datalength(length_bytes));
963 506
964 cfg_if::cfg_if! { 507 #[cfg(sdmmc_v1)]
965 if #[cfg(sdmmc_v1)] { 508 {
966 let request = dma.request(); 509 let request = self.dma.request();
967 dma.start_read(request, regs.fifor().ptr() as *const u32, buffer, crate::dma::TransferOptions { 510 self.dma.start_read(
511 request,
512 regs.fifor().ptr() as *const u32,
513 buffer,
514 crate::dma::TransferOptions {
968 pburst: crate::dma::Burst::Incr4, 515 pburst: crate::dma::Burst::Incr4,
969 mburst: crate::dma::Burst::Incr4, 516 mburst: crate::dma::Burst::Incr4,
970 flow_ctrl: crate::dma::FlowControl::Peripheral, 517 flow_ctrl: crate::dma::FlowControl::Peripheral,
971 fifo_threshold: Some(crate::dma::FifoThreshold::Full), 518 fifo_threshold: Some(crate::dma::FifoThreshold::Full),
972 ..Default::default() 519 ..Default::default()
973 }); 520 },
974 } else if #[cfg(sdmmc_v2)] { 521 );
975 regs.idmabase0r().write(|w| w.set_idmabase0(buffer as *mut u32 as u32)); 522 }
976 regs.idmactrlr().modify(|w| w.set_idmaen(true)); 523 #[cfg(sdmmc_v2)]
977 } 524 {
525 regs.idmabase0r().write(|w| w.set_idmabase0(buffer as *mut u32 as u32));
526 regs.idmactrlr().modify(|w| w.set_idmaen(true));
978 } 527 }
979 528
980 regs.dctrl().modify(|w| { 529 regs.dctrl().modify(|w| {
@@ -991,40 +540,41 @@ impl SdmmcInner {
991 /// # Safety 540 /// # Safety
992 /// 541 ///
993 /// `buffer` must be valid for the whole transfer and word aligned 542 /// `buffer` must be valid for the whole transfer and word aligned
994 unsafe fn prepare_datapath_write<T: Instance, Dma: SdmmcDma<T>>( 543 unsafe fn prepare_datapath_write(&mut self, buffer: *const [u32], length_bytes: u32, block_size: u8) {
995 &self,
996 buffer: *const [u32],
997 length_bytes: u32,
998 block_size: u8,
999 data_transfer_timeout: u32,
1000 #[allow(unused_variables)] dma: &mut Dma,
1001 ) {
1002 assert!(block_size <= 14, "Block size up to 2^14 bytes"); 544 assert!(block_size <= 14, "Block size up to 2^14 bytes");
1003 let regs = self.0; 545 let regs = T::regs();
1004 546
1005 // Command AND Data state machines must be idle 547 // Command AND Data state machines must be idle
1006 self.wait_idle(); 548 Self::wait_idle();
1007 self.clear_interrupt_flags(); 549 Self::clear_interrupt_flags();
1008 550
1009 // NOTE(unsafe) We have exclusive access to the regisers 551 // NOTE(unsafe) We have exclusive access to the regisers
1010 552
1011 regs.dtimer().write(|w| w.set_datatime(data_transfer_timeout)); 553 regs.dtimer()
554 .write(|w| w.set_datatime(self.config.data_transfer_timeout));
1012 regs.dlenr().write(|w| w.set_datalength(length_bytes)); 555 regs.dlenr().write(|w| w.set_datalength(length_bytes));
1013 556
1014 cfg_if::cfg_if! { 557 #[cfg(sdmmc_v1)]
1015 if #[cfg(sdmmc_v1)] { 558 {
1016 let request = dma.request(); 559 let request = self.dma.request();
1017 dma.start_write(request, buffer, regs.fifor().ptr() as *mut u32, crate::dma::TransferOptions { 560 self.dma.start_write(
561 request,
562 buffer,
563 regs.fifor().ptr() as *mut u32,
564 crate::dma::TransferOptions {
1018 pburst: crate::dma::Burst::Incr4, 565 pburst: crate::dma::Burst::Incr4,
1019 mburst: crate::dma::Burst::Incr4, 566 mburst: crate::dma::Burst::Incr4,
1020 flow_ctrl: crate::dma::FlowControl::Peripheral, 567 flow_ctrl: crate::dma::FlowControl::Peripheral,
1021 fifo_threshold: Some(crate::dma::FifoThreshold::Full), 568 fifo_threshold: Some(crate::dma::FifoThreshold::Full),
1022 ..Default::default() 569 ..Default::default()
1023 }); 570 },
1024 } else if #[cfg(sdmmc_v2)] { 571 );
1025 regs.idmabase0r().write(|w| w.set_idmabase0(buffer as *const u32 as u32)); 572 }
1026 regs.idmactrlr().modify(|w| w.set_idmaen(true)); 573 #[cfg(sdmmc_v2)]
1027 } 574 {
575 regs.idmabase0r()
576 .write(|w| w.set_idmabase0(buffer as *const u32 as u32));
577 regs.idmactrlr().modify(|w| w.set_idmaen(true));
1028 } 578 }
1029 579
1030 regs.dctrl().modify(|w| { 580 regs.dctrl().modify(|w| {
@@ -1039,26 +589,23 @@ impl SdmmcInner {
1039 } 589 }
1040 590
1041 /// Stops the DMA datapath 591 /// Stops the DMA datapath
1042 fn stop_datapath(&self) { 592 fn stop_datapath() {
1043 let regs = self.0; 593 let regs = T::regs();
1044 594
1045 unsafe { 595 unsafe {
1046 cfg_if::cfg_if! { 596 #[cfg(sdmmc_v1)]
1047 if #[cfg(sdmmc_v1)] { 597 regs.dctrl().modify(|w| {
1048 regs.dctrl().modify(|w| { 598 w.set_dmaen(false);
1049 w.set_dmaen(false); 599 w.set_dten(false);
1050 w.set_dten(false); 600 });
1051 }); 601 #[cfg(sdmmc_v2)]
1052 } else if #[cfg(sdmmc_v2)] { 602 regs.idmactrlr().modify(|w| w.set_idmaen(false));
1053 regs.idmactrlr().modify(|w| w.set_idmaen(false));
1054 }
1055 }
1056 } 603 }
1057 } 604 }
1058 605
1059 /// Sets the CLKDIV field in CLKCR. Updates clock field in self 606 /// Sets the CLKDIV field in CLKCR. Updates clock field in self
1060 fn clkcr_set_clkdiv(&self, freq: u32, width: BusWidth, ker_ck: Hertz, clock: &mut Hertz) -> Result<(), Error> { 607 fn clkcr_set_clkdiv(&mut self, freq: u32, width: BusWidth) -> Result<(), Error> {
1061 let regs = self.0; 608 let regs = T::regs();
1062 609
1063 let width_u32 = match width { 610 let width_u32 = match width {
1064 BusWidth::One => 1u32, 611 BusWidth::One => 1u32,
@@ -1067,18 +614,19 @@ impl SdmmcInner {
1067 _ => panic!("Invalid Bus Width"), 614 _ => panic!("Invalid Bus Width"),
1068 }; 615 };
1069 616
617 let ker_ck = T::kernel_clk();
1070 let (_bypass, clkdiv, new_clock) = clk_div(ker_ck, freq)?; 618 let (_bypass, clkdiv, new_clock) = clk_div(ker_ck, freq)?;
1071 619
1072 // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7 620 // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7
1073 // Section 55.5.8 621 // Section 55.5.8
1074 let sdmmc_bus_bandwidth = new_clock.0 * width_u32; 622 let sdmmc_bus_bandwidth = new_clock.0 * width_u32;
1075 assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32); 623 assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32);
1076 *clock = new_clock; 624 self.clock = new_clock;
1077 625
1078 // NOTE(unsafe) We have exclusive access to the regblock 626 // NOTE(unsafe) We have exclusive access to the regblock
1079 unsafe { 627 unsafe {
1080 // CPSMACT and DPSMACT must be 0 to set CLKDIV 628 // CPSMACT and DPSMACT must be 0 to set CLKDIV
1081 self.wait_idle(); 629 Self::wait_idle();
1082 regs.clkcr().modify(|w| { 630 regs.clkcr().modify(|w| {
1083 w.set_clkdiv(clkdiv); 631 w.set_clkdiv(clkdiv);
1084 #[cfg(sdmmc_v1)] 632 #[cfg(sdmmc_v1)]
@@ -1094,13 +642,7 @@ impl SdmmcInner {
1094 /// Attempt to set a new signalling mode. The selected 642 /// Attempt to set a new signalling mode. The selected
1095 /// signalling mode is returned. Expects the current clock 643 /// signalling mode is returned. Expects the current clock
1096 /// frequency to be > 12.5MHz. 644 /// frequency to be > 12.5MHz.
1097 async fn switch_signalling_mode<T: Instance, Dma: SdmmcDma<T>>( 645 async fn switch_signalling_mode(&mut self, signalling: Signalling) -> Result<Signalling, Error> {
1098 &self,
1099 signalling: Signalling,
1100 waker_reg: &AtomicWaker,
1101 data_transfer_timeout: u32,
1102 dma: &mut Dma,
1103 ) -> Result<Signalling, Error> {
1104 // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not 646 // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not
1105 // necessary" 647 // necessary"
1106 648
@@ -1117,17 +659,17 @@ impl SdmmcInner {
1117 let mut status = [0u32; 16]; 659 let mut status = [0u32; 16];
1118 660
1119 // Arm `OnDrop` after the buffer, so it will be dropped first 661 // Arm `OnDrop` after the buffer, so it will be dropped first
1120 let regs = self.0; 662 let regs = T::regs();
1121 let on_drop = OnDrop::new(|| unsafe { self.on_drop() }); 663 let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
1122 664
1123 unsafe { 665 unsafe {
1124 self.prepare_datapath_read(&mut status as *mut [u32; 16], 64, 6, data_transfer_timeout, dma); 666 self.prepare_datapath_read(&mut status, 64, 6);
1125 self.data_interrupts(true); 667 Self::data_interrupts(true);
1126 } 668 }
1127 self.cmd(Cmd::cmd6(set_function), true)?; // CMD6 669 self.cmd(Cmd::cmd6(set_function), true)?; // CMD6
1128 670
1129 let res = poll_fn(|cx| { 671 let res = poll_fn(|cx| {
1130 waker_reg.register(cx.waker()); 672 T::state().register(cx.waker());
1131 let status = unsafe { regs.star().read() }; 673 let status = unsafe { regs.star().read() };
1132 674
1133 if status.dcrcfail() { 675 if status.dcrcfail() {
@@ -1140,7 +682,7 @@ impl SdmmcInner {
1140 Poll::Pending 682 Poll::Pending
1141 }) 683 })
1142 .await; 684 .await;
1143 self.clear_interrupt_flags(); 685 Self::clear_interrupt_flags();
1144 686
1145 // Host is allowed to use the new functions at least 8 687 // Host is allowed to use the new functions at least 8
1146 // clocks after the end of the switch command 688 // clocks after the end of the switch command
@@ -1153,7 +695,7 @@ impl SdmmcInner {
1153 match res { 695 match res {
1154 Ok(_) => { 696 Ok(_) => {
1155 on_drop.defuse(); 697 on_drop.defuse();
1156 self.stop_datapath(); 698 Self::stop_datapath();
1157 699
1158 // Function Selection of Function Group 1 700 // Function Selection of Function Group 1
1159 let selection = (u32::from_be(status[4]) >> 24) & 0xF; 701 let selection = (u32::from_be(status[4]) >> 24) & 0xF;
@@ -1173,7 +715,7 @@ impl SdmmcInner {
1173 715
1174 /// Query the card status (CMD13, returns R1) 716 /// Query the card status (CMD13, returns R1)
1175 fn read_status(&self, card: &Card) -> Result<CardStatus, Error> { 717 fn read_status(&self, card: &Card) -> Result<CardStatus, Error> {
1176 let regs = self.0; 718 let regs = T::regs();
1177 let rca = card.rca; 719 let rca = card.rca;
1178 720
1179 self.cmd(Cmd::card_status(rca << 16), false)?; // CMD13 721 self.cmd(Cmd::card_status(rca << 16), false)?; // CMD13
@@ -1184,31 +726,27 @@ impl SdmmcInner {
1184 } 726 }
1185 727
1186 /// Reads the SD Status (ACMD13) 728 /// Reads the SD Status (ACMD13)
1187 async fn read_sd_status<T: Instance, Dma: SdmmcDma<T>>( 729 async fn read_sd_status(&mut self) -> Result<(), Error> {
1188 &self, 730 let card = self.card.as_mut().ok_or(Error::NoCard)?;
1189 card: &mut Card,
1190 waker_reg: &AtomicWaker,
1191 data_transfer_timeout: u32,
1192 dma: &mut Dma,
1193 ) -> Result<(), Error> {
1194 let rca = card.rca; 731 let rca = card.rca;
732
1195 self.cmd(Cmd::set_block_length(64), false)?; // CMD16 733 self.cmd(Cmd::set_block_length(64), false)?; // CMD16
1196 self.cmd(Cmd::app_cmd(rca << 16), false)?; // APP 734 self.cmd(Cmd::app_cmd(rca << 16), false)?; // APP
1197 735
1198 let mut status = [0u32; 16]; 736 let mut status = [0u32; 16];
1199 737
1200 // Arm `OnDrop` after the buffer, so it will be dropped first 738 // Arm `OnDrop` after the buffer, so it will be dropped first
1201 let regs = self.0; 739 let regs = T::regs();
1202 let on_drop = OnDrop::new(|| unsafe { self.on_drop() }); 740 let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
1203 741
1204 unsafe { 742 unsafe {
1205 self.prepare_datapath_read(&mut status as *mut [u32; 16], 64, 6, data_transfer_timeout, dma); 743 self.prepare_datapath_read(&mut status, 64, 6);
1206 self.data_interrupts(true); 744 Self::data_interrupts(true);
1207 } 745 }
1208 self.cmd(Cmd::card_status(0), true)?; 746 self.cmd(Cmd::card_status(0), true)?;
1209 747
1210 let res = poll_fn(|cx| { 748 let res = poll_fn(|cx| {
1211 waker_reg.register(cx.waker()); 749 T::state().register(cx.waker());
1212 let status = unsafe { regs.star().read() }; 750 let status = unsafe { regs.star().read() };
1213 751
1214 if status.dcrcfail() { 752 if status.dcrcfail() {
@@ -1221,16 +759,16 @@ impl SdmmcInner {
1221 Poll::Pending 759 Poll::Pending
1222 }) 760 })
1223 .await; 761 .await;
1224 self.clear_interrupt_flags(); 762 Self::clear_interrupt_flags();
1225 763
1226 if res.is_ok() { 764 if res.is_ok() {
1227 on_drop.defuse(); 765 on_drop.defuse();
1228 self.stop_datapath(); 766 Self::stop_datapath();
1229 767
1230 for byte in status.iter_mut() { 768 for byte in status.iter_mut() {
1231 *byte = u32::from_be(*byte); 769 *byte = u32::from_be(*byte);
1232 } 770 }
1233 card.status = status.into(); 771 self.card.as_mut().unwrap().status = status.into();
1234 } 772 }
1235 res 773 res
1236 } 774 }
@@ -1252,8 +790,8 @@ impl SdmmcInner {
1252 790
1253 /// Clear flags in interrupt clear register 791 /// Clear flags in interrupt clear register
1254 #[inline(always)] 792 #[inline(always)]
1255 fn clear_interrupt_flags(&self) { 793 fn clear_interrupt_flags() {
1256 let regs = self.0; 794 let regs = T::regs();
1257 // NOTE(unsafe) Atomic write 795 // NOTE(unsafe) Atomic write
1258 unsafe { 796 unsafe {
1259 regs.icr().write(|w| { 797 regs.icr().write(|w| {
@@ -1287,8 +825,8 @@ impl SdmmcInner {
1287 825
1288 /// Enables the interrupts for data transfer 826 /// Enables the interrupts for data transfer
1289 #[inline(always)] 827 #[inline(always)]
1290 fn data_interrupts(&self, enable: bool) { 828 fn data_interrupts(enable: bool) {
1291 let regs = self.0; 829 let regs = T::regs();
1292 // NOTE(unsafe) Atomic write 830 // NOTE(unsafe) Atomic write
1293 unsafe { 831 unsafe {
1294 regs.maskr().write(|w| { 832 regs.maskr().write(|w| {
@@ -1302,13 +840,7 @@ impl SdmmcInner {
1302 } 840 }
1303 } 841 }
1304 842
1305 async fn get_scr<T: Instance, Dma: SdmmcDma<T>>( 843 async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> {
1306 &self,
1307 card: &mut Card,
1308 waker_reg: &AtomicWaker,
1309 data_transfer_timeout: u32,
1310 dma: &mut Dma,
1311 ) -> Result<(), Error> {
1312 // Read the the 64-bit SCR register 844 // Read the the 64-bit SCR register
1313 self.cmd(Cmd::set_block_length(8), false)?; // CMD16 845 self.cmd(Cmd::set_block_length(8), false)?; // CMD16
1314 self.cmd(Cmd::app_cmd(card.rca << 16), false)?; 846 self.cmd(Cmd::app_cmd(card.rca << 16), false)?;
@@ -1316,17 +848,17 @@ impl SdmmcInner {
1316 let mut scr = [0u32; 2]; 848 let mut scr = [0u32; 2];
1317 849
1318 // Arm `OnDrop` after the buffer, so it will be dropped first 850 // Arm `OnDrop` after the buffer, so it will be dropped first
1319 let regs = self.0; 851 let regs = T::regs();
1320 let on_drop = OnDrop::new(move || unsafe { self.on_drop() }); 852 let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
1321 853
1322 unsafe { 854 unsafe {
1323 self.prepare_datapath_read(&mut scr as *mut [u32], 8, 3, data_transfer_timeout, dma); 855 self.prepare_datapath_read(&mut scr[..], 8, 3);
1324 self.data_interrupts(true); 856 Self::data_interrupts(true);
1325 } 857 }
1326 self.cmd(Cmd::cmd51(), true)?; 858 self.cmd(Cmd::cmd51(), true)?;
1327 859
1328 let res = poll_fn(|cx| { 860 let res = poll_fn(|cx| {
1329 waker_reg.register(cx.waker()); 861 T::state().register(cx.waker());
1330 let status = unsafe { regs.star().read() }; 862 let status = unsafe { regs.star().read() };
1331 863
1332 if status.dcrcfail() { 864 if status.dcrcfail() {
@@ -1339,11 +871,11 @@ impl SdmmcInner {
1339 Poll::Pending 871 Poll::Pending
1340 }) 872 })
1341 .await; 873 .await;
1342 self.clear_interrupt_flags(); 874 Self::clear_interrupt_flags();
1343 875
1344 if res.is_ok() { 876 if res.is_ok() {
1345 on_drop.defuse(); 877 on_drop.defuse();
1346 self.stop_datapath(); 878 Self::stop_datapath();
1347 879
1348 unsafe { 880 unsafe {
1349 let scr_bytes = &*(&scr as *const [u32; 2] as *const [u8; 8]); 881 let scr_bytes = &*(&scr as *const [u32; 2] as *const [u8; 8]);
@@ -1356,13 +888,13 @@ impl SdmmcInner {
1356 /// Send command to card 888 /// Send command to card
1357 #[allow(unused_variables)] 889 #[allow(unused_variables)]
1358 fn cmd(&self, cmd: Cmd, data: bool) -> Result<(), Error> { 890 fn cmd(&self, cmd: Cmd, data: bool) -> Result<(), Error> {
1359 let regs = self.0; 891 let regs = T::regs();
1360 892
1361 self.clear_interrupt_flags(); 893 Self::clear_interrupt_flags();
1362 // NOTE(safety) Atomic operations 894 // NOTE(safety) Atomic operations
1363 unsafe { 895 unsafe {
1364 // CP state machine must be idle 896 // CP state machine must be idle
1365 while self.cmd_active() {} 897 while Self::cmd_active() {}
1366 898
1367 // Command arg 899 // Command arg
1368 regs.argr().write(|w| w.set_cmdarg(cmd.arg)); 900 regs.argr().write(|w| w.set_cmdarg(cmd.arg));
@@ -1411,13 +943,13 @@ impl SdmmcInner {
1411 /// # Safety 943 /// # Safety
1412 /// 944 ///
1413 /// Ensure that `regs` has exclusive access to the regblocks 945 /// Ensure that `regs` has exclusive access to the regblocks
1414 unsafe fn on_drop(&self) { 946 unsafe fn on_drop() {
1415 let regs = self.0; 947 let regs = T::regs();
1416 if self.data_active() { 948 if Self::data_active() {
1417 self.clear_interrupt_flags(); 949 Self::clear_interrupt_flags();
1418 // Send abort 950 // Send abort
1419 // CP state machine must be idle 951 // CP state machine must be idle
1420 while self.cmd_active() {} 952 while Self::cmd_active() {}
1421 953
1422 // Command arg 954 // Command arg
1423 regs.argr().write(|w| w.set_cmdarg(0)); 955 regs.argr().write(|w| w.set_cmdarg(0));
@@ -1437,11 +969,320 @@ impl SdmmcInner {
1437 }); 969 });
1438 970
1439 // Wait for the abort 971 // Wait for the abort
1440 while self.data_active() {} 972 while Self::data_active() {}
1441 } 973 }
1442 self.data_interrupts(false); 974 Self::data_interrupts(false);
1443 self.clear_interrupt_flags(); 975 Self::clear_interrupt_flags();
1444 self.stop_datapath(); 976 Self::stop_datapath();
977 }
978
979 /// Initializes card (if present) and sets the bus at the
980 /// specified frequency.
981 pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> {
982 let regs = T::regs();
983 let ker_ck = T::kernel_clk();
984
985 let bus_width = match self.d3.is_some() {
986 true => BusWidth::Four,
987 false => BusWidth::One,
988 };
989
990 // NOTE(unsafe) We have exclusive access to the peripheral
991 unsafe {
992 // While the SD/SDIO card or eMMC is in identification mode,
993 // the SDMMC_CK frequency must be no more than 400 kHz.
994 let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
995 self.clock = init_clock;
996
997 // CPSMACT and DPSMACT must be 0 to set WIDBUS
998 Self::wait_idle();
999
1000 regs.clkcr().modify(|w| {
1001 w.set_widbus(0);
1002 w.set_clkdiv(clkdiv);
1003 #[cfg(sdmmc_v1)]
1004 w.set_bypass(_bypass);
1005 });
1006
1007 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
1008 self.cmd(Cmd::idle(), false)?;
1009
1010 // Check if cards supports CMD8 (with pattern)
1011 self.cmd(Cmd::hs_send_ext_csd(0x1AA), false)?;
1012 let r1 = regs.respr(0).read().cardstatus();
1013
1014 let mut card = if r1 == 0x1AA {
1015 // Card echoed back the pattern. Must be at least v2
1016 Card::default()
1017 } else {
1018 return Err(Error::UnsupportedCardVersion);
1019 };
1020
1021 let ocr = loop {
1022 // Signal that next command is a app command
1023 self.cmd(Cmd::app_cmd(0), false)?; // CMD55
1024
1025 let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32
1026 | CmdAppOper::HIGH_CAPACITY as u32
1027 | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32;
1028
1029 // Initialize card
1030 match self.cmd(Cmd::app_op_cmd(arg), false) {
1031 // ACMD41
1032 Ok(_) => (),
1033 Err(Error::Crc) => (),
1034 Err(err) => return Err(err),
1035 }
1036 let ocr: OCR = regs.respr(0).read().cardstatus().into();
1037 if !ocr.is_busy() {
1038 // Power up done
1039 break ocr;
1040 }
1041 };
1042
1043 if ocr.high_capacity() {
1044 // Card is SDHC or SDXC or SDUC
1045 card.card_type = CardCapacity::SDHC;
1046 } else {
1047 card.card_type = CardCapacity::SDSC;
1048 }
1049 card.ocr = ocr;
1050
1051 self.cmd(Cmd::all_send_cid(), false)?; // CMD2
1052 let cid0 = regs.respr(0).read().cardstatus() as u128;
1053 let cid1 = regs.respr(1).read().cardstatus() as u128;
1054 let cid2 = regs.respr(2).read().cardstatus() as u128;
1055 let cid3 = regs.respr(3).read().cardstatus() as u128;
1056 let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
1057 card.cid = cid.into();
1058
1059 self.cmd(Cmd::send_rel_addr(), false)?;
1060 card.rca = regs.respr(0).read().cardstatus() >> 16;
1061
1062 self.cmd(Cmd::send_csd(card.rca << 16), false)?;
1063 let csd0 = regs.respr(0).read().cardstatus() as u128;
1064 let csd1 = regs.respr(1).read().cardstatus() as u128;
1065 let csd2 = regs.respr(2).read().cardstatus() as u128;
1066 let csd3 = regs.respr(3).read().cardstatus() as u128;
1067 let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
1068 card.csd = csd.into();
1069
1070 self.select_card(Some(&card))?;
1071
1072 self.get_scr(&mut card).await?;
1073
1074 // Set bus width
1075 let (width, acmd_arg) = match bus_width {
1076 BusWidth::Eight => unimplemented!(),
1077 BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2),
1078 _ => (BusWidth::One, 0),
1079 };
1080 self.cmd(Cmd::app_cmd(card.rca << 16), false)?;
1081 self.cmd(Cmd::cmd6(acmd_arg), false)?;
1082
1083 // CPSMACT and DPSMACT must be 0 to set WIDBUS
1084 Self::wait_idle();
1085
1086 regs.clkcr().modify(|w| {
1087 w.set_widbus(match width {
1088 BusWidth::One => 0,
1089 BusWidth::Four => 1,
1090 BusWidth::Eight => 2,
1091 _ => panic!("Invalid Bus Width"),
1092 })
1093 });
1094
1095 // Set Clock
1096 if freq.0 <= 25_000_000 {
1097 // Final clock frequency
1098 self.clkcr_set_clkdiv(freq.0, width)?;
1099 } else {
1100 // Switch to max clock for SDR12
1101 self.clkcr_set_clkdiv(25_000_000, width)?;
1102 }
1103
1104 self.card = Some(card);
1105
1106 // Read status
1107 self.read_sd_status().await?;
1108
1109 if freq.0 > 25_000_000 {
1110 // Switch to SDR25
1111 self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?;
1112
1113 if self.signalling == Signalling::SDR25 {
1114 // Set final clock frequency
1115 self.clkcr_set_clkdiv(freq.0, width)?;
1116
1117 if self.read_status(&card)?.state() != CurrentState::Transfer {
1118 return Err(Error::SignalingSwitchFailed);
1119 }
1120 }
1121 }
1122 // Read status after signalling change
1123 self.read_sd_status().await?;
1124 }
1125
1126 Ok(())
1127 }
1128
1129 #[inline(always)]
1130 pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> {
1131 let card_capacity = self.card()?.card_type;
1132
1133 // NOTE(unsafe) DataBlock uses align 4
1134 let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) };
1135
1136 // Always read 1 block of 512 bytes
1137 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
1138 let address = match card_capacity {
1139 CardCapacity::SDSC => block_idx * 512,
1140 _ => block_idx,
1141 };
1142 self.cmd(Cmd::set_block_length(512), false)?; // CMD16
1143
1144 let regs = T::regs();
1145 let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
1146
1147 unsafe {
1148 self.prepare_datapath_read(buffer, 512, 9);
1149 Self::data_interrupts(true);
1150 }
1151 self.cmd(Cmd::read_single_block(address), true)?;
1152
1153 let res = poll_fn(|cx| {
1154 T::state().register(cx.waker());
1155 let status = unsafe { regs.star().read() };
1156
1157 if status.dcrcfail() {
1158 return Poll::Ready(Err(Error::Crc));
1159 } else if status.dtimeout() {
1160 return Poll::Ready(Err(Error::Timeout));
1161 } else if status.dataend() {
1162 return Poll::Ready(Ok(()));
1163 }
1164 Poll::Pending
1165 })
1166 .await;
1167 Self::clear_interrupt_flags();
1168
1169 if res.is_ok() {
1170 on_drop.defuse();
1171 Self::stop_datapath();
1172 }
1173 res
1174 }
1175
1176 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> {
1177 let card = self.card.as_mut().ok_or(Error::NoCard)?;
1178
1179 // NOTE(unsafe) DataBlock uses align 4
1180 let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) };
1181
1182 // Always read 1 block of 512 bytes
1183 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
1184 let address = match card.card_type {
1185 CardCapacity::SDSC => block_idx * 512,
1186 _ => block_idx,
1187 };
1188 self.cmd(Cmd::set_block_length(512), false)?; // CMD16
1189
1190 let regs = T::regs();
1191 let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
1192
1193 // sdmmc_v1 uses different cmd/dma order than v2, but only for writes
1194 #[cfg(sdmmc_v1)]
1195 self.cmd(Cmd::write_single_block(address), true)?;
1196
1197 unsafe {
1198 self.prepare_datapath_write(buffer as *const [u32; 128], 512, 9);
1199 Self::data_interrupts(true);
1200 }
1201
1202 #[cfg(sdmmc_v2)]
1203 self.cmd(Cmd::write_single_block(address), true)?;
1204
1205 let res = poll_fn(|cx| {
1206 T::state().register(cx.waker());
1207 let status = unsafe { regs.star().read() };
1208
1209 if status.dcrcfail() {
1210 return Poll::Ready(Err(Error::Crc));
1211 } else if status.dtimeout() {
1212 return Poll::Ready(Err(Error::Timeout));
1213 } else if status.dataend() {
1214 return Poll::Ready(Ok(()));
1215 }
1216 Poll::Pending
1217 })
1218 .await;
1219 Self::clear_interrupt_flags();
1220
1221 match res {
1222 Ok(_) => {
1223 on_drop.defuse();
1224 Self::stop_datapath();
1225
1226 // TODO: Make this configurable
1227 let mut timeout: u32 = 0x00FF_FFFF;
1228
1229 // Try to read card status (ACMD13)
1230 while timeout > 0 {
1231 match self.read_sd_status().await {
1232 Ok(_) => return Ok(()),
1233 Err(Error::Timeout) => (), // Try again
1234 Err(e) => return Err(e),
1235 }
1236 timeout -= 1;
1237 }
1238 Err(Error::SoftwareTimeout)
1239 }
1240 Err(e) => Err(e),
1241 }
1242 }
1243
1244 /// Get a reference to the initialized card
1245 ///
1246 /// # Errors
1247 ///
1248 /// Returns Error::NoCard if [`init_card`](#method.init_card)
1249 /// has not previously succeeded
1250 #[inline(always)]
1251 pub fn card(&self) -> Result<&Card, Error> {
1252 self.card.as_ref().ok_or(Error::NoCard)
1253 }
1254
1255 /// Get the current SDMMC bus clock
1256 pub fn clock(&self) -> Hertz {
1257 self.clock
1258 }
1259
1260 #[inline(always)]
1261 fn on_interrupt(_: *mut ()) {
1262 Self::data_interrupts(false);
1263 T::state().wake();
1264 }
1265}
1266
1267impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> {
1268 fn drop(&mut self) {
1269 self.irq.disable();
1270 unsafe { Self::on_drop() };
1271
1272 critical_section::with(|_| unsafe {
1273 self.clk.set_as_disconnected();
1274 self.cmd.set_as_disconnected();
1275 self.d0.set_as_disconnected();
1276 if let Some(x) = &mut self.d1 {
1277 x.set_as_disconnected();
1278 }
1279 if let Some(x) = &mut self.d2 {
1280 x.set_as_disconnected();
1281 }
1282 if let Some(x) = &mut self.d3 {
1283 x.set_as_disconnected();
1284 }
1285 });
1445 } 1286 }
1446} 1287}
1447 1288
@@ -1540,7 +1381,7 @@ pub(crate) mod sealed {
1540 pub trait Instance { 1381 pub trait Instance {
1541 type Interrupt: Interrupt; 1382 type Interrupt: Interrupt;
1542 1383
1543 fn inner() -> SdmmcInner; 1384 fn regs() -> RegBlock;
1544 fn state() -> &'static AtomicWaker; 1385 fn state() -> &'static AtomicWaker;
1545 fn kernel_clk() -> Hertz; 1386 fn kernel_clk() -> Hertz;
1546 } 1387 }
@@ -1560,15 +1401,14 @@ pin_trait!(D5Pin, Instance);
1560pin_trait!(D6Pin, Instance); 1401pin_trait!(D6Pin, Instance);
1561pin_trait!(D7Pin, Instance); 1402pin_trait!(D7Pin, Instance);
1562 1403
1563cfg_if::cfg_if! { 1404#[cfg(sdmmc_v1)]
1564 if #[cfg(sdmmc_v1)] { 1405dma_trait!(SdmmcDma, Instance);
1565 dma_trait!(SdmmcDma, Instance); 1406
1566 } else if #[cfg(sdmmc_v2)] { 1407// SDMMCv2 uses internal DMA
1567 // SDMMCv2 uses internal DMA 1408#[cfg(sdmmc_v2)]
1568 pub trait SdmmcDma<T: Instance> {} 1409pub trait SdmmcDma<T: Instance> {}
1569 impl<T: Instance> SdmmcDma<T> for NoDma {} 1410#[cfg(sdmmc_v2)]
1570 } 1411impl<T: Instance> SdmmcDma<T> for NoDma {}
1571}
1572 1412
1573cfg_if::cfg_if! { 1413cfg_if::cfg_if! {
1574 // TODO, these could not be implemented, because required clocks are not exposed in RCC: 1414 // TODO, these could not be implemented, because required clocks are not exposed in RCC:
@@ -1630,9 +1470,8 @@ foreach_peripheral!(
1630 impl sealed::Instance for peripherals::$inst { 1470 impl sealed::Instance for peripherals::$inst {
1631 type Interrupt = crate::interrupt::$inst; 1471 type Interrupt = crate::interrupt::$inst;
1632 1472
1633 fn inner() -> SdmmcInner { 1473 fn regs() -> RegBlock {
1634 const INNER: SdmmcInner = SdmmcInner(crate::pac::$inst); 1474 crate::pac::$inst
1635 INNER
1636 } 1475 }
1637 1476
1638 fn state() -> &'static ::embassy_sync::waitqueue::AtomicWaker { 1477 fn state() -> &'static ::embassy_sync::waitqueue::AtomicWaker {
diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs
index ebdfdb22d..eeecbd321 100644
--- a/examples/stm32f4/src/bin/sdmmc.rs
+++ b/examples/stm32f4/src/bin/sdmmc.rs
@@ -39,7 +39,18 @@ async fn main(_spawner: Spawner) {
39 // Should print 400kHz for initialization 39 // Should print 400kHz for initialization
40 info!("Configured clock: {}", sdmmc.clock().0); 40 info!("Configured clock: {}", sdmmc.clock().0);
41 41
42 unwrap!(sdmmc.init_card(mhz(48)).await); 42 let mut err = None;
43 loop {
44 match sdmmc.init_card(mhz(24)).await {
45 Ok(_) => break,
46 Err(e) => {
47 if err != Some(e) {
48 info!("waiting for card error, retrying: {:?}", e);
49 err = Some(e);
50 }
51 }
52 }
53 }
43 54
44 let card = unwrap!(sdmmc.card()); 55 let card = unwrap!(sdmmc.card());
45 56
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index 8b70a1015..3047c34ce 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[features] 7[features]
8stm32f103c8 = ["embassy-stm32/stm32f103c8"] # Blue Pill 8stm32f103c8 = ["embassy-stm32/stm32f103c8"] # Blue Pill
9stm32f429zi = ["embassy-stm32/stm32f429zi"] # Nucleo 9stm32f429zi = ["embassy-stm32/stm32f429zi", "sdmmc"] # Nucleo
10stm32g071rb = ["embassy-stm32/stm32g071rb"] # Nucleo 10stm32g071rb = ["embassy-stm32/stm32g071rb"] # Nucleo
11stm32c031c6 = ["embassy-stm32/stm32c031c6"] # Nucleo 11stm32c031c6 = ["embassy-stm32/stm32c031c6"] # Nucleo
12stm32g491re = ["embassy-stm32/stm32g491re"] # Nucleo 12stm32g491re = ["embassy-stm32/stm32g491re"] # Nucleo
@@ -15,6 +15,8 @@ stm32wb55rg = ["embassy-stm32/stm32wb55rg"] # Nucleo
15stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo 15stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo
16stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board 16stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board
17 17
18sdmmc = []
19
18[dependencies] 20[dependencies]
19embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 21embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
20embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 22embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
@@ -31,6 +33,45 @@ embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" }
31embedded-hal-async = { version = "=0.2.0-alpha.1" } 33embedded-hal-async = { version = "=0.2.0-alpha.1" }
32panic-probe = { version = "0.3.0", features = ["print-defmt"] } 34panic-probe = { version = "0.3.0", features = ["print-defmt"] }
33 35
36# BEGIN TESTS
37# Generated by gen_test.py. DO NOT EDIT.
38[[bin]]
39name = "gpio"
40path = "src/bin/gpio.rs"
41required-features = []
42
43[[bin]]
44name = "sdmmc"
45path = "src/bin/sdmmc.rs"
46required-features = [ "sdmmc",]
47
48[[bin]]
49name = "spi"
50path = "src/bin/spi.rs"
51required-features = []
52
53[[bin]]
54name = "spi_dma"
55path = "src/bin/spi_dma.rs"
56required-features = []
57
58[[bin]]
59name = "timer"
60path = "src/bin/timer.rs"
61required-features = []
62
63[[bin]]
64name = "usart"
65path = "src/bin/usart.rs"
66required-features = []
67
68[[bin]]
69name = "usart_dma"
70path = "src/bin/usart_dma.rs"
71required-features = []
72
73# END TESTS
74
34[profile.dev] 75[profile.dev]
35debug = 2 76debug = 2
36debug-assertions = true 77debug-assertions = true
diff --git a/tests/stm32/gen_test.py b/tests/stm32/gen_test.py
new file mode 100644
index 000000000..8ff156c0e
--- /dev/null
+++ b/tests/stm32/gen_test.py
@@ -0,0 +1,44 @@
1import os
2import toml
3from glob import glob
4
5abspath = os.path.abspath(__file__)
6dname = os.path.dirname(abspath)
7os.chdir(dname)
8
9# ======= load test list
10tests = {}
11for f in sorted(glob('./src/bin/*.rs')):
12 name = os.path.splitext(os.path.basename(f))[0]
13 features = []
14 with open(f, 'r') as f:
15 for line in f:
16 if line.startswith('// required-features:'):
17 features = line.split(':', 2)[1].strip().split(',')
18
19 tests[name] = features
20
21# ========= Update Cargo.toml
22
23things = {
24 'bin': [
25 {
26 'name': f'{name}',
27 'path': f'src/bin/{name}.rs',
28 'required-features': features,
29 }
30 for name, features in tests.items()
31 ]
32}
33
34SEPARATOR_START = '# BEGIN TESTS\n'
35SEPARATOR_END = '# END TESTS\n'
36HELP = '# Generated by gen_test.py. DO NOT EDIT.\n'
37with open('Cargo.toml', 'r') as f:
38 data = f.read()
39before, data = data.split(SEPARATOR_START, maxsplit=1)
40_, after = data.split(SEPARATOR_END, maxsplit=1)
41data = before + SEPARATOR_START + HELP + \
42 toml.dumps(things) + SEPARATOR_END + after
43with open('Cargo.toml', 'w') as f:
44 f.write(data)
diff --git a/tests/stm32/src/bin/sdmmc.rs b/tests/stm32/src/bin/sdmmc.rs
new file mode 100644
index 000000000..c4e50cb4a
--- /dev/null
+++ b/tests/stm32/src/bin/sdmmc.rs
@@ -0,0 +1,148 @@
1// required-features: sdmmc
2#![no_std]
3#![no_main]
4#![feature(type_alias_impl_trait)]
5
6use defmt::{assert_eq, *};
7use embassy_executor::Spawner;
8use embassy_stm32::sdmmc::{DataBlock, Sdmmc};
9use embassy_stm32::time::mhz;
10use embassy_stm32::{interrupt, Config};
11use {defmt_rtt as _, panic_probe as _};
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 info!("Hello World!");
16
17 let mut config = Config::default();
18 config.rcc.sys_ck = Some(mhz(48));
19 config.rcc.pll48 = true;
20 let p = embassy_stm32::init(config);
21
22 #[cfg(feature = "stm32f429zi")]
23 let (mut sdmmc, mut irq, mut dma, mut clk, mut cmd, mut d0, mut d1, mut d2, mut d3) = (
24 p.SDIO,
25 interrupt::take!(SDIO),
26 p.DMA2_CH3,
27 p.PC12,
28 p.PD2,
29 p.PC8,
30 p.PC9,
31 p.PC10,
32 p.PC11,
33 );
34
35 // Arbitrary block index
36 let block_idx = 16;
37
38 let mut pattern1 = DataBlock([0u8; 512]);
39 let mut pattern2 = DataBlock([0u8; 512]);
40 for i in 0..512 {
41 pattern1[i] = i as u8;
42 pattern2[i] = !i as u8;
43 }
44
45 let mut block = DataBlock([0u8; 512]);
46
47 // ======== Try 4bit. ==============
48 info!("initializing in 4-bit mode...");
49 let mut s = Sdmmc::new_4bit(
50 &mut sdmmc,
51 &mut irq,
52 &mut dma,
53 &mut clk,
54 &mut cmd,
55 &mut d0,
56 &mut d1,
57 &mut d2,
58 &mut d3,
59 Default::default(),
60 );
61
62 let mut err = None;
63 loop {
64 match s.init_card(mhz(24)).await {
65 Ok(_) => break,
66 Err(e) => {
67 if err != Some(e) {
68 info!("waiting for card: {:?}", e);
69 err = Some(e);
70 }
71 }
72 }
73 }
74
75 let card = unwrap!(s.card());
76
77 info!("Card: {:#?}", Debug2Format(card));
78 info!("Clock: {}", s.clock());
79
80 info!("writing pattern1...");
81 s.write_block(block_idx, &pattern1).await.unwrap();
82
83 info!("reading...");
84 s.read_block(block_idx, &mut block).await.unwrap();
85 assert_eq!(block, pattern1);
86
87 info!("writing pattern2...");
88 s.write_block(block_idx, &pattern2).await.unwrap();
89
90 info!("reading...");
91 s.read_block(block_idx, &mut block).await.unwrap();
92 assert_eq!(block, pattern2);
93
94 drop(s);
95
96 // ======== Try 1bit. ==============
97 info!("initializing in 1-bit mode...");
98 let mut s = Sdmmc::new_1bit(
99 &mut sdmmc,
100 &mut irq,
101 &mut dma,
102 &mut clk,
103 &mut cmd,
104 &mut d0,
105 Default::default(),
106 );
107
108 let mut err = None;
109 loop {
110 match s.init_card(mhz(24)).await {
111 Ok(_) => break,
112 Err(e) => {
113 if err != Some(e) {
114 info!("waiting for card: {:?}", e);
115 err = Some(e);
116 }
117 }
118 }
119 }
120
121 let card = unwrap!(s.card());
122
123 info!("Card: {:#?}", Debug2Format(card));
124 info!("Clock: {}", s.clock());
125
126 info!("reading pattern2 written in 4bit mode...");
127 s.read_block(block_idx, &mut block).await.unwrap();
128 assert_eq!(block, pattern2);
129
130 info!("writing pattern1...");
131 s.write_block(block_idx, &pattern1).await.unwrap();
132
133 info!("reading...");
134 s.read_block(block_idx, &mut block).await.unwrap();
135 assert_eq!(block, pattern1);
136
137 info!("writing pattern2...");
138 s.write_block(block_idx, &pattern2).await.unwrap();
139
140 info!("reading...");
141 s.read_block(block_idx, &mut block).await.unwrap();
142 assert_eq!(block, pattern2);
143
144 drop(s);
145
146 info!("Test OK");
147 cortex_m::asm::bkpt();
148}