aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThales Fragoso <[email protected]>2021-05-11 01:28:45 -0300
committerThales Fragoso <[email protected]>2021-05-14 23:42:12 -0300
commitc183c352c747bb418f5ed4553645c82ab2be3dbf (patch)
tree595d3538f3327ff932931a73a8d1b9d60aa00d0a
parent490152d02892ed7478c3920a2eb7373af66be90f (diff)
SDMMC: Implement read and write
-rw-r--r--embassy-stm32/src/sdmmc_v2.rs185
1 files changed, 154 insertions, 31 deletions
diff --git a/embassy-stm32/src/sdmmc_v2.rs b/embassy-stm32/src/sdmmc_v2.rs
index a3094f691..182add6f6 100644
--- a/embassy-stm32/src/sdmmc_v2.rs
+++ b/embassy-stm32/src/sdmmc_v2.rs
@@ -1,5 +1,5 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2use core::task::{Context, Poll}; 2use core::task::Poll;
3 3
4use embassy::interrupt::InterruptExt; 4use embassy::interrupt::InterruptExt;
5use embassy::util::{AtomicWaker, OnDrop, Unborrow}; 5use embassy::util::{AtomicWaker, OnDrop, Unborrow};
@@ -10,7 +10,7 @@ use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID,
10use crate::fmt::*; 10use crate::fmt::*;
11use crate::pac; 11use crate::pac;
12use crate::pac::gpio::Gpio; 12use crate::pac::gpio::Gpio;
13use crate::pac::interrupt::{Interrupt, InterruptEnum}; 13use crate::pac::interrupt::Interrupt;
14use crate::pac::sdmmc::Sdmmc as RegBlock; 14use crate::pac::sdmmc::Sdmmc as RegBlock;
15use crate::time::Hertz; 15use crate::time::Hertz;
16 16
@@ -32,6 +32,9 @@ impl Default for Signalling {
32 } 32 }
33} 33}
34 34
35#[repr(align(4))]
36pub struct DataBlock([u8; 512]);
37
35/// Errors 38/// Errors
36#[non_exhaustive] 39#[non_exhaustive]
37#[derive(Debug, Copy, Clone)] 40#[derive(Debug, Copy, Clone)]
@@ -201,16 +204,43 @@ impl<'d, T: Instance, P: Pins<T>> Sdmmc<'d, T, P> {
201 .await 204 .await
202 } 205 }
203 206
207 #[inline(always)]
208 pub async fn read_block(
209 &mut self,
210 block_idx: u32,
211 buffer: &mut DataBlock,
212 ) -> Result<(), Error> {
213 let card_capacity = self.card()?.card_type;
214 let inner = T::inner();
215 let state = T::state();
216
217 // NOTE(unsafe) DataBlock uses align 4
218 let buf = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) };
219 inner.read_block(block_idx, buf, card_capacity, state).await
220 }
221
222 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> {
223 let card = self.card.as_mut().ok_or(Error::NoCard)?;
224 let inner = T::inner();
225 let state = T::state();
226
227 // NOTE(unsafe) DataBlock uses align 4
228 let buf = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) };
229 inner.write_block(block_idx, buf, card, state).await
230 }
231
204 /// Get a reference to the initialized card 232 /// Get a reference to the initialized card
205 /// 233 ///
206 /// # Errors 234 /// # Errors
207 /// 235 ///
208 /// Returns Error::NoCard if [`init_card`](#method.init_card) 236 /// Returns Error::NoCard if [`init_card`](#method.init_card)
209 /// has not previously succeeded 237 /// has not previously succeeded
238 #[inline(always)]
210 pub fn card(&self) -> Result<&Card, Error> { 239 pub fn card(&self) -> Result<&Card, Error> {
211 self.card.as_ref().ok_or(Error::NoCard) 240 self.card.as_ref().ok_or(Error::NoCard)
212 } 241 }
213 242
243 #[inline(always)]
214 fn on_interrupt(_: *mut ()) { 244 fn on_interrupt(_: *mut ()) {
215 let regs = T::inner(); 245 let regs = T::inner();
216 let state = T::state(); 246 let state = T::state();
@@ -260,7 +290,7 @@ impl SdmmcInner {
260 /// Initializes card (if present) and sets the bus at the 290 /// Initializes card (if present) and sets the bus at the
261 /// specified frequency. 291 /// specified frequency.
262 #[allow(clippy::too_many_arguments)] 292 #[allow(clippy::too_many_arguments)]
263 pub async fn init_card( 293 async fn init_card(
264 &self, 294 &self,
265 freq: Hertz, 295 freq: Hertz,
266 bus_width: BusWidth, 296 bus_width: BusWidth,
@@ -397,8 +427,120 @@ impl SdmmcInner {
397 Ok(()) 427 Ok(())
398 } 428 }
399 429
400 async fn read_block(&mut self, block_idx: u32, buffer: &mut [u32; 128]) -> Result<(), Error> { 430 async fn read_block(
401 self::todo!() 431 &self,
432 block_idx: u32,
433 buffer: &mut [u32; 128],
434 capacity: CardCapacity,
435 waker_reg: &AtomicWaker,
436 ) -> Result<(), Error> {
437 // Always read 1 block of 512 bytes
438 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
439 let address = match capacity {
440 CardCapacity::SDSC => block_idx * 512,
441 _ => block_idx,
442 };
443 self.cmd(Cmd::set_block_length(512), false)?; // CMD16
444
445 let regs = self.0;
446 let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
447
448 let buf_addr = buffer as *mut [u32; 128] as u32;
449 unsafe {
450 self.prepare_datapath_transfer(buf_addr, 512, 9, Dir::CardToHost);
451 self.data_interrupts(true);
452 }
453 self.cmd(Cmd::read_single_block(address), true)?;
454
455 let res = poll_fn(|cx| {
456 waker_reg.register(cx.waker());
457 let status = unsafe { regs.star().read() };
458
459 if status.dcrcfail() {
460 return Poll::Ready(Err(Error::Crc));
461 } else if status.dtimeout() {
462 return Poll::Ready(Err(Error::Timeout));
463 } else if status.dataend() {
464 return Poll::Ready(Ok(()));
465 }
466 Poll::Pending
467 })
468 .await;
469 self.clear_interrupt_flags();
470
471 if res.is_ok() {
472 on_drop.defuse();
473 unsafe {
474 regs.idmactrlr().modify(|w| w.set_idmaen(false));
475 }
476 }
477 res
478 }
479
480 async fn write_block(
481 &self,
482 block_idx: u32,
483 buffer: &[u32; 128],
484 card: &mut Card,
485 waker_reg: &AtomicWaker,
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 card.card_type {
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 *const [u32; 128] as u32;
499 unsafe {
500 self.prepare_datapath_transfer(buf_addr, 512, 9, Dir::HostToCard);
501 self.data_interrupts(true);
502 }
503 self.cmd(Cmd::write_single_block(address), true)?;
504
505 let res = poll_fn(|cx| {
506 waker_reg.register(cx.waker());
507 let status = unsafe { regs.star().read() };
508
509 if status.dcrcfail() {
510 return Poll::Ready(Err(Error::Crc));
511 } else if status.dtimeout() {
512 return Poll::Ready(Err(Error::Timeout));
513 } else if status.dataend() {
514 return Poll::Ready(Ok(()));
515 }
516 Poll::Pending
517 })
518 .await;
519 self.clear_interrupt_flags();
520
521 match res {
522 Ok(_) => {
523 on_drop.defuse();
524 unsafe {
525 regs.idmactrlr().modify(|w| w.set_idmaen(false));
526 }
527 // TODO: Make this configurable
528 let mut timeout: u32 = 0xFFFF_FFFF;
529
530 // Try to read card status (ACMD13)
531 while timeout > 0 {
532 match self.read_sd_status(card, waker_reg).await {
533 Ok(_) => return Ok(()),
534 Err(Error::Timeout) => (), // Try again
535 Err(e) => return Err(e),
536 }
537
538 timeout -= 1;
539 }
540 Err(Error::SoftwareTimeout)
541 }
542 Err(e) => Err(e),
543 }
402 } 544 }
403 545
404 /// Get the current SDMMC bus clock 546 /// Get the current SDMMC bus clock
@@ -795,32 +937,13 @@ impl SdmmcInner {
795 } 937 }
796 } 938 }
797 939
798 fn store_waker_and_unmask(
799 &self,
800 cx: &Context,
801 interrupt_sdmmc1: bool,
802 waker_reg: &AtomicWaker,
803 ) {
804 use cortex_m::peripheral::NVIC;
805
806 // NOTE(unsafe) We own the interrupt and can unmask it, it won't cause unsoundness
807 unsafe {
808 if interrupt_sdmmc1 {
809 waker_reg.register(cx.waker());
810 NVIC::unmask(InterruptEnum::SDMMC1);
811 } else {
812 waker_reg.register(cx.waker());
813 NVIC::unmask(InterruptEnum::SDMMC2);
814 }
815 }
816 }
817
818 /// # Safety 940 /// # Safety
819 /// 941 ///
820 /// Ensure that `regs` has exclusive access to the regblocks 942 /// Ensure that `regs` has exclusive access to the regblocks
821 unsafe fn on_drop(&self) { 943 unsafe fn on_drop(&self) {
822 let regs = self.0; 944 let regs = self.0;
823 if regs.star().read().dpsmact() { 945 if regs.star().read().dpsmact() {
946 self.clear_interrupt_flags();
824 // Send abort 947 // Send abort
825 // CP state machine must be idle 948 // CP state machine must be idle
826 while regs.star().read().cpsmact() {} 949 while regs.star().read().cpsmact() {}
@@ -890,9 +1013,9 @@ impl Cmd {
890 } 1013 }
891 1014
892 /// CMD12: 1015 /// CMD12:
893 const fn stop_transmission() -> Cmd { 1016 //const fn stop_transmission() -> Cmd {
894 Cmd::new(12, 0, Response::Short) 1017 // Cmd::new(12, 0, Response::Short)
895 } 1018 //}
896 1019
897 /// CMD13: Ask card to send status register 1020 /// CMD13: Ask card to send status register
898 /// ACMD13: SD Status 1021 /// ACMD13: SD Status
@@ -911,9 +1034,9 @@ impl Cmd {
911 } 1034 }
912 1035
913 /// CMD18: Multiple Block Read 1036 /// CMD18: Multiple Block Read
914 const fn read_multiple_blocks(addr: u32) -> Cmd { 1037 //const fn read_multiple_blocks(addr: u32) -> Cmd {
915 Cmd::new(18, addr, Response::Short) 1038 // Cmd::new(18, addr, Response::Short)
916 } 1039 //}
917 1040
918 /// CMD24: Block Write 1041 /// CMD24: Block Write
919 const fn write_single_block(addr: u32) -> Cmd { 1042 const fn write_single_block(addr: u32) -> Cmd {