aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorchemicstry <[email protected]>2022-03-15 19:58:19 +0200
committerchemicstry <[email protected]>2022-03-15 19:58:19 +0200
commit2d224cf6a072bf9f12c56147c9a0339302ef47ce (patch)
tree699aa80ee446827ba6addfd99f63b3be4347ef0e
parentda9c0efaad594b48cfcdf641d353133d14cf98fe (diff)
Update
-rw-r--r--.vscode/settings.json6
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs1450
-rw-r--r--embassy-stm32/src/sdmmc/v1.rs1
-rw-r--r--embassy-stm32/src/sdmmc/v2.rs1374
m---------stm32-data0
5 files changed, 1449 insertions, 1382 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 79433a7c9..b4047399c 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -16,16 +16,16 @@
16 //"embassy-net/medium-ethernet", 16 //"embassy-net/medium-ethernet",
17 //"embassy-net/tcp", 17 //"embassy-net/tcp",
18 //"embassy-net/pool-16", 18 //"embassy-net/pool-16",
19 "nightly", 19 //"nightly",
20 ], 20 ],
21 "rust-analyzer.linkedProjects": [ 21 "rust-analyzer.linkedProjects": [
22 // Declare for the target you wish to develop 22 // Declare for the target you wish to develop
23 "examples/nrf/Cargo.toml", 23 // "examples/nrf/Cargo.toml",
24 // "examples/rp/Cargo.toml", 24 // "examples/rp/Cargo.toml",
25 // "examples/std/Cargo.toml", 25 // "examples/std/Cargo.toml",
26 // "examples/stm32f0/Cargo.toml", 26 // "examples/stm32f0/Cargo.toml",
27 // "examples/stm32f1/Cargo.toml", 27 // "examples/stm32f1/Cargo.toml",
28 // "examples/stm32f4/Cargo.toml", 28 "examples/stm32f4/Cargo.toml",
29 // "examples/stm32f7/Cargo.toml", 29 // "examples/stm32f7/Cargo.toml",
30 // "examples/stm32g0/Cargo.toml", 30 // "examples/stm32g0/Cargo.toml",
31 // "examples/stm32g4/Cargo.toml", 31 // "examples/stm32g4/Cargo.toml",
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index 087cb4c40..7bd809810 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -1,7 +1,1449 @@
1#![macro_use] 1#![macro_use]
2 2
3#[cfg_attr(sdmmc_v1, path = "v1.rs")] 3use core::default::Default;
4#[cfg_attr(sdmmc_v2, path = "v2.rs")] 4use core::marker::PhantomData;
5mod _version; 5use core::task::Poll;
6 6
7pub use _version::*; 7use embassy::interrupt::InterruptExt;
8use embassy::util::Unborrow;
9use embassy::waitqueue::AtomicWaker;
10use embassy_hal_common::drop::OnDrop;
11use embassy_hal_common::unborrow;
12use futures::future::poll_fn;
13use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR};
14
15use crate::dma::NoDma;
16use crate::gpio::sealed::AFType;
17use crate::gpio::{Pull, Speed};
18use crate::interrupt::Interrupt;
19use crate::pac::sdmmc::Sdmmc as RegBlock;
20use crate::peripherals;
21use crate::time::Hertz;
22
23/// The signalling scheme used on the SDMMC bus
24#[non_exhaustive]
25#[derive(Debug, Copy, Clone, PartialEq, Eq)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
27pub enum Signalling {
28 SDR12,
29 SDR25,
30 SDR50,
31 SDR104,
32 DDR50,
33}
34
35impl Default for Signalling {
36 fn default() -> Self {
37 Signalling::SDR12
38 }
39}
40
41#[repr(align(4))]
42pub struct DataBlock([u8; 512]);
43
44/// Errors
45#[non_exhaustive]
46#[derive(Debug, Copy, Clone)]
47#[cfg_attr(feature = "defmt", derive(defmt::Format))]
48pub enum Error {
49 Timeout,
50 SoftwareTimeout,
51 UnsupportedCardVersion,
52 UnsupportedCardType,
53 Crc,
54 DataCrcFail,
55 RxOverFlow,
56 NoCard,
57 BadClock,
58 SignalingSwitchFailed,
59 PeripheralBusy,
60}
61
62/// A SD command
63struct Cmd {
64 cmd: u8,
65 arg: u32,
66 resp: Response,
67}
68
69#[derive(Clone, Copy, Debug, Default)]
70/// SD Card
71pub struct Card {
72 /// The type of this card
73 pub card_type: CardCapacity,
74 /// Operation Conditions Register
75 pub ocr: OCR,
76 /// Relative Card Address
77 pub rca: u32,
78 /// Card ID
79 pub cid: CID,
80 /// Card Specific Data
81 pub csd: CSD,
82 /// SD CARD Configuration Register
83 pub scr: SCR,
84 /// SD Status
85 pub status: SDStatus,
86}
87impl Card {
88 /// Size in bytes
89 pub fn size(&self) -> u64 {
90 // SDHC / SDXC / SDUC
91 u64::from(self.csd.block_count()) * 512
92 }
93}
94
95/// Indicates transfer direction
96enum Dir {
97 CardToHost,
98 HostToCard,
99}
100
101#[repr(u8)]
102enum PowerCtrl {
103 Off = 0b00,
104 On = 0b11,
105}
106
107#[repr(u32)]
108#[allow(dead_code)]
109#[allow(non_camel_case_types)]
110enum CmdAppOper {
111 VOLTAGE_WINDOW_SD = 0x8010_0000,
112 HIGH_CAPACITY = 0x4000_0000,
113 SDMMC_STD_CAPACITY = 0x0000_0000,
114 SDMMC_CHECK_PATTERN = 0x0000_01AA,
115 SD_SWITCH_1_8V_CAPACITY = 0x0100_0000,
116}
117
118#[derive(Eq, PartialEq, Copy, Clone)]
119enum Response {
120 None = 0,
121 Short = 1,
122 Long = 3,
123}
124
125cfg_if::cfg_if! {
126 if #[cfg(sdmmc_v1)] {
127 /// Calculate clock divisor. Returns a SDMMC_CK less than or equal to
128 /// `sdmmc_ck` in Hertz.
129 ///
130 /// Returns `(clk_div, clk_f)`, where `clk_div` is the divisor register
131 /// value and `clk_f` is the resulting new clock frequency.
132 fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(u8, Hertz), Error> {
133 let clk_div = match ker_ck.0 / sdmmc_ck {
134 0 | 1 => Ok(0),
135 x @ 2..=258 => {
136 Ok((x - 2) as u8)
137 }
138 _ => Err(Error::BadClock),
139 }?;
140
141 let clk_f = Hertz(ker_ck.0 / (clk_div as u32 + 2));
142 Ok((clk_div, clk_f))
143 }
144 } else if #[cfg(sdmmc_v2)] {
145 /// Calculate clock divisor. Returns a SDMMC_CK less than or equal to
146 /// `sdmmc_ck` in Hertz.
147 ///
148 /// Returns `(clk_div, clk_f)`, where `clk_div` is the divisor register
149 /// value and `clk_f` is the resulting new clock frequency.
150 fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(u16, Hertz), Error> {
151 match (ker_ck.0 + sdmmc_ck - 1) / sdmmc_ck {
152 0 | 1 => Ok((0, ker_ck)),
153 x @ 2..=2046 => {
154 let clk_div = ((x + 1) / 2) as u16;
155 let clk = Hertz(ker_ck.0 / (clk_div as u32 * 2));
156
157 Ok((clk_div, clk))
158 }
159 _ => Err(Error::BadClock),
160 }
161 }
162 }
163}
164
165/// SDMMC configuration
166///
167/// You should probably change the default clock values to match your configuration
168///
169/// Default values:
170/// hclk = 400_000_000 Hz
171/// kernel_clk: 100_000_000 Hz
172/// data_transfer_timeout: 5_000_000
173#[non_exhaustive]
174pub struct Config {
175 /// AHB clock
176 pub hclk: Hertz,
177 /// SDMMC kernel clock
178 pub kernel_clk: Hertz,
179 /// The timeout to be set for data transfers, in card bus clock periods
180 pub data_transfer_timeout: u32,
181}
182
183impl Default for Config {
184 fn default() -> Self {
185 Self {
186 hclk: Hertz(400_000_000),
187 kernel_clk: Hertz(100_000_000),
188 data_transfer_timeout: 5_000_000,
189 }
190 }
191}
192
193/// Sdmmc device
194pub struct Sdmmc<'d, T: Instance, P: Pins<T>, Dma = NoDma> {
195 sdmmc: PhantomData<&'d mut T>,
196 pins: P,
197 irq: T::Interrupt,
198 config: Config,
199 /// Current clock to card
200 clock: Hertz,
201 /// Current signalling scheme to card
202 signalling: Signalling,
203 /// Card
204 card: Option<Card>,
205 dma: Dma,
206}
207
208impl<'d, T: Instance, P: Pins<T>, Dma> Sdmmc<'d, T, P, Dma> {
209 /// # Safety
210 ///
211 /// Futures that borrow this type can't be leaked
212 #[inline(always)]
213 pub unsafe fn new(
214 _peripheral: impl Unborrow<Target = T> + 'd,
215 pins: impl Unborrow<Target = P> + 'd,
216 irq: impl Unborrow<Target = T::Interrupt> + 'd,
217 config: Config,
218 dma: Dma,
219 ) -> Self {
220 unborrow!(irq, pins);
221 pins.configure();
222
223 let inner = T::inner();
224 let clock = inner.new_inner(config.kernel_clk);
225
226 irq.set_handler(Self::on_interrupt);
227 irq.unpend();
228 irq.enable();
229
230 Self {
231 sdmmc: PhantomData,
232 pins,
233 irq,
234 config,
235 clock,
236 signalling: Default::default(),
237 card: None,
238 dma,
239 }
240 }
241
242 #[inline(always)]
243 pub async fn init_card(&mut self, freq: impl Into<Hertz>) -> Result<(), Error> {
244 let inner = T::inner();
245 let freq = freq.into();
246
247 inner
248 .init_card(
249 freq,
250 P::BUSWIDTH,
251 &mut self.card,
252 &mut self.signalling,
253 self.config.hclk,
254 self.config.kernel_clk,
255 &mut self.clock,
256 T::state(),
257 self.config.data_transfer_timeout,
258 )
259 .await
260 }
261
262 #[inline(always)]
263 pub async fn read_block(
264 &mut self,
265 block_idx: u32,
266 buffer: &mut DataBlock,
267 ) -> Result<(), Error> {
268 let card_capacity = self.card()?.card_type;
269 let inner = T::inner();
270 let state = T::state();
271
272 // NOTE(unsafe) DataBlock uses align 4
273 let buf = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) };
274 inner
275 .read_block(
276 block_idx,
277 buf,
278 card_capacity,
279 state,
280 self.config.data_transfer_timeout,
281 )
282 .await
283 }
284
285 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> {
286 let card = self.card.as_mut().ok_or(Error::NoCard)?;
287 let inner = T::inner();
288 let state = T::state();
289
290 // NOTE(unsafe) DataBlock uses align 4
291 let buf = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) };
292 inner
293 .write_block(
294 block_idx,
295 buf,
296 card,
297 state,
298 self.config.data_transfer_timeout,
299 )
300 .await
301 }
302
303 /// Get a reference to the initialized card
304 ///
305 /// # Errors
306 ///
307 /// Returns Error::NoCard if [`init_card`](#method.init_card)
308 /// has not previously succeeded
309 #[inline(always)]
310 pub fn card(&self) -> Result<&Card, Error> {
311 self.card.as_ref().ok_or(Error::NoCard)
312 }
313
314 #[inline(always)]
315 fn on_interrupt(_: *mut ()) {
316 let regs = T::inner();
317 let state = T::state();
318
319 regs.data_interrupts(false);
320 state.wake();
321 }
322}
323
324impl<'d, T: Instance, P: Pins<T>, Dma> Drop for Sdmmc<'d, T, P, Dma> {
325 fn drop(&mut self) {
326 self.irq.disable();
327 let inner = T::inner();
328 unsafe { inner.on_drop() };
329 self.pins.deconfigure();
330 }
331}
332
333pub struct SdmmcInner(pub(crate) RegBlock);
334
335impl SdmmcInner {
336 /// # Safety
337 ///
338 /// Access to `regs` registers should be exclusive
339 unsafe fn new_inner(&self, kernel_clk: Hertz) -> Hertz {
340 let regs = self.0;
341
342 // While the SD/SDIO card or eMMC is in identification mode,
343 // the SDMMC_CK frequency must be less than 400 kHz.
344 let (clkdiv, clock) = unwrap!(clk_div(kernel_clk, 400_000));
345
346 regs.clkcr().write(|w| {
347 w.set_widbus(0);
348 w.set_clkdiv(clkdiv);
349 w.set_pwrsav(false);
350 w.set_negedge(false);
351 w.set_hwfc_en(true);
352 });
353
354 // Power off, writen 00: Clock to the card is stopped;
355 // D[7:0], CMD, and CK are driven high.
356 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8));
357
358 clock
359 }
360
361 /// Initializes card (if present) and sets the bus at the
362 /// specified frequency.
363 #[allow(clippy::too_many_arguments)]
364 async fn init_card(
365 &self,
366 freq: Hertz,
367 bus_width: BusWidth,
368 old_card: &mut Option<Card>,
369 signalling: &mut Signalling,
370 hclk: Hertz,
371 ker_ck: Hertz,
372 clock: &mut Hertz,
373 waker_reg: &AtomicWaker,
374 data_transfer_timeout: u32,
375 ) -> Result<(), Error> {
376 let regs = self.0;
377
378 // NOTE(unsafe) We have exclusive access to the peripheral
379 unsafe {
380 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
381 self.cmd(Cmd::idle(), false)?;
382
383 // Check if cards supports CMD8 (with pattern)
384 self.cmd(Cmd::hs_send_ext_csd(0x1AA), false)?;
385 let r1 = regs.resp(0).read().cardstatus();
386
387 let mut card = if r1 == 0x1AA {
388 // Card echoed back the pattern. Must be at least v2
389 Card::default()
390 } else {
391 return Err(Error::UnsupportedCardVersion);
392 };
393
394 let ocr = loop {
395 // Signal that next command is a app command
396 self.cmd(Cmd::app_cmd(0), false)?; // CMD55
397
398 let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32
399 | CmdAppOper::HIGH_CAPACITY as u32
400 | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32;
401
402 // Initialize card
403 match self.cmd(Cmd::app_op_cmd(arg), false) {
404 // ACMD41
405 Ok(_) => (),
406 Err(Error::Crc) => (),
407 Err(err) => return Err(err),
408 }
409 let ocr: OCR = regs.resp(0).read().cardstatus().into();
410 if !ocr.is_busy() {
411 // Power up done
412 break ocr;
413 }
414 };
415
416 if ocr.high_capacity() {
417 // Card is SDHC or SDXC or SDUC
418 card.card_type = CardCapacity::SDHC;
419 } else {
420 card.card_type = CardCapacity::SDSC;
421 }
422 card.ocr = ocr;
423
424 self.cmd(Cmd::all_send_cid(), false)?; // CMD2
425 let cid0 = regs.resp(0).read().cardstatus() as u128;
426 let cid1 = regs.resp(1).read().cardstatus() as u128;
427 let cid2 = regs.resp(2).read().cardstatus() as u128;
428 let cid3 = regs.resp(3).read().cardstatus() as u128;
429 let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
430 card.cid = cid.into();
431
432 self.cmd(Cmd::send_rel_addr(), false)?;
433 card.rca = regs.resp(0).read().cardstatus() >> 16;
434
435 self.cmd(Cmd::send_csd(card.rca << 16), false)?;
436 let csd0 = regs.resp(0).read().cardstatus() as u128;
437 let csd1 = regs.resp(1).read().cardstatus() as u128;
438 let csd2 = regs.resp(2).read().cardstatus() as u128;
439 let csd3 = regs.resp(3).read().cardstatus() as u128;
440 let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
441 card.csd = csd.into();
442
443 self.select_card(Some(&card))?;
444 self.get_scr(&mut card, waker_reg, data_transfer_timeout)
445 .await?;
446
447 // Set bus width
448 let (width, acmd_arg) = match bus_width {
449 BusWidth::Eight => unimplemented!(),
450 BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2),
451 _ => (BusWidth::One, 0),
452 };
453 self.cmd(Cmd::app_cmd(card.rca << 16), false)?;
454 self.cmd(Cmd::cmd6(acmd_arg), false)?;
455
456 // CPSMACT and DPSMACT must be 0 to set WIDBUS
457 self.wait_idle();
458
459 regs.clkcr().modify(|w| {
460 w.set_widbus(match width {
461 BusWidth::One => 0,
462 BusWidth::Four => 1,
463 BusWidth::Eight => 2,
464 _ => panic!("Invalid Bus Width"),
465 })
466 });
467
468 // Set Clock
469 if freq.0 <= 25_000_000 {
470 // Final clock frequency
471 self.clkcr_set_clkdiv(freq.0, width, hclk, ker_ck, clock)?;
472 } else {
473 // Switch to max clock for SDR12
474 self.clkcr_set_clkdiv(25_000_000, width, hclk, ker_ck, clock)?;
475 }
476
477 // Read status
478 self.read_sd_status(&mut card, waker_reg, data_transfer_timeout)
479 .await?;
480
481 if freq.0 > 25_000_000 {
482 // Switch to SDR25
483 *signalling = self
484 .switch_signalling_mode(Signalling::SDR25, waker_reg, data_transfer_timeout)
485 .await?;
486
487 if *signalling == Signalling::SDR25 {
488 // Set final clock frequency
489 self.clkcr_set_clkdiv(freq.0, width, hclk, ker_ck, clock)?;
490
491 if self.read_status(&card)?.state() != CurrentState::Transfer {
492 return Err(Error::SignalingSwitchFailed);
493 }
494 }
495 }
496 // Read status after signalling change
497 self.read_sd_status(&mut card, waker_reg, data_transfer_timeout)
498 .await?;
499 old_card.replace(card);
500 }
501
502 Ok(())
503 }
504
505 async fn read_block(
506 &self,
507 block_idx: u32,
508 buffer: &mut [u32; 128],
509 capacity: CardCapacity,
510 waker_reg: &AtomicWaker,
511 data_transfer_timeout: u32,
512 ) -> Result<(), Error> {
513 // Always read 1 block of 512 bytes
514 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
515 let address = match capacity {
516 CardCapacity::SDSC => block_idx * 512,
517 _ => block_idx,
518 };
519 self.cmd(Cmd::set_block_length(512), false)?; // CMD16
520
521 let regs = self.0;
522 let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
523
524 let buf_addr = buffer as *mut [u32; 128] as u32;
525 unsafe {
526 self.prepare_datapath_transfer(
527 buf_addr,
528 512,
529 9,
530 Dir::CardToHost,
531 data_transfer_timeout,
532 );
533 self.data_interrupts(true);
534 }
535 self.cmd(Cmd::read_single_block(address), true)?;
536
537 let res = poll_fn(|cx| {
538 waker_reg.register(cx.waker());
539 let status = unsafe { regs.sta().read() };
540
541 if status.dcrcfail() {
542 return Poll::Ready(Err(Error::Crc));
543 } else if status.dtimeout() {
544 return Poll::Ready(Err(Error::Timeout));
545 } else if status.dataend() {
546 return Poll::Ready(Ok(()));
547 }
548 Poll::Pending
549 })
550 .await;
551 self.clear_interrupt_flags();
552
553 if res.is_ok() {
554 on_drop.defuse();
555 unsafe {
556 regs.idmactrlr().modify(|w| w.set_idmaen(false));
557 }
558 }
559 res
560 }
561
562 async fn write_block(
563 &self,
564 block_idx: u32,
565 buffer: &[u32; 128],
566 card: &mut Card,
567 waker_reg: &AtomicWaker,
568 data_transfer_timeout: u32,
569 ) -> Result<(), Error> {
570 // Always read 1 block of 512 bytes
571 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
572 let address = match card.card_type {
573 CardCapacity::SDSC => block_idx * 512,
574 _ => block_idx,
575 };
576 self.cmd(Cmd::set_block_length(512), false)?; // CMD16
577
578 let regs = self.0;
579 let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
580
581 let buf_addr = buffer as *const [u32; 128] as u32;
582 unsafe {
583 self.prepare_datapath_transfer(
584 buf_addr,
585 512,
586 9,
587 Dir::HostToCard,
588 data_transfer_timeout,
589 );
590 self.data_interrupts(true);
591 }
592 self.cmd(Cmd::write_single_block(address), true)?;
593
594 let res = poll_fn(|cx| {
595 waker_reg.register(cx.waker());
596 let status = unsafe { regs.sta().read() };
597
598 if status.dcrcfail() {
599 return Poll::Ready(Err(Error::Crc));
600 } else if status.dtimeout() {
601 return Poll::Ready(Err(Error::Timeout));
602 } else if status.dataend() {
603 return Poll::Ready(Ok(()));
604 }
605 Poll::Pending
606 })
607 .await;
608 self.clear_interrupt_flags();
609
610 match res {
611 Ok(_) => {
612 on_drop.defuse();
613 unsafe {
614 regs.idmactrlr().modify(|w| w.set_idmaen(false));
615 }
616 // TODO: Make this configurable
617 let mut timeout: u32 = 0x00FF_FFFF;
618
619 // Try to read card status (ACMD13)
620 while timeout > 0 {
621 match self
622 .read_sd_status(card, waker_reg, data_transfer_timeout)
623 .await
624 {
625 Ok(_) => return Ok(()),
626 Err(Error::Timeout) => (), // Try again
627 Err(e) => return Err(e),
628 }
629 timeout -= 1;
630 }
631 Err(Error::SoftwareTimeout)
632 }
633 Err(e) => Err(e),
634 }
635 }
636
637 /// Get the current SDMMC bus clock
638 //pub fn clock(&self) -> Hertz {
639 // self.clock
640 //}
641
642 /// Data transfer is in progress
643 #[inline(always)]
644 fn data_active(&self) -> bool {
645 let regs = self.0;
646
647 // NOTE(unsafe) Atomic read with no side-effects
648 unsafe {
649 let status = regs.sta().read();
650 cfg_if::cfg_if! {
651 if #[cfg(sdmmc_v1)] {
652 status.rxact() || status.txact()
653 } else if #[cfg(sdmmc_v2)] {
654 status.dpsmact()
655 }
656 }
657 }
658 }
659
660 /// Coammand transfer is in progress
661 #[inline(always)]
662 fn cmd_active(&self) -> bool {
663 let regs = self.0;
664
665 // NOTE(unsafe) Atomic read with no side-effects
666 unsafe {
667 let status = regs.sta().read();
668 cfg_if::cfg_if! {
669 if #[cfg(sdmmc_v1)] {
670 status.cmdact()
671 } else if #[cfg(sdmmc_v2)] {
672 status.cpsmact()
673 }
674 }
675 }
676 }
677
678 /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2)
679 #[inline(always)]
680 fn wait_idle(&self) {
681 while self.data_active() || self.cmd_active() {}
682 }
683
684 /// # Safety
685 ///
686 /// `buffer_addr` must be valid for the whole transfer and word aligned
687 unsafe fn prepare_datapath_transfer(
688 &self,
689 buffer_addr: u32,
690 length_bytes: u32,
691 block_size: u8,
692 direction: Dir,
693 data_transfer_timeout: u32,
694 ) {
695 assert!(block_size <= 14, "Block size up to 2^14 bytes");
696 let regs = self.0;
697
698 let dtdir = match direction {
699 Dir::CardToHost => true,
700 Dir::HostToCard => false,
701 };
702
703 // Command AND Data state machines must be idle
704 self.wait_idle();
705 self.clear_interrupt_flags();
706
707 // NOTE(unsafe) We have exclusive access to the regisers
708
709 regs.dtimer()
710 .write(|w| w.set_datatime(data_transfer_timeout));
711 regs.dlen().write(|w| w.set_datalength(length_bytes));
712
713 regs.idmabase0r().write(|w| w.set_idmabase0(buffer_addr));
714 regs.idmactrlr().modify(|w| w.set_idmaen(true));
715 regs.dctrl().modify(|w| {
716 w.set_dblocksize(block_size);
717 w.set_dtdir(dtdir);
718 });
719 }
720
721 /// Sets the CLKDIV field in CLKCR. Updates clock field in self
722 fn clkcr_set_clkdiv(
723 &self,
724 freq: u32,
725 width: BusWidth,
726 hclk: Hertz,
727 ker_ck: Hertz,
728 clock: &mut Hertz,
729 ) -> Result<(), Error> {
730 let regs = self.0;
731
732 let (clkdiv, new_clock) = clk_div(ker_ck, freq)?;
733 // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7
734 // Section 55.5.8
735 let sdmmc_bus_bandwidth = new_clock.0 * (width as u32);
736 assert!(hclk.0 > 3 * sdmmc_bus_bandwidth / 32);
737 *clock = new_clock;
738
739 // NOTE(unsafe) We have exclusive access to the regblock
740 unsafe {
741 // CPSMACT and DPSMACT must be 0 to set CLKDIV
742 self.wait_idle();
743 regs.clkcr().modify(|w| w.set_clkdiv(clkdiv));
744 }
745
746 Ok(())
747 }
748
749 /// Switch mode using CMD6.
750 ///
751 /// Attempt to set a new signalling mode. The selected
752 /// signalling mode is returned. Expects the current clock
753 /// frequency to be > 12.5MHz.
754 async fn switch_signalling_mode(
755 &self,
756 signalling: Signalling,
757 waker_reg: &AtomicWaker,
758 data_transfer_timeout: u32,
759 ) -> Result<Signalling, Error> {
760 // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not
761 // necessary"
762
763 let set_function = 0x8000_0000
764 | match signalling {
765 // See PLSS v7_10 Table 4-11
766 Signalling::DDR50 => 0xFF_FF04,
767 Signalling::SDR104 => 0xFF_1F03,
768 Signalling::SDR50 => 0xFF_1F02,
769 Signalling::SDR25 => 0xFF_FF01,
770 Signalling::SDR12 => 0xFF_FF00,
771 };
772
773 let mut status = [0u32; 16];
774 let status_addr = &mut status as *mut [u32; 16] as u32;
775
776 // Arm `OnDrop` after the buffer, so it will be dropped first
777 let regs = self.0;
778 let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
779
780 unsafe {
781 self.prepare_datapath_transfer(
782 status_addr,
783 64,
784 6,
785 Dir::CardToHost,
786 data_transfer_timeout,
787 );
788 self.data_interrupts(true);
789 }
790 self.cmd(Cmd::cmd6(set_function), true)?; // CMD6
791
792 let res = poll_fn(|cx| {
793 waker_reg.register(cx.waker());
794 let status = unsafe { regs.sta().read() };
795
796 if status.dcrcfail() {
797 return Poll::Ready(Err(Error::Crc));
798 } else if status.dtimeout() {
799 return Poll::Ready(Err(Error::Timeout));
800 } else if status.dataend() {
801 return Poll::Ready(Ok(()));
802 }
803 Poll::Pending
804 })
805 .await;
806 self.clear_interrupt_flags();
807
808 // Host is allowed to use the new functions at least 8
809 // clocks after the end of the switch command
810 // transaction. We know the current clock period is < 80ns,
811 // so a total delay of 640ns is required here
812 for _ in 0..300 {
813 cortex_m::asm::nop();
814 }
815
816 match res {
817 Ok(_) => {
818 on_drop.defuse();
819 unsafe {
820 regs.idmactrlr().modify(|w| w.set_idmaen(false));
821 }
822 // Function Selection of Function Group 1
823 let selection = (u32::from_be(status[4]) >> 24) & 0xF;
824
825 match selection {
826 0 => Ok(Signalling::SDR12),
827 1 => Ok(Signalling::SDR25),
828 2 => Ok(Signalling::SDR50),
829 3 => Ok(Signalling::SDR104),
830 4 => Ok(Signalling::DDR50),
831 _ => Err(Error::UnsupportedCardType),
832 }
833 }
834 Err(e) => Err(e),
835 }
836 }
837
838 /// Query the card status (CMD13, returns R1)
839 ///
840 fn read_status(&self, card: &Card) -> Result<CardStatus, Error> {
841 let regs = self.0;
842 let rca = card.rca;
843
844 self.cmd(Cmd::card_status(rca << 16), false)?; // CMD13
845
846 // NOTE(unsafe) Atomic read with no side-effects
847 let r1 = unsafe { regs.resp(0).read().cardstatus() };
848 Ok(r1.into())
849 }
850
851 /// Reads the SD Status (ACMD13)
852 async fn read_sd_status(
853 &self,
854 card: &mut Card,
855 waker_reg: &AtomicWaker,
856 data_transfer_timeout: u32,
857 ) -> Result<(), Error> {
858 let rca = card.rca;
859 self.cmd(Cmd::set_block_length(64), false)?; // CMD16
860 self.cmd(Cmd::app_cmd(rca << 16), false)?; // APP
861
862 let mut status = [0u32; 16];
863 let status_addr = &mut status as *mut [u32; 16] as u32;
864
865 // Arm `OnDrop` after the buffer, so it will be dropped first
866 let regs = self.0;
867 let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
868
869 unsafe {
870 self.prepare_datapath_transfer(
871 status_addr,
872 64,
873 6,
874 Dir::CardToHost,
875 data_transfer_timeout,
876 );
877 self.data_interrupts(true);
878 }
879 self.cmd(Cmd::card_status(0), true)?;
880
881 let res = poll_fn(|cx| {
882 waker_reg.register(cx.waker());
883 let status = unsafe { regs.sta().read() };
884
885 if status.dcrcfail() {
886 return Poll::Ready(Err(Error::Crc));
887 } else if status.dtimeout() {
888 return Poll::Ready(Err(Error::Timeout));
889 } else if status.dataend() {
890 return Poll::Ready(Ok(()));
891 }
892 Poll::Pending
893 })
894 .await;
895 self.clear_interrupt_flags();
896
897 if res.is_ok() {
898 on_drop.defuse();
899 unsafe {
900 regs.idmactrlr().modify(|w| w.set_idmaen(false));
901 }
902 for byte in status.iter_mut() {
903 *byte = u32::from_be(*byte);
904 }
905 card.status = status.into();
906 }
907 res
908 }
909
910 /// Select one card and place it into the _Tranfer State_
911 ///
912 /// If `None` is specifed for `card`, all cards are put back into
913 /// _Stand-by State_
914 fn select_card(&self, card: Option<&Card>) -> Result<(), Error> {
915 // Determine Relative Card Address (RCA) of given card
916 let rca = card.map(|c| c.rca << 16).unwrap_or(0);
917
918 let r = self.cmd(Cmd::sel_desel_card(rca), false);
919 match (r, rca) {
920 (Err(Error::Timeout), 0) => Ok(()),
921 _ => r,
922 }
923 }
924
925 /// Clear flags in interrupt clear register
926 #[inline(always)]
927 fn clear_interrupt_flags(&self) {
928 let regs = self.0;
929 // NOTE(unsafe) Atomic write
930 unsafe {
931 regs.icr().write(|w| {
932 w.set_ccrcfailc(true);
933 w.set_dcrcfailc(true);
934 w.set_ctimeoutc(true);
935 w.set_dtimeoutc(true);
936 w.set_txunderrc(true);
937 w.set_rxoverrc(true);
938 w.set_cmdrendc(true);
939 w.set_cmdsentc(true);
940 w.set_dataendc(true);
941 w.set_dbckendc(true);
942 w.set_sdioitc(true);
943
944 cfg_if::cfg_if! {
945 if #[cfg(sdmmc_v1)] {
946 w.set_stbiterrc(true);
947 w.set_ceataendc(true);
948 } else if #[cfg(sdmmc_v2)] {
949 w.set_dholdc(true);
950 w.set_dabortc(true);
951 w.set_busyd0endc(true);
952 w.set_ackfailc(true);
953 w.set_acktimeoutc(true);
954 w.set_vswendc(true);
955 w.set_ckstopc(true);
956 w.set_idmatec(true);
957 w.set_idmabtcc(true);
958 }
959 }
960 });
961 }
962 }
963
964 /// Enables the interrupts for data transfer
965 #[inline(always)]
966 fn data_interrupts(&self, enable: bool) {
967 let regs = self.0;
968 // NOTE(unsafe) Atomic write
969 unsafe {
970 regs.mask().write(|w| {
971 w.set_dcrcfailie(enable);
972 w.set_dtimeoutie(enable);
973 w.set_dataendie(enable);
974
975 #[cfg(sdmmc_v2)]
976 w.set_dabortie(enable);
977 });
978 }
979 }
980
981 async fn get_scr(
982 &self,
983 card: &mut Card,
984 waker_reg: &AtomicWaker,
985 data_transfer_timeout: u32,
986 ) -> Result<(), Error> {
987 // Read the the 64-bit SCR register
988 self.cmd(Cmd::set_block_length(8), false)?; // CMD16
989 self.cmd(Cmd::app_cmd(card.rca << 16), false)?;
990
991 let mut scr = [0u32; 2];
992 let scr_addr = &mut scr as *mut u32 as u32;
993
994 // Arm `OnDrop` after the buffer, so it will be dropped first
995 let regs = self.0;
996 let on_drop = OnDrop::new(move || unsafe { self.on_drop() });
997
998 unsafe {
999 self.prepare_datapath_transfer(scr_addr, 8, 3, Dir::CardToHost, data_transfer_timeout);
1000 self.data_interrupts(true);
1001 }
1002 self.cmd(Cmd::cmd51(), true)?;
1003
1004 let res = poll_fn(|cx| {
1005 waker_reg.register(cx.waker());
1006 let status = unsafe { regs.sta().read() };
1007
1008 if status.dcrcfail() {
1009 return Poll::Ready(Err(Error::Crc));
1010 } else if status.dtimeout() {
1011 return Poll::Ready(Err(Error::Timeout));
1012 } else if status.dataend() {
1013 return Poll::Ready(Ok(()));
1014 }
1015 Poll::Pending
1016 })
1017 .await;
1018 self.clear_interrupt_flags();
1019
1020 if res.is_ok() {
1021 on_drop.defuse();
1022
1023 unsafe {
1024 regs.idmactrlr().modify(|w| w.set_idmaen(false));
1025 let scr_bytes = &*(&scr as *const [u32; 2] as *const [u8; 8]);
1026 card.scr = SCR(u64::from_be_bytes(*scr_bytes));
1027 }
1028 }
1029 res
1030 }
1031
1032 /// Send command to card
1033 fn cmd(&self, cmd: Cmd, data: bool) -> Result<(), Error> {
1034 let regs = self.0;
1035
1036 self.clear_interrupt_flags();
1037 // NOTE(safety) Atomic operations
1038 unsafe {
1039 // CP state machine must be idle
1040 while self.cmd_active() {}
1041
1042 // Command arg
1043 regs.arg().write(|w| w.set_cmdarg(cmd.arg));
1044
1045 // Command index and start CP State Machine
1046 regs.cmd().write(|w| {
1047 w.set_waitint(false);
1048 w.set_waitresp(cmd.resp as u8);
1049 w.set_cmdindex(cmd.cmd);
1050 w.set_cpsmen(true);
1051
1052 cfg_if::cfg_if! {
1053 if #[cfg(sdmmc_v2)] {
1054 // Special mode in CP State Machine
1055 // CMD12: Stop Transmission
1056 let cpsm_stop_transmission = cmd.cmd == 12;
1057 w.set_cmdstop(cpsm_stop_transmission);
1058 w.set_cmdtrans(data);
1059 }
1060 }
1061 });
1062
1063 let mut status;
1064 if cmd.resp == Response::None {
1065 // Wait for CMDSENT or a timeout
1066 while {
1067 status = regs.sta().read();
1068 !(status.ctimeout() || status.cmdsent())
1069 } {}
1070 } else {
1071 // Wait for CMDREND or CCRCFAIL or a timeout
1072 while {
1073 status = regs.sta().read();
1074 !(status.ctimeout() || status.cmdrend() || status.ccrcfail())
1075 } {}
1076 }
1077
1078 if status.ctimeout() {
1079 return Err(Error::Timeout);
1080 } else if status.ccrcfail() {
1081 return Err(Error::Crc);
1082 }
1083 Ok(())
1084 }
1085 }
1086
1087 /// # Safety
1088 ///
1089 /// Ensure that `regs` has exclusive access to the regblocks
1090 unsafe fn on_drop(&self) {
1091 let regs = self.0;
1092 if self.data_active() {
1093 self.clear_interrupt_flags();
1094 // Send abort
1095 // CP state machine must be idle
1096 while self.cmd_active() {}
1097
1098 // Command arg
1099 regs.arg().write(|w| w.set_cmdarg(0));
1100
1101 // Command index and start CP State Machine
1102 regs.cmd().write(|w| {
1103 w.set_waitint(false);
1104 w.set_waitresp(Response::Short as u8);
1105 w.set_cmdindex(12);
1106 w.set_cpsmen(true);
1107
1108 cfg_if::cfg_if! {
1109 if #[cfg(sdmmc_v2)] {
1110 w.set_cmdstop(true);
1111 w.set_cmdtrans(false);
1112 }
1113 }
1114 });
1115
1116 // Wait for the abort
1117 while self.data_active() {}
1118 }
1119 self.data_interrupts(false);
1120 self.clear_interrupt_flags();
1121 regs.idmactrlr().modify(|w| w.set_idmaen(false));
1122 }
1123}
1124
1125/// SD card Commands
1126impl Cmd {
1127 const fn new(cmd: u8, arg: u32, resp: Response) -> Cmd {
1128 Cmd { cmd, arg, resp }
1129 }
1130
1131 /// CMD0: Idle
1132 const fn idle() -> Cmd {
1133 Cmd::new(0, 0, Response::None)
1134 }
1135
1136 /// CMD2: Send CID
1137 const fn all_send_cid() -> Cmd {
1138 Cmd::new(2, 0, Response::Long)
1139 }
1140
1141 /// CMD3: Send Relative Address
1142 const fn send_rel_addr() -> Cmd {
1143 Cmd::new(3, 0, Response::Short)
1144 }
1145
1146 /// CMD6: Switch Function Command
1147 /// ACMD6: Bus Width
1148 const fn cmd6(arg: u32) -> Cmd {
1149 Cmd::new(6, arg, Response::Short)
1150 }
1151
1152 /// CMD7: Select one card and put it into the _Tranfer State_
1153 const fn sel_desel_card(rca: u32) -> Cmd {
1154 Cmd::new(7, rca, Response::Short)
1155 }
1156
1157 /// CMD8:
1158 const fn hs_send_ext_csd(arg: u32) -> Cmd {
1159 Cmd::new(8, arg, Response::Short)
1160 }
1161
1162 /// CMD9:
1163 const fn send_csd(rca: u32) -> Cmd {
1164 Cmd::new(9, rca, Response::Long)
1165 }
1166
1167 /// CMD12:
1168 //const fn stop_transmission() -> Cmd {
1169 // Cmd::new(12, 0, Response::Short)
1170 //}
1171
1172 /// CMD13: Ask card to send status register
1173 /// ACMD13: SD Status
1174 const fn card_status(rca: u32) -> Cmd {
1175 Cmd::new(13, rca, Response::Short)
1176 }
1177
1178 /// CMD16:
1179 const fn set_block_length(blocklen: u32) -> Cmd {
1180 Cmd::new(16, blocklen, Response::Short)
1181 }
1182
1183 /// CMD17: Block Read
1184 const fn read_single_block(addr: u32) -> Cmd {
1185 Cmd::new(17, addr, Response::Short)
1186 }
1187
1188 /// CMD18: Multiple Block Read
1189 //const fn read_multiple_blocks(addr: u32) -> Cmd {
1190 // Cmd::new(18, addr, Response::Short)
1191 //}
1192
1193 /// CMD24: Block Write
1194 const fn write_single_block(addr: u32) -> Cmd {
1195 Cmd::new(24, addr, Response::Short)
1196 }
1197
1198 const fn app_op_cmd(arg: u32) -> Cmd {
1199 Cmd::new(41, arg, Response::Short)
1200 }
1201
1202 const fn cmd51() -> Cmd {
1203 Cmd::new(51, 0, Response::Short)
1204 }
1205
1206 /// App Command. Indicates that next command will be a app command
1207 const fn app_cmd(rca: u32) -> Cmd {
1208 Cmd::new(55, rca, Response::Short)
1209 }
1210}
1211
1212//////////////////////////////////////////////////////
1213
1214pub(crate) mod sealed {
1215 use super::*;
1216
1217 pub trait Instance {
1218 type Interrupt: Interrupt;
1219
1220 fn inner() -> SdmmcInner;
1221 fn state() -> &'static AtomicWaker;
1222 }
1223
1224 pub trait Pins<T: Instance> {}
1225}
1226
1227pub trait Instance: sealed::Instance + 'static {}
1228pin_trait!(CkPin, Instance);
1229pin_trait!(CmdPin, Instance);
1230pin_trait!(D0Pin, Instance);
1231pin_trait!(D1Pin, Instance);
1232pin_trait!(D2Pin, Instance);
1233pin_trait!(D3Pin, Instance);
1234pin_trait!(D4Pin, Instance);
1235pin_trait!(D5Pin, Instance);
1236pin_trait!(D6Pin, Instance);
1237pin_trait!(D7Pin, Instance);
1238
1239dma_trait!(SdioDma, Instance);
1240
1241pub trait Pins<T: Instance>: sealed::Pins<T> + 'static {
1242 const BUSWIDTH: BusWidth;
1243
1244 fn configure(&mut self);
1245 fn deconfigure(&mut self);
1246}
1247
1248impl<T, CLK, CMD, D0, D1, D2, D3> sealed::Pins<T> for (CLK, CMD, D0, D1, D2, D3)
1249where
1250 T: Instance,
1251 CLK: CkPin<T>,
1252 CMD: CmdPin<T>,
1253 D0: D0Pin<T>,
1254 D1: D1Pin<T>,
1255 D2: D2Pin<T>,
1256 D3: D3Pin<T>,
1257{
1258}
1259
1260impl<T, CLK, CMD, D0> sealed::Pins<T> for (CLK, CMD, D0)
1261where
1262 T: Instance,
1263 CLK: CkPin<T>,
1264 CMD: CmdPin<T>,
1265 D0: D0Pin<T>,
1266{
1267}
1268
1269impl<T, CLK, CMD, D0, D1, D2, D3> Pins<T> for (CLK, CMD, D0, D1, D2, D3)
1270where
1271 T: Instance,
1272 CLK: CkPin<T>,
1273 CMD: CmdPin<T>,
1274 D0: D0Pin<T>,
1275 D1: D1Pin<T>,
1276 D2: D2Pin<T>,
1277 D3: D3Pin<T>,
1278{
1279 const BUSWIDTH: BusWidth = BusWidth::Four;
1280
1281 fn configure(&mut self) {
1282 let (clk_pin, cmd_pin, d0_pin, d1_pin, d2_pin, d3_pin) = self;
1283
1284 critical_section::with(|_| unsafe {
1285 clk_pin.set_as_af_pull(clk_pin.af_num(), AFType::OutputPushPull, Pull::None);
1286 cmd_pin.set_as_af_pull(cmd_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1287 d0_pin.set_as_af_pull(d0_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1288 d1_pin.set_as_af_pull(d1_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1289 d2_pin.set_as_af_pull(d2_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1290 d3_pin.set_as_af_pull(d3_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1291
1292 clk_pin.set_speed(Speed::VeryHigh);
1293 cmd_pin.set_speed(Speed::VeryHigh);
1294 d0_pin.set_speed(Speed::VeryHigh);
1295 d1_pin.set_speed(Speed::VeryHigh);
1296 d2_pin.set_speed(Speed::VeryHigh);
1297 d3_pin.set_speed(Speed::VeryHigh);
1298 });
1299 }
1300
1301 fn deconfigure(&mut self) {
1302 let (clk_pin, cmd_pin, d0_pin, d1_pin, d2_pin, d3_pin) = self;
1303
1304 critical_section::with(|_| unsafe {
1305 clk_pin.set_as_disconnected();
1306 cmd_pin.set_as_disconnected();
1307 d0_pin.set_as_disconnected();
1308 d1_pin.set_as_disconnected();
1309 d2_pin.set_as_disconnected();
1310 d3_pin.set_as_disconnected();
1311 });
1312 }
1313}
1314
1315impl<T, CLK, CMD, D0> Pins<T> for (CLK, CMD, D0)
1316where
1317 T: Instance,
1318 CLK: CkPin<T>,
1319 CMD: CmdPin<T>,
1320 D0: D0Pin<T>,
1321{
1322 const BUSWIDTH: BusWidth = BusWidth::One;
1323
1324 fn configure(&mut self) {
1325 let (clk_pin, cmd_pin, d0_pin) = self;
1326
1327 critical_section::with(|_| unsafe {
1328 clk_pin.set_as_af_pull(clk_pin.af_num(), AFType::OutputPushPull, Pull::None);
1329 cmd_pin.set_as_af_pull(cmd_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1330 d0_pin.set_as_af_pull(d0_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1331
1332 clk_pin.set_speed(Speed::VeryHigh);
1333 cmd_pin.set_speed(Speed::VeryHigh);
1334 d0_pin.set_speed(Speed::VeryHigh);
1335 });
1336 }
1337
1338 fn deconfigure(&mut self) {
1339 let (clk_pin, cmd_pin, d0_pin) = self;
1340
1341 critical_section::with(|_| unsafe {
1342 clk_pin.set_as_disconnected();
1343 cmd_pin.set_as_disconnected();
1344 d0_pin.set_as_disconnected();
1345 });
1346 }
1347}
1348
1349foreach_peripheral!(
1350 (sdmmc, $inst:ident) => {
1351 impl sealed::Instance for peripherals::$inst {
1352 type Interrupt = crate::interrupt::$inst;
1353
1354 fn inner() -> SdmmcInner {
1355 const INNER: SdmmcInner = SdmmcInner(crate::pac::$inst);
1356 INNER
1357 }
1358
1359 fn state() -> &'static ::embassy::waitqueue::AtomicWaker {
1360 static WAKER: ::embassy::waitqueue::AtomicWaker = ::embassy::waitqueue::AtomicWaker::new();
1361 &WAKER
1362 }
1363 }
1364
1365 impl Instance for peripherals::$inst {}
1366 };
1367);
1368
1369#[cfg(feature = "sdmmc-rs")]
1370mod sdmmc_rs {
1371 use super::*;
1372 use core::future::Future;
1373 use embedded_sdmmc::{Block, BlockCount, BlockDevice, BlockIdx};
1374
1375 impl<'d, T: Instance, P: Pins<T>> BlockDevice for Sdmmc<'d, T, P> {
1376 type Error = Error;
1377 type ReadFuture<'a>
1378 where
1379 Self: 'a,
1380 = impl Future<Output = Result<(), Self::Error>> + 'a;
1381 type WriteFuture<'a>
1382 where
1383 Self: 'a,
1384 = impl Future<Output = Result<(), Self::Error>> + 'a;
1385
1386 fn read<'a>(
1387 &'a mut self,
1388 blocks: &'a mut [Block],
1389 start_block_idx: BlockIdx,
1390 _reason: &str,
1391 ) -> Self::ReadFuture<'a> {
1392 async move {
1393 let card_capacity = self.card()?.card_type;
1394 let inner = T::inner();
1395 let state = T::state();
1396 let mut address = start_block_idx.0;
1397
1398 for block in blocks.iter_mut() {
1399 let block: &mut [u8; 512] = &mut block.contents;
1400
1401 // NOTE(unsafe) Block uses align(4)
1402 let buf = unsafe { &mut *(block as *mut [u8; 512] as *mut [u32; 128]) };
1403 inner
1404 .read_block(
1405 address,
1406 buf,
1407 card_capacity,
1408 state,
1409 self.config.data_transfer_timeout,
1410 )
1411 .await?;
1412 address += 1;
1413 }
1414 Ok(())
1415 }
1416 }
1417
1418 fn write<'a>(
1419 &'a mut self,
1420 blocks: &'a [Block],
1421 start_block_idx: BlockIdx,
1422 ) -> Self::WriteFuture<'a> {
1423 async move {
1424 let card = self.card.as_mut().ok_or(Error::NoCard)?;
1425 let inner = T::inner();
1426 let state = T::state();
1427 let mut address = start_block_idx.0;
1428
1429 for block in blocks.iter() {
1430 let block: &[u8; 512] = &block.contents;
1431
1432 // NOTE(unsafe) DataBlock uses align 4
1433 let buf = unsafe { &*(block as *const [u8; 512] as *const [u32; 128]) };
1434 inner
1435 .write_block(address, buf, card, state, self.config.data_transfer_timeout)
1436 .await?;
1437 address += 1;
1438 }
1439 Ok(())
1440 }
1441 }
1442
1443 fn num_blocks(&self) -> Result<BlockCount, Self::Error> {
1444 let card = self.card()?;
1445 let count = card.csd.block_count();
1446 Ok(BlockCount(count))
1447 }
1448 }
1449}
diff --git a/embassy-stm32/src/sdmmc/v1.rs b/embassy-stm32/src/sdmmc/v1.rs
deleted file mode 100644
index 8b1378917..000000000
--- a/embassy-stm32/src/sdmmc/v1.rs
+++ /dev/null
@@ -1 +0,0 @@
1
diff --git a/embassy-stm32/src/sdmmc/v2.rs b/embassy-stm32/src/sdmmc/v2.rs
deleted file mode 100644
index cb8fa5544..000000000
--- a/embassy-stm32/src/sdmmc/v2.rs
+++ /dev/null
@@ -1,1374 +0,0 @@
1#![macro_use]
2
3use core::default::Default;
4use core::marker::PhantomData;
5use core::task::Poll;
6
7use embassy::interrupt::InterruptExt;
8use embassy::util::Unborrow;
9use embassy::waitqueue::AtomicWaker;
10use embassy_hal_common::drop::OnDrop;
11use embassy_hal_common::unborrow;
12use futures::future::poll_fn;
13use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR};
14
15use crate::gpio::sealed::AFType;
16use crate::gpio::{Pull, Speed};
17use crate::interrupt::Interrupt;
18use crate::pac::sdmmc::Sdmmc as RegBlock;
19use crate::peripherals;
20use crate::time::Hertz;
21
22/// The signalling scheme used on the SDMMC bus
23#[non_exhaustive]
24#[derive(Debug, Copy, Clone, PartialEq, Eq)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub enum Signalling {
27 SDR12,
28 SDR25,
29 SDR50,
30 SDR104,
31 DDR50,
32}
33
34impl Default for Signalling {
35 fn default() -> Self {
36 Signalling::SDR12
37 }
38}
39
40#[repr(align(4))]
41pub struct DataBlock([u8; 512]);
42
43/// Errors
44#[non_exhaustive]
45#[derive(Debug, Copy, Clone)]
46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47pub enum Error {
48 Timeout,
49 SoftwareTimeout,
50 UnsupportedCardVersion,
51 UnsupportedCardType,
52 Crc,
53 DataCrcFail,
54 RxOverFlow,
55 NoCard,
56 BadClock,
57 SignalingSwitchFailed,
58 PeripheralBusy,
59}
60
61/// A SD command
62struct Cmd {
63 cmd: u8,
64 arg: u32,
65 resp: Response,
66}
67
68#[derive(Clone, Copy, Debug, Default)]
69/// SD Card
70pub struct Card {
71 /// The type of this card
72 pub card_type: CardCapacity,
73 /// Operation Conditions Register
74 pub ocr: OCR,
75 /// Relative Card Address
76 pub rca: u32,
77 /// Card ID
78 pub cid: CID,
79 /// Card Specific Data
80 pub csd: CSD,
81 /// SD CARD Configuration Register
82 pub scr: SCR,
83 /// SD Status
84 pub status: SDStatus,
85}
86impl Card {
87 /// Size in bytes
88 pub fn size(&self) -> u64 {
89 // SDHC / SDXC / SDUC
90 u64::from(self.csd.block_count()) * 512
91 }
92}
93
94/// Indicates transfer direction
95enum Dir {
96 CardToHost,
97 HostToCard,
98}
99
100#[repr(u8)]
101enum PowerCtrl {
102 Off = 0b00,
103 On = 0b11,
104}
105
106#[repr(u32)]
107#[allow(dead_code)]
108#[allow(non_camel_case_types)]
109enum CmdAppOper {
110 VOLTAGE_WINDOW_SD = 0x8010_0000,
111 HIGH_CAPACITY = 0x4000_0000,
112 SDMMC_STD_CAPACITY = 0x0000_0000,
113 SDMMC_CHECK_PATTERN = 0x0000_01AA,
114 SD_SWITCH_1_8V_CAPACITY = 0x0100_0000,
115}
116
117#[derive(Eq, PartialEq, Copy, Clone)]
118enum Response {
119 None = 0,
120 Short = 1,
121 Long = 3,
122}
123
124/// Calculate clock divisor. Returns a SDMMC_CK less than or equal to
125/// `sdmmc_ck` in Hertz.
126///
127/// Returns `(clk_div, clk_f)`, where `clk_div` is the divisor register
128/// value and `clk_f` is the resulting new clock frequency.
129fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(u16, Hertz), Error> {
130 match (ker_ck.0 + sdmmc_ck - 1) / sdmmc_ck {
131 0 | 1 => Ok((0, ker_ck)),
132 x @ 2..=2046 => {
133 let clk_div = ((x + 1) / 2) as u16;
134 let clk = Hertz(ker_ck.0 / (clk_div as u32 * 2));
135
136 Ok((clk_div, clk))
137 }
138 _ => Err(Error::BadClock),
139 }
140}
141
142/// SDMMC configuration
143///
144/// You should probably change the default clock values to match your configuration
145///
146/// Default values:
147/// hclk = 400_000_000 Hz
148/// kernel_clk: 100_000_000 Hz
149/// data_transfer_timeout: 5_000_000
150#[non_exhaustive]
151pub struct Config {
152 /// AHB clock
153 pub hclk: Hertz,
154 /// SDMMC kernel clock
155 pub kernel_clk: Hertz,
156 /// The timeout to be set for data transfers, in card bus clock periods
157 pub data_transfer_timeout: u32,
158}
159
160impl Default for Config {
161 fn default() -> Self {
162 Self {
163 hclk: Hertz(400_000_000),
164 kernel_clk: Hertz(100_000_000),
165 data_transfer_timeout: 5_000_000,
166 }
167 }
168}
169
170/// Sdmmc device
171pub struct Sdmmc<'d, T: Instance, P: Pins<T>> {
172 sdmmc: PhantomData<&'d mut T>,
173 pins: P,
174 irq: T::Interrupt,
175 config: Config,
176 /// Current clock to card
177 clock: Hertz,
178 /// Current signalling scheme to card
179 signalling: Signalling,
180 /// Card
181 card: Option<Card>,
182}
183
184impl<'d, T: Instance, P: Pins<T>> Sdmmc<'d, T, P> {
185 /// # Safety
186 ///
187 /// Futures that borrow this type can't be leaked
188 #[inline(always)]
189 pub unsafe fn new(
190 _peripheral: impl Unborrow<Target = T> + 'd,
191 pins: impl Unborrow<Target = P> + 'd,
192 irq: impl Unborrow<Target = T::Interrupt> + 'd,
193 config: Config,
194 ) -> Self {
195 unborrow!(irq, pins);
196 pins.configure();
197
198 let inner = T::inner();
199 let clock = inner.new_inner(config.kernel_clk);
200
201 irq.set_handler(Self::on_interrupt);
202 irq.unpend();
203 irq.enable();
204
205 Self {
206 sdmmc: PhantomData,
207 pins,
208 irq,
209 config,
210 clock,
211 signalling: Default::default(),
212 card: None,
213 }
214 }
215
216 #[inline(always)]
217 pub async fn init_card(&mut self, freq: impl Into<Hertz>) -> Result<(), Error> {
218 let inner = T::inner();
219 let freq = freq.into();
220
221 inner
222 .init_card(
223 freq,
224 P::BUSWIDTH,
225 &mut self.card,
226 &mut self.signalling,
227 self.config.hclk,
228 self.config.kernel_clk,
229 &mut self.clock,
230 T::state(),
231 self.config.data_transfer_timeout,
232 )
233 .await
234 }
235
236 #[inline(always)]
237 pub async fn read_block(
238 &mut self,
239 block_idx: u32,
240 buffer: &mut DataBlock,
241 ) -> Result<(), Error> {
242 let card_capacity = self.card()?.card_type;
243 let inner = T::inner();
244 let state = T::state();
245
246 // NOTE(unsafe) DataBlock uses align 4
247 let buf = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) };
248 inner
249 .read_block(
250 block_idx,
251 buf,
252 card_capacity,
253 state,
254 self.config.data_transfer_timeout,
255 )
256 .await
257 }
258
259 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> {
260 let card = self.card.as_mut().ok_or(Error::NoCard)?;
261 let inner = T::inner();
262 let state = T::state();
263
264 // NOTE(unsafe) DataBlock uses align 4
265 let buf = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) };
266 inner
267 .write_block(
268 block_idx,
269 buf,
270 card,
271 state,
272 self.config.data_transfer_timeout,
273 )
274 .await
275 }
276
277 /// Get a reference to the initialized card
278 ///
279 /// # Errors
280 ///
281 /// Returns Error::NoCard if [`init_card`](#method.init_card)
282 /// has not previously succeeded
283 #[inline(always)]
284 pub fn card(&self) -> Result<&Card, Error> {
285 self.card.as_ref().ok_or(Error::NoCard)
286 }
287
288 #[inline(always)]
289 fn on_interrupt(_: *mut ()) {
290 let regs = T::inner();
291 let state = T::state();
292
293 regs.data_interrupts(false);
294 state.wake();
295 }
296}
297
298impl<'d, T: Instance, P: Pins<T>> Drop for Sdmmc<'d, T, P> {
299 fn drop(&mut self) {
300 self.irq.disable();
301 let inner = T::inner();
302 unsafe { inner.on_drop() };
303 self.pins.deconfigure();
304 }
305}
306
307pub struct SdmmcInner(pub(crate) RegBlock);
308
309impl SdmmcInner {
310 /// # Safety
311 ///
312 /// Access to `regs` registers should be exclusive
313 unsafe fn new_inner(&self, kernel_clk: Hertz) -> Hertz {
314 let regs = self.0;
315
316 // While the SD/SDIO card or eMMC is in identification mode,
317 // the SDMMC_CK frequency must be less than 400 kHz.
318 let (clkdiv, clock) = unwrap!(clk_div(kernel_clk, 400_000));
319
320 regs.clkcr().write(|w| {
321 w.set_widbus(0);
322 w.set_clkdiv(clkdiv);
323 w.set_pwrsav(false);
324 w.set_negedge(false);
325 w.set_hwfc_en(true);
326 });
327
328 // Power off, writen 00: Clock to the card is stopped;
329 // D[7:0], CMD, and CK are driven high.
330 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8));
331
332 clock
333 }
334
335 /// Initializes card (if present) and sets the bus at the
336 /// specified frequency.
337 #[allow(clippy::too_many_arguments)]
338 async fn init_card(
339 &self,
340 freq: Hertz,
341 bus_width: BusWidth,
342 old_card: &mut Option<Card>,
343 signalling: &mut Signalling,
344 hclk: Hertz,
345 ker_ck: Hertz,
346 clock: &mut Hertz,
347 waker_reg: &AtomicWaker,
348 data_transfer_timeout: u32,
349 ) -> Result<(), Error> {
350 let regs = self.0;
351
352 // NOTE(unsafe) We have exclusive access to the peripheral
353 unsafe {
354 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
355 self.cmd(Cmd::idle(), false)?;
356
357 // Check if cards supports CMD8 (with pattern)
358 self.cmd(Cmd::hs_send_ext_csd(0x1AA), false)?;
359 let r1 = regs.respr(0).read().cardstatus1();
360
361 let mut card = if r1 == 0x1AA {
362 // Card echoed back the pattern. Must be at least v2
363 Card::default()
364 } else {
365 return Err(Error::UnsupportedCardVersion);
366 };
367
368 let ocr = loop {
369 // Signal that next command is a app command
370 self.cmd(Cmd::app_cmd(0), false)?; // CMD55
371
372 let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32
373 | CmdAppOper::HIGH_CAPACITY as u32
374 | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32;
375
376 // Initialize card
377 match self.cmd(Cmd::app_op_cmd(arg), false) {
378 // ACMD41
379 Ok(_) => (),
380 Err(Error::Crc) => (),
381 Err(err) => return Err(err),
382 }
383 let ocr: OCR = regs.respr(0).read().cardstatus1().into();
384 if !ocr.is_busy() {
385 // Power up done
386 break ocr;
387 }
388 };
389
390 if ocr.high_capacity() {
391 // Card is SDHC or SDXC or SDUC
392 card.card_type = CardCapacity::SDHC;
393 } else {
394 card.card_type = CardCapacity::SDSC;
395 }
396 card.ocr = ocr;
397
398 self.cmd(Cmd::all_send_cid(), false)?; // CMD2
399 let cid0 = regs.respr(0).read().cardstatus1() as u128;
400 let cid1 = regs.respr(1).read().cardstatus1() as u128;
401 let cid2 = regs.respr(2).read().cardstatus1() as u128;
402 let cid3 = regs.respr(3).read().cardstatus1() as u128;
403 let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
404 card.cid = cid.into();
405
406 self.cmd(Cmd::send_rel_addr(), false)?;
407 card.rca = regs.respr(0).read().cardstatus1() >> 16;
408
409 self.cmd(Cmd::send_csd(card.rca << 16), false)?;
410 let csd0 = regs.respr(0).read().cardstatus1() as u128;
411 let csd1 = regs.respr(1).read().cardstatus1() as u128;
412 let csd2 = regs.respr(2).read().cardstatus1() as u128;
413 let csd3 = regs.respr(3).read().cardstatus1() as u128;
414 let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
415 card.csd = csd.into();
416
417 self.select_card(Some(&card))?;
418 self.get_scr(&mut card, waker_reg, data_transfer_timeout)
419 .await?;
420
421 // Set bus width
422 let (width, acmd_arg) = match bus_width {
423 BusWidth::Eight => unimplemented!(),
424 BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2),
425 _ => (BusWidth::One, 0),
426 };
427 self.cmd(Cmd::app_cmd(card.rca << 16), false)?;
428 self.cmd(Cmd::cmd6(acmd_arg), false)?;
429
430 // CPSMACT and DPSMACT must be 0 to set WIDBUS
431 self.wait_idle();
432
433 regs.clkcr().modify(|w| {
434 w.set_widbus(match width {
435 BusWidth::One => 0,
436 BusWidth::Four => 1,
437 BusWidth::Eight => 2,
438 _ => panic!("Invalid Bus Width"),
439 })
440 });
441
442 // Set Clock
443 if freq.0 <= 25_000_000 {
444 // Final clock frequency
445 self.clkcr_set_clkdiv(freq.0, width, hclk, ker_ck, clock)?;
446 } else {
447 // Switch to max clock for SDR12
448 self.clkcr_set_clkdiv(25_000_000, width, hclk, ker_ck, clock)?;
449 }
450
451 // Read status
452 self.read_sd_status(&mut card, waker_reg, data_transfer_timeout)
453 .await?;
454
455 if freq.0 > 25_000_000 {
456 // Switch to SDR25
457 *signalling = self
458 .switch_signalling_mode(Signalling::SDR25, waker_reg, data_transfer_timeout)
459 .await?;
460
461 if *signalling == Signalling::SDR25 {
462 // Set final clock frequency
463 self.clkcr_set_clkdiv(freq.0, width, hclk, ker_ck, clock)?;
464
465 if self.read_status(&card)?.state() != CurrentState::Transfer {
466 return Err(Error::SignalingSwitchFailed);
467 }
468 }
469 }
470 // Read status after signalling change
471 self.read_sd_status(&mut card, waker_reg, data_transfer_timeout)
472 .await?;
473 old_card.replace(card);
474 }
475
476 Ok(())
477 }
478
479 async fn read_block(
480 &self,
481 block_idx: u32,
482 buffer: &mut [u32; 128],
483 capacity: CardCapacity,
484 waker_reg: &AtomicWaker,
485 data_transfer_timeout: u32,
486 ) -> Result<(), Error> {
487 // Always read 1 block of 512 bytes
488 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
489 let address = match capacity {
490 CardCapacity::SDSC => block_idx * 512,
491 _ => block_idx,
492 };
493 self.cmd(Cmd::set_block_length(512), false)?; // CMD16
494
495 let regs = self.0;
496 let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
497
498 let buf_addr = buffer as *mut [u32; 128] as u32;
499 unsafe {
500 self.prepare_datapath_transfer(
501 buf_addr,
502 512,
503 9,
504 Dir::CardToHost,
505 data_transfer_timeout,
506 );
507 self.data_interrupts(true);
508 }
509 self.cmd(Cmd::read_single_block(address), true)?;
510
511 let res = poll_fn(|cx| {
512 waker_reg.register(cx.waker());
513 let status = unsafe { regs.star().read() };
514
515 if status.dcrcfail() {
516 return Poll::Ready(Err(Error::Crc));
517 } else if status.dtimeout() {
518 return Poll::Ready(Err(Error::Timeout));
519 } else if status.dataend() {
520 return Poll::Ready(Ok(()));
521 }
522 Poll::Pending
523 })
524 .await;
525 self.clear_interrupt_flags();
526
527 if res.is_ok() {
528 on_drop.defuse();
529 unsafe {
530 regs.idmactrlr().modify(|w| w.set_idmaen(false));
531 }
532 }
533 res
534 }
535
536 async fn write_block(
537 &self,
538 block_idx: u32,
539 buffer: &[u32; 128],
540 card: &mut Card,
541 waker_reg: &AtomicWaker,
542 data_transfer_timeout: u32,
543 ) -> Result<(), Error> {
544 // Always read 1 block of 512 bytes
545 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
546 let address = match card.card_type {
547 CardCapacity::SDSC => block_idx * 512,
548 _ => block_idx,
549 };
550 self.cmd(Cmd::set_block_length(512), false)?; // CMD16
551
552 let regs = self.0;
553 let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
554
555 let buf_addr = buffer as *const [u32; 128] as u32;
556 unsafe {
557 self.prepare_datapath_transfer(
558 buf_addr,
559 512,
560 9,
561 Dir::HostToCard,
562 data_transfer_timeout,
563 );
564 self.data_interrupts(true);
565 }
566 self.cmd(Cmd::write_single_block(address), true)?;
567
568 let res = poll_fn(|cx| {
569 waker_reg.register(cx.waker());
570 let status = unsafe { regs.star().read() };
571
572 if status.dcrcfail() {
573 return Poll::Ready(Err(Error::Crc));
574 } else if status.dtimeout() {
575 return Poll::Ready(Err(Error::Timeout));
576 } else if status.dataend() {
577 return Poll::Ready(Ok(()));
578 }
579 Poll::Pending
580 })
581 .await;
582 self.clear_interrupt_flags();
583
584 match res {
585 Ok(_) => {
586 on_drop.defuse();
587 unsafe {
588 regs.idmactrlr().modify(|w| w.set_idmaen(false));
589 }
590 // TODO: Make this configurable
591 let mut timeout: u32 = 0x00FF_FFFF;
592
593 // Try to read card status (ACMD13)
594 while timeout > 0 {
595 match self
596 .read_sd_status(card, waker_reg, data_transfer_timeout)
597 .await
598 {
599 Ok(_) => return Ok(()),
600 Err(Error::Timeout) => (), // Try again
601 Err(e) => return Err(e),
602 }
603 timeout -= 1;
604 }
605 Err(Error::SoftwareTimeout)
606 }
607 Err(e) => Err(e),
608 }
609 }
610
611 /// Get the current SDMMC bus clock
612 //pub fn clock(&self) -> Hertz {
613 // self.clock
614 //}
615
616 /// Wait idle on DOSNACT and CPSMACT
617 #[inline(always)]
618 fn wait_idle(&self) {
619 let regs = self.0;
620
621 // NOTE(unsafe) Atomic read with no side-effects
622 unsafe {
623 while {
624 let status = regs.star().read();
625 status.dpsmact() || status.cpsmact()
626 } {}
627 }
628 }
629
630 /// # Safety
631 ///
632 /// `buffer_addr` must be valid for the whole transfer and word aligned
633 unsafe fn prepare_datapath_transfer(
634 &self,
635 buffer_addr: u32,
636 length_bytes: u32,
637 block_size: u8,
638 direction: Dir,
639 data_transfer_timeout: u32,
640 ) {
641 assert!(block_size <= 14, "Block size up to 2^14 bytes");
642 let regs = self.0;
643
644 let dtdir = match direction {
645 Dir::CardToHost => true,
646 Dir::HostToCard => false,
647 };
648
649 // Command AND Data state machines must be idle
650 self.wait_idle();
651 self.clear_interrupt_flags();
652
653 // NOTE(unsafe) We have exclusive access to the regisers
654
655 regs.dtimer()
656 .write(|w| w.set_datatime(data_transfer_timeout));
657 regs.dlenr().write(|w| w.set_datalength(length_bytes));
658
659 regs.idmabase0r().write(|w| w.set_idmabase0(buffer_addr));
660 regs.idmactrlr().modify(|w| w.set_idmaen(true));
661 regs.dctrl().modify(|w| {
662 w.set_dblocksize(block_size);
663 w.set_dtdir(dtdir);
664 });
665 }
666
667 /// Sets the CLKDIV field in CLKCR. Updates clock field in self
668 fn clkcr_set_clkdiv(
669 &self,
670 freq: u32,
671 width: BusWidth,
672 hclk: Hertz,
673 ker_ck: Hertz,
674 clock: &mut Hertz,
675 ) -> Result<(), Error> {
676 let regs = self.0;
677
678 let (clkdiv, new_clock) = clk_div(ker_ck, freq)?;
679 // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7
680 // Section 55.5.8
681 let sdmmc_bus_bandwidth = new_clock.0 * (width as u32);
682 assert!(hclk.0 > 3 * sdmmc_bus_bandwidth / 32);
683 *clock = new_clock;
684
685 // NOTE(unsafe) We have exclusive access to the regblock
686 unsafe {
687 // CPSMACT and DPSMACT must be 0 to set CLKDIV
688 self.wait_idle();
689 regs.clkcr().modify(|w| w.set_clkdiv(clkdiv));
690 }
691
692 Ok(())
693 }
694
695 /// Switch mode using CMD6.
696 ///
697 /// Attempt to set a new signalling mode. The selected
698 /// signalling mode is returned. Expects the current clock
699 /// frequency to be > 12.5MHz.
700 async fn switch_signalling_mode(
701 &self,
702 signalling: Signalling,
703 waker_reg: &AtomicWaker,
704 data_transfer_timeout: u32,
705 ) -> Result<Signalling, Error> {
706 // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not
707 // necessary"
708
709 let set_function = 0x8000_0000
710 | match signalling {
711 // See PLSS v7_10 Table 4-11
712 Signalling::DDR50 => 0xFF_FF04,
713 Signalling::SDR104 => 0xFF_1F03,
714 Signalling::SDR50 => 0xFF_1F02,
715 Signalling::SDR25 => 0xFF_FF01,
716 Signalling::SDR12 => 0xFF_FF00,
717 };
718
719 let mut status = [0u32; 16];
720 let status_addr = &mut status as *mut [u32; 16] as u32;
721
722 // Arm `OnDrop` after the buffer, so it will be dropped first
723 let regs = self.0;
724 let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
725
726 unsafe {
727 self.prepare_datapath_transfer(
728 status_addr,
729 64,
730 6,
731 Dir::CardToHost,
732 data_transfer_timeout,
733 );
734 self.data_interrupts(true);
735 }
736 self.cmd(Cmd::cmd6(set_function), true)?; // CMD6
737
738 let res = poll_fn(|cx| {
739 waker_reg.register(cx.waker());
740 let status = unsafe { regs.star().read() };
741
742 if status.dcrcfail() {
743 return Poll::Ready(Err(Error::Crc));
744 } else if status.dtimeout() {
745 return Poll::Ready(Err(Error::Timeout));
746 } else if status.dataend() {
747 return Poll::Ready(Ok(()));
748 }
749 Poll::Pending
750 })
751 .await;
752 self.clear_interrupt_flags();
753
754 // Host is allowed to use the new functions at least 8
755 // clocks after the end of the switch command
756 // transaction. We know the current clock period is < 80ns,
757 // so a total delay of 640ns is required here
758 for _ in 0..300 {
759 cortex_m::asm::nop();
760 }
761
762 match res {
763 Ok(_) => {
764 on_drop.defuse();
765 unsafe {
766 regs.idmactrlr().modify(|w| w.set_idmaen(false));
767 }
768 // Function Selection of Function Group 1
769 let selection = (u32::from_be(status[4]) >> 24) & 0xF;
770
771 match selection {
772 0 => Ok(Signalling::SDR12),
773 1 => Ok(Signalling::SDR25),
774 2 => Ok(Signalling::SDR50),
775 3 => Ok(Signalling::SDR104),
776 4 => Ok(Signalling::DDR50),
777 _ => Err(Error::UnsupportedCardType),
778 }
779 }
780 Err(e) => Err(e),
781 }
782 }
783
784 /// Query the card status (CMD13, returns R1)
785 ///
786 fn read_status(&self, card: &Card) -> Result<CardStatus, Error> {
787 let regs = self.0;
788 let rca = card.rca;
789
790 self.cmd(Cmd::card_status(rca << 16), false)?; // CMD13
791
792 // NOTE(unsafe) Atomic read with no side-effects
793 let r1 = unsafe { regs.respr(0).read().cardstatus1() };
794 Ok(r1.into())
795 }
796
797 /// Reads the SD Status (ACMD13)
798 async fn read_sd_status(
799 &self,
800 card: &mut Card,
801 waker_reg: &AtomicWaker,
802 data_transfer_timeout: u32,
803 ) -> Result<(), Error> {
804 let rca = card.rca;
805 self.cmd(Cmd::set_block_length(64), false)?; // CMD16
806 self.cmd(Cmd::app_cmd(rca << 16), false)?; // APP
807
808 let mut status = [0u32; 16];
809 let status_addr = &mut status as *mut [u32; 16] as u32;
810
811 // Arm `OnDrop` after the buffer, so it will be dropped first
812 let regs = self.0;
813 let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
814
815 unsafe {
816 self.prepare_datapath_transfer(
817 status_addr,
818 64,
819 6,
820 Dir::CardToHost,
821 data_transfer_timeout,
822 );
823 self.data_interrupts(true);
824 }
825 self.cmd(Cmd::card_status(0), true)?;
826
827 let res = poll_fn(|cx| {
828 waker_reg.register(cx.waker());
829 let status = unsafe { regs.star().read() };
830
831 if status.dcrcfail() {
832 return Poll::Ready(Err(Error::Crc));
833 } else if status.dtimeout() {
834 return Poll::Ready(Err(Error::Timeout));
835 } else if status.dataend() {
836 return Poll::Ready(Ok(()));
837 }
838 Poll::Pending
839 })
840 .await;
841 self.clear_interrupt_flags();
842
843 if res.is_ok() {
844 on_drop.defuse();
845 unsafe {
846 regs.idmactrlr().modify(|w| w.set_idmaen(false));
847 }
848 for byte in status.iter_mut() {
849 *byte = u32::from_be(*byte);
850 }
851 card.status = status.into();
852 }
853 res
854 }
855
856 /// Select one card and place it into the _Tranfer State_
857 ///
858 /// If `None` is specifed for `card`, all cards are put back into
859 /// _Stand-by State_
860 fn select_card(&self, card: Option<&Card>) -> Result<(), Error> {
861 // Determine Relative Card Address (RCA) of given card
862 let rca = card.map(|c| c.rca << 16).unwrap_or(0);
863
864 let r = self.cmd(Cmd::sel_desel_card(rca), false);
865 match (r, rca) {
866 (Err(Error::Timeout), 0) => Ok(()),
867 _ => r,
868 }
869 }
870
871 /// Clear flags in interrupt clear register
872 #[inline(always)]
873 fn clear_interrupt_flags(&self) {
874 let regs = self.0;
875 // NOTE(unsafe) Atomic write
876 unsafe {
877 regs.icr().write(|w| {
878 w.set_ccrcfailc(true);
879 w.set_dcrcfailc(true);
880 w.set_ctimeoutc(true);
881 w.set_dtimeoutc(true);
882 w.set_txunderrc(true);
883 w.set_rxoverrc(true);
884 w.set_cmdrendc(true);
885 w.set_cmdsentc(true);
886 w.set_dataendc(true);
887 w.set_dholdc(true);
888 w.set_dbckendc(true);
889 w.set_dabortc(true);
890 w.set_busyd0endc(true);
891 w.set_sdioitc(true);
892 w.set_ackfailc(true);
893 w.set_acktimeoutc(true);
894 w.set_vswendc(true);
895 w.set_ckstopc(true);
896 w.set_idmatec(true);
897 w.set_idmabtcc(true);
898 });
899 }
900 }
901
902 /// Enables the interrupts for data transfer
903 #[inline(always)]
904 fn data_interrupts(&self, enable: bool) {
905 let regs = self.0;
906 // NOTE(unsafe) Atomic write
907 unsafe {
908 regs.maskr().write(|w| {
909 w.set_dcrcfailie(enable);
910 w.set_dtimeoutie(enable);
911 w.set_dataendie(enable);
912 w.set_dabortie(enable);
913 });
914 }
915 }
916
917 async fn get_scr(
918 &self,
919 card: &mut Card,
920 waker_reg: &AtomicWaker,
921 data_transfer_timeout: u32,
922 ) -> Result<(), Error> {
923 // Read the the 64-bit SCR register
924 self.cmd(Cmd::set_block_length(8), false)?; // CMD16
925 self.cmd(Cmd::app_cmd(card.rca << 16), false)?;
926
927 let mut scr = [0u32; 2];
928 let scr_addr = &mut scr as *mut u32 as u32;
929
930 // Arm `OnDrop` after the buffer, so it will be dropped first
931 let regs = self.0;
932 let on_drop = OnDrop::new(move || unsafe { self.on_drop() });
933
934 unsafe {
935 self.prepare_datapath_transfer(scr_addr, 8, 3, Dir::CardToHost, data_transfer_timeout);
936 self.data_interrupts(true);
937 }
938 self.cmd(Cmd::cmd51(), true)?;
939
940 let res = poll_fn(|cx| {
941 waker_reg.register(cx.waker());
942 let status = unsafe { regs.star().read() };
943
944 if status.dcrcfail() {
945 return Poll::Ready(Err(Error::Crc));
946 } else if status.dtimeout() {
947 return Poll::Ready(Err(Error::Timeout));
948 } else if status.dataend() {
949 return Poll::Ready(Ok(()));
950 }
951 Poll::Pending
952 })
953 .await;
954 self.clear_interrupt_flags();
955
956 if res.is_ok() {
957 on_drop.defuse();
958
959 unsafe {
960 regs.idmactrlr().modify(|w| w.set_idmaen(false));
961 let scr_bytes = &*(&scr as *const [u32; 2] as *const [u8; 8]);
962 card.scr = SCR(u64::from_be_bytes(*scr_bytes));
963 }
964 }
965 res
966 }
967
968 /// Send command to card
969 fn cmd(&self, cmd: Cmd, data: bool) -> Result<(), Error> {
970 let regs = self.0;
971
972 self.clear_interrupt_flags();
973 // NOTE(safety) Atomic operations
974 unsafe {
975 // CP state machine must be idle
976 while regs.star().read().cpsmact() {}
977
978 // Command arg
979 regs.argr().write(|w| w.set_cmdarg(cmd.arg));
980
981 // Special mode in CP State Machine
982 // CMD12: Stop Transmission
983 let cpsm_stop_transmission = cmd.cmd == 12;
984
985 // Command index and start CP State Machine
986 regs.cmdr().write(|w| {
987 w.set_waitint(false);
988 w.set_waitresp(cmd.resp as u8);
989 w.set_cmdstop(cpsm_stop_transmission);
990 w.set_cmdindex(cmd.cmd);
991 w.set_cpsmen(true);
992 w.set_cmdtrans(data);
993 });
994
995 let mut status;
996 if cmd.resp == Response::None {
997 // Wait for CMDSENT or a timeout
998 while {
999 status = regs.star().read();
1000 !(status.ctimeout() || status.cmdsent())
1001 } {}
1002 } else {
1003 // Wait for CMDREND or CCRCFAIL or a timeout
1004 while {
1005 status = regs.star().read();
1006 !(status.ctimeout() || status.cmdrend() || status.ccrcfail())
1007 } {}
1008 }
1009
1010 if status.ctimeout() {
1011 return Err(Error::Timeout);
1012 } else if status.ccrcfail() {
1013 return Err(Error::Crc);
1014 }
1015 Ok(())
1016 }
1017 }
1018
1019 /// # Safety
1020 ///
1021 /// Ensure that `regs` has exclusive access to the regblocks
1022 unsafe fn on_drop(&self) {
1023 let regs = self.0;
1024 if regs.star().read().dpsmact() {
1025 self.clear_interrupt_flags();
1026 // Send abort
1027 // CP state machine must be idle
1028 while regs.star().read().cpsmact() {}
1029
1030 // Command arg
1031 regs.argr().write(|w| w.set_cmdarg(0));
1032
1033 // Command index and start CP State Machine
1034 regs.cmdr().write(|w| {
1035 w.set_waitint(false);
1036 w.set_waitresp(Response::Short as u8);
1037 w.set_cmdstop(true);
1038 w.set_cmdindex(12);
1039 w.set_cpsmen(true);
1040 w.set_cmdtrans(false);
1041 });
1042
1043 // Wait for the abort
1044 while regs.star().read().dpsmact() {}
1045 }
1046 self.data_interrupts(false);
1047 self.clear_interrupt_flags();
1048 regs.idmactrlr().modify(|w| w.set_idmaen(false));
1049 }
1050}
1051
1052/// SD card Commands
1053impl Cmd {
1054 const fn new(cmd: u8, arg: u32, resp: Response) -> Cmd {
1055 Cmd { cmd, arg, resp }
1056 }
1057
1058 /// CMD0: Idle
1059 const fn idle() -> Cmd {
1060 Cmd::new(0, 0, Response::None)
1061 }
1062
1063 /// CMD2: Send CID
1064 const fn all_send_cid() -> Cmd {
1065 Cmd::new(2, 0, Response::Long)
1066 }
1067
1068 /// CMD3: Send Relative Address
1069 const fn send_rel_addr() -> Cmd {
1070 Cmd::new(3, 0, Response::Short)
1071 }
1072
1073 /// CMD6: Switch Function Command
1074 /// ACMD6: Bus Width
1075 const fn cmd6(arg: u32) -> Cmd {
1076 Cmd::new(6, arg, Response::Short)
1077 }
1078
1079 /// CMD7: Select one card and put it into the _Tranfer State_
1080 const fn sel_desel_card(rca: u32) -> Cmd {
1081 Cmd::new(7, rca, Response::Short)
1082 }
1083
1084 /// CMD8:
1085 const fn hs_send_ext_csd(arg: u32) -> Cmd {
1086 Cmd::new(8, arg, Response::Short)
1087 }
1088
1089 /// CMD9:
1090 const fn send_csd(rca: u32) -> Cmd {
1091 Cmd::new(9, rca, Response::Long)
1092 }
1093
1094 /// CMD12:
1095 //const fn stop_transmission() -> Cmd {
1096 // Cmd::new(12, 0, Response::Short)
1097 //}
1098
1099 /// CMD13: Ask card to send status register
1100 /// ACMD13: SD Status
1101 const fn card_status(rca: u32) -> Cmd {
1102 Cmd::new(13, rca, Response::Short)
1103 }
1104
1105 /// CMD16:
1106 const fn set_block_length(blocklen: u32) -> Cmd {
1107 Cmd::new(16, blocklen, Response::Short)
1108 }
1109
1110 /// CMD17: Block Read
1111 const fn read_single_block(addr: u32) -> Cmd {
1112 Cmd::new(17, addr, Response::Short)
1113 }
1114
1115 /// CMD18: Multiple Block Read
1116 //const fn read_multiple_blocks(addr: u32) -> Cmd {
1117 // Cmd::new(18, addr, Response::Short)
1118 //}
1119
1120 /// CMD24: Block Write
1121 const fn write_single_block(addr: u32) -> Cmd {
1122 Cmd::new(24, addr, Response::Short)
1123 }
1124
1125 const fn app_op_cmd(arg: u32) -> Cmd {
1126 Cmd::new(41, arg, Response::Short)
1127 }
1128
1129 const fn cmd51() -> Cmd {
1130 Cmd::new(51, 0, Response::Short)
1131 }
1132
1133 /// App Command. Indicates that next command will be a app command
1134 const fn app_cmd(rca: u32) -> Cmd {
1135 Cmd::new(55, rca, Response::Short)
1136 }
1137}
1138
1139//////////////////////////////////////////////////////
1140
1141pub(crate) mod sealed {
1142 use super::*;
1143
1144 pub trait Instance {
1145 type Interrupt: Interrupt;
1146
1147 fn inner() -> SdmmcInner;
1148 fn state() -> &'static AtomicWaker;
1149 }
1150
1151 pub trait Pins<T: Instance> {}
1152}
1153
1154pub trait Instance: sealed::Instance + 'static {}
1155pin_trait!(CkPin, Instance);
1156pin_trait!(CmdPin, Instance);
1157pin_trait!(D0Pin, Instance);
1158pin_trait!(D1Pin, Instance);
1159pin_trait!(D2Pin, Instance);
1160pin_trait!(D3Pin, Instance);
1161pin_trait!(D4Pin, Instance);
1162pin_trait!(D5Pin, Instance);
1163pin_trait!(D6Pin, Instance);
1164pin_trait!(D7Pin, Instance);
1165
1166pub trait Pins<T: Instance>: sealed::Pins<T> + 'static {
1167 const BUSWIDTH: BusWidth;
1168
1169 fn configure(&mut self);
1170 fn deconfigure(&mut self);
1171}
1172
1173impl<T, CLK, CMD, D0, D1, D2, D3> sealed::Pins<T> for (CLK, CMD, D0, D1, D2, D3)
1174where
1175 T: Instance,
1176 CLK: CkPin<T>,
1177 CMD: CmdPin<T>,
1178 D0: D0Pin<T>,
1179 D1: D1Pin<T>,
1180 D2: D2Pin<T>,
1181 D3: D3Pin<T>,
1182{
1183}
1184
1185impl<T, CLK, CMD, D0> sealed::Pins<T> for (CLK, CMD, D0)
1186where
1187 T: Instance,
1188 CLK: CkPin<T>,
1189 CMD: CmdPin<T>,
1190 D0: D0Pin<T>,
1191{
1192}
1193
1194impl<T, CLK, CMD, D0, D1, D2, D3> Pins<T> for (CLK, CMD, D0, D1, D2, D3)
1195where
1196 T: Instance,
1197 CLK: CkPin<T>,
1198 CMD: CmdPin<T>,
1199 D0: D0Pin<T>,
1200 D1: D1Pin<T>,
1201 D2: D2Pin<T>,
1202 D3: D3Pin<T>,
1203{
1204 const BUSWIDTH: BusWidth = BusWidth::Four;
1205
1206 fn configure(&mut self) {
1207 let (clk_pin, cmd_pin, d0_pin, d1_pin, d2_pin, d3_pin) = self;
1208
1209 critical_section::with(|_| unsafe {
1210 clk_pin.set_as_af_pull(clk_pin.af_num(), AFType::OutputPushPull, Pull::None);
1211 cmd_pin.set_as_af_pull(cmd_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1212 d0_pin.set_as_af_pull(d0_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1213 d1_pin.set_as_af_pull(d1_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1214 d2_pin.set_as_af_pull(d2_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1215 d3_pin.set_as_af_pull(d3_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1216
1217 clk_pin.set_speed(Speed::VeryHigh);
1218 cmd_pin.set_speed(Speed::VeryHigh);
1219 d0_pin.set_speed(Speed::VeryHigh);
1220 d1_pin.set_speed(Speed::VeryHigh);
1221 d2_pin.set_speed(Speed::VeryHigh);
1222 d3_pin.set_speed(Speed::VeryHigh);
1223 });
1224 }
1225
1226 fn deconfigure(&mut self) {
1227 let (clk_pin, cmd_pin, d0_pin, d1_pin, d2_pin, d3_pin) = self;
1228
1229 critical_section::with(|_| unsafe {
1230 clk_pin.set_as_disconnected();
1231 cmd_pin.set_as_disconnected();
1232 d0_pin.set_as_disconnected();
1233 d1_pin.set_as_disconnected();
1234 d2_pin.set_as_disconnected();
1235 d3_pin.set_as_disconnected();
1236 });
1237 }
1238}
1239
1240impl<T, CLK, CMD, D0> Pins<T> for (CLK, CMD, D0)
1241where
1242 T: Instance,
1243 CLK: CkPin<T>,
1244 CMD: CmdPin<T>,
1245 D0: D0Pin<T>,
1246{
1247 const BUSWIDTH: BusWidth = BusWidth::One;
1248
1249 fn configure(&mut self) {
1250 let (clk_pin, cmd_pin, d0_pin) = self;
1251
1252 critical_section::with(|_| unsafe {
1253 clk_pin.set_as_af_pull(clk_pin.af_num(), AFType::OutputPushPull, Pull::None);
1254 cmd_pin.set_as_af_pull(cmd_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1255 d0_pin.set_as_af_pull(d0_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1256
1257 clk_pin.set_speed(Speed::VeryHigh);
1258 cmd_pin.set_speed(Speed::VeryHigh);
1259 d0_pin.set_speed(Speed::VeryHigh);
1260 });
1261 }
1262
1263 fn deconfigure(&mut self) {
1264 let (clk_pin, cmd_pin, d0_pin) = self;
1265
1266 critical_section::with(|_| unsafe {
1267 clk_pin.set_as_disconnected();
1268 cmd_pin.set_as_disconnected();
1269 d0_pin.set_as_disconnected();
1270 });
1271 }
1272}
1273
1274foreach_peripheral!(
1275 (sdmmc, $inst:ident) => {
1276 impl sealed::Instance for peripherals::$inst {
1277 type Interrupt = crate::interrupt::$inst;
1278
1279 fn inner() -> SdmmcInner {
1280 const INNER: SdmmcInner = SdmmcInner(crate::pac::$inst);
1281 INNER
1282 }
1283
1284 fn state() -> &'static ::embassy::waitqueue::AtomicWaker {
1285 static WAKER: ::embassy::waitqueue::AtomicWaker = ::embassy::waitqueue::AtomicWaker::new();
1286 &WAKER
1287 }
1288 }
1289
1290 impl Instance for peripherals::$inst {}
1291 };
1292);
1293
1294#[cfg(feature = "sdmmc-rs")]
1295mod sdmmc_rs {
1296 use super::*;
1297 use core::future::Future;
1298 use embedded_sdmmc::{Block, BlockCount, BlockDevice, BlockIdx};
1299
1300 impl<'d, T: Instance, P: Pins<T>> BlockDevice for Sdmmc<'d, T, P> {
1301 type Error = Error;
1302 type ReadFuture<'a>
1303 where
1304 Self: 'a,
1305 = impl Future<Output = Result<(), Self::Error>> + 'a;
1306 type WriteFuture<'a>
1307 where
1308 Self: 'a,
1309 = impl Future<Output = Result<(), Self::Error>> + 'a;
1310
1311 fn read<'a>(
1312 &'a mut self,
1313 blocks: &'a mut [Block],
1314 start_block_idx: BlockIdx,
1315 _reason: &str,
1316 ) -> Self::ReadFuture<'a> {
1317 async move {
1318 let card_capacity = self.card()?.card_type;
1319 let inner = T::inner();
1320 let state = T::state();
1321 let mut address = start_block_idx.0;
1322
1323 for block in blocks.iter_mut() {
1324 let block: &mut [u8; 512] = &mut block.contents;
1325
1326 // NOTE(unsafe) Block uses align(4)
1327 let buf = unsafe { &mut *(block as *mut [u8; 512] as *mut [u32; 128]) };
1328 inner
1329 .read_block(
1330 address,
1331 buf,
1332 card_capacity,
1333 state,
1334 self.config.data_transfer_timeout,
1335 )
1336 .await?;
1337 address += 1;
1338 }
1339 Ok(())
1340 }
1341 }
1342
1343 fn write<'a>(
1344 &'a mut self,
1345 blocks: &'a [Block],
1346 start_block_idx: BlockIdx,
1347 ) -> Self::WriteFuture<'a> {
1348 async move {
1349 let card = self.card.as_mut().ok_or(Error::NoCard)?;
1350 let inner = T::inner();
1351 let state = T::state();
1352 let mut address = start_block_idx.0;
1353
1354 for block in blocks.iter() {
1355 let block: &[u8; 512] = &block.contents;
1356
1357 // NOTE(unsafe) DataBlock uses align 4
1358 let buf = unsafe { &*(block as *const [u8; 512] as *const [u32; 128]) };
1359 inner
1360 .write_block(address, buf, card, state, self.config.data_transfer_timeout)
1361 .await?;
1362 address += 1;
1363 }
1364 Ok(())
1365 }
1366 }
1367
1368 fn num_blocks(&self) -> Result<BlockCount, Self::Error> {
1369 let card = self.card()?;
1370 let count = card.csd.block_count();
1371 Ok(BlockCount(count))
1372 }
1373 }
1374}
diff --git a/stm32-data b/stm32-data
Subproject d3e8a2fe63eeb403102559f3f9917d9fcf27e1a Subproject 9a23a90cc038ce657611770d919c26e89719d1f