From 3b0b7d71554054c9ad7a7e263b938f9fe6ce1e09 Mon Sep 17 00:00:00 2001 From: Oliver <18360865+ost-ing@users.noreply.github.com> Date: Tue, 4 Feb 2025 12:15:22 +1100 Subject: [PATCH 1/5] multiple block writes --- embassy-stm32/src/sdmmc/mod.rs | 101 +++++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index ed344c4128..1e19161c28 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -1322,6 +1322,90 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { } } + /// Write multiple data blocks. + pub async fn write_blocks(&mut self, block_idx: u32, blocks: &[DataBlock]) -> Result<(), Error> { + let card = self.card.as_mut().ok_or(Error::NoCard)?; + + // NOTE(unsafe) reinterpret buffer as &[u32] + let buffer = unsafe { + let ptr = blocks.as_ptr() as *const u32; + let len = blocks.len() * 128; + core::slice::from_raw_parts(ptr, len) + }; + + // Always read 1 block of 512 bytes + // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes + let address = match card.card_type { + CardCapacity::SDSC => block_idx * 512, + _ => block_idx, + }; + + Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 + + let block_count = blocks.len(); + + let regs = T::regs(); + let on_drop = OnDrop::new(|| Self::on_drop()); + + #[cfg(sdmmc_v1)] + Self::cmd(Cmd::write_multiple_blocks(address), true)?; // CMD25 + + // Setup write command + let transfer = self.prepare_datapath_write(buffer, 512 * block_count as u32, 9); + InterruptHandler::::data_interrupts(true); + + #[cfg(sdmmc_v2)] + Self::cmd(Cmd::write_multiple_blocks(address), true)?; // CMD25 + + let res = poll_fn(|cx| { + T::state().register(cx.waker()); + let status = regs.star().read(); + + if status.dcrcfail() { + return Poll::Ready(Err(Error::Crc)); + } + if status.dtimeout() { + return Poll::Ready(Err(Error::Timeout)); + } + // if status.d + #[cfg(sdmmc_v1)] + if status.stbiterr() { + return Poll::Ready(Err(Error::StBitErr)); + } + if status.dataend() { + return Poll::Ready(Ok(())); + } + Poll::Pending + }) + .await; + + Self::cmd(Cmd::stop_transmission(), false)?; // CMD12 + Self::clear_interrupt_flags(); + + match res { + Ok(_) => { + on_drop.defuse(); + Self::stop_datapath(); + drop(transfer); + + // TODO: Make this configurable + let mut timeout: u32 = 0x00FF_FFFF; + + // Try to read card status (ACMD13) + while timeout > 0 { + match self.read_sd_status().await { + Ok(_) => return Ok(()), + Err(Error::Timeout) => (), // Try again + Err(e) => return Err(e), + } + timeout -= 1; + } + Err(Error::SoftwareTimeout) + } + Err(e) => Err(e), + } + } + /// Get a reference to the initialized card /// /// # Errors @@ -1412,9 +1496,9 @@ impl Cmd { } /// CMD12: - //const fn stop_transmission() -> Cmd { - // Cmd::new(12, 0, Response::Short) - //} + const fn stop_transmission() -> Cmd { + Cmd::new(12, 0, Response::Short) + } /// CMD13: Ask card to send status register /// ACMD13: SD Status @@ -1433,15 +1517,20 @@ impl Cmd { } /// CMD18: Multiple Block Read - //const fn read_multiple_blocks(addr: u32) -> Cmd { - // Cmd::new(18, addr, Response::Short) - //} + const fn read_multiple_blocks(addr: u32) -> Cmd { + Cmd::new(18, addr, Response::Short) + } /// CMD24: Block Write const fn write_single_block(addr: u32) -> Cmd { Cmd::new(24, addr, Response::Short) } + /// CMD25: Multiple Block Write + const fn write_multiple_blocks(addr: u32) -> Cmd { + Cmd::new(25, addr, Response::Short) + } + const fn app_op_cmd(arg: u32) -> Cmd { Cmd::new(41, arg, Response::Short) } From dc468c88df703a56e4522795f1e6d3834376f405 Mon Sep 17 00:00:00 2001 From: Oliver <18360865+ost-ing@users.noreply.github.com> Date: Tue, 4 Feb 2025 12:26:59 +1100 Subject: [PATCH 2/5] multiple block reads --- embassy-stm32/src/sdmmc/mod.rs | 60 ++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 1e19161c28..6038ec0e68 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -1248,6 +1248,66 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { res } + /// Read multiple data blocks. + #[inline] + pub async fn read_blocks(&mut self, block_idx: u32, blocks: &mut [DataBlock]) -> Result<(), Error> { + let card_capacity = self.card()?.card_type; + + // NOTE(unsafe) reinterpret buffer as &mut [u32] + let buffer = unsafe { + let ptr = blocks.as_mut_ptr() as *mut u32; + let len = blocks.len() * 128; + core::slice::from_raw_parts_mut(ptr, len) + }; + + // Always read 1 block of 512 bytes + // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes + let address = match card_capacity { + CardCapacity::SDSC => block_idx * 512, + _ => block_idx, + }; + Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 + + let regs = T::regs(); + let on_drop = OnDrop::new(|| Self::on_drop()); + + let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, buffer, 512 * blocks.len() as u32, 9); + InterruptHandler::::data_interrupts(true); + + Self::cmd(Cmd::read_multiple_blocks(address), true)?; + + let res = poll_fn(|cx| { + T::state().register(cx.waker()); + let status = regs.star().read(); + + if status.dcrcfail() { + return Poll::Ready(Err(Error::Crc)); + } + if status.dtimeout() { + return Poll::Ready(Err(Error::Timeout)); + } + #[cfg(sdmmc_v1)] + if status.stbiterr() { + return Poll::Ready(Err(Error::StBitErr)); + } + if status.dataend() { + return Poll::Ready(Ok(())); + } + Poll::Pending + }) + .await; + + Self::cmd(Cmd::stop_transmission(), false)?; // CMD12 + Self::clear_interrupt_flags(); + + if res.is_ok() { + on_drop.defuse(); + Self::stop_datapath(); + drop(transfer); + } + res + } + /// Write a data block. pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { let card = self.card.as_mut().ok_or(Error::NoCard)?; From 4e3bd1e4cc5bcafcd380de7f5c587eb18acdf96f Mon Sep 17 00:00:00 2001 From: Oliver <18360865+ost-ing@users.noreply.github.com> Date: Tue, 4 Feb 2025 12:43:51 +1100 Subject: [PATCH 3/5] device_block_driver uses multiple block read/writes --- embassy-stm32/src/sdmmc/mod.rs | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 6038ec0e68..cddcdeec81 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -1667,33 +1667,35 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> block_device_driver::BlockDevice<51 async fn read( &mut self, - mut block_address: u32, + block_address: u32, buf: &mut [aligned::Aligned], ) -> Result<(), Self::Error> { - // FIXME/TODO because of missing read_blocks multiple we have to do this one block at a time - for block in buf.iter_mut() { - // safety aligned by block device - let block = unsafe { &mut *(block as *mut _ as *mut crate::sdmmc::DataBlock) }; + // TODO: I think block_address needs to be adjusted by the partition start offset + if buf.len() == 1 { + let block = unsafe { &mut *(&mut buf[0] as *mut _ as *mut crate::sdmmc::DataBlock) }; self.read_block(block_address, block).await?; - block_address += 1; + } else { + let blocks: &mut [DataBlock] = + unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut DataBlock, buf.len()) }; + self.read_blocks(block_address, blocks).await?; } - Ok(()) } async fn write( &mut self, - mut block_address: u32, + block_address: u32, buf: &[aligned::Aligned], ) -> Result<(), Self::Error> { - // FIXME/TODO because of missing read_blocks multiple we have to do this one block at a time - for block in buf.iter() { - // safety aligned by block device - let block = unsafe { &*(block as *const _ as *const crate::sdmmc::DataBlock) }; + // TODO: I think block_address needs to be adjusted by the partition start offset + if buf.len() == 1 { + let block = unsafe { &*(&buf[0] as *const _ as *const crate::sdmmc::DataBlock) }; self.write_block(block_address, block).await?; - block_address += 1; + } else { + let blocks: &[DataBlock] = + unsafe { core::slice::from_raw_parts(buf.as_ptr() as *const DataBlock, buf.len()) }; + self.write_blocks(block_address, blocks).await?; } - Ok(()) } From 251315183fa1d02c694637300719206ae9f6dd8f Mon Sep 17 00:00:00 2001 From: Oliver <18360865+ost-ing@users.noreply.github.com> Date: Tue, 4 Feb 2025 12:57:27 +1100 Subject: [PATCH 4/5] add tests --- tests/stm32/src/bin/sdmmc.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/stm32/src/bin/sdmmc.rs b/tests/stm32/src/bin/sdmmc.rs index a6bc117c01..c54d699444 100644 --- a/tests/stm32/src/bin/sdmmc.rs +++ b/tests/stm32/src/bin/sdmmc.rs @@ -36,6 +36,7 @@ async fn main(_spawner: Spawner) { } let mut block = DataBlock([0u8; 512]); + let mut blocks = [DataBlock([0u8; 512]), DataBlock([0u8; 512])]; // ======== Try 4bit. ============== info!("initializing in 4-bit mode..."); @@ -84,6 +85,13 @@ async fn main(_spawner: Spawner) { s.read_block(block_idx, &mut block).await.unwrap(); assert_eq!(block, pattern2); + info!("writing blocks [pattern1, pattern2]..."); + s.write_blocks(block_idx, [pattern1, pattern2]).await.unwrap(); + + info!("reading blocks..."); + s.read_blocks(block_idx, &mut blocks).await.unwrap(); + assert_eq!(blocks, [pattern1, pattern2]); + drop(s); // ======== Try 1bit. ============== @@ -134,6 +142,13 @@ async fn main(_spawner: Spawner) { s.read_block(block_idx, &mut block).await.unwrap(); assert_eq!(block, pattern2); + info!("writing blocks [pattern1, pattern2]..."); + s.write_blocks(block_idx, [pattern1, pattern2]).await.unwrap(); + + info!("reading blocks..."); + s.read_blocks(block_idx, &mut blocks).await.unwrap(); + assert_eq!(blocks, [pattern1, pattern2]); + drop(s); info!("Test OK"); From ae7eafbe9f9e1bb589ce024f37239fcfe7f1fea9 Mon Sep 17 00:00:00 2001 From: Oliver <18360865+ost-ing@users.noreply.github.com> Date: Tue, 4 Feb 2025 21:30:52 +1100 Subject: [PATCH 5/5] fix tests --- tests/stm32/src/bin/sdmmc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/stm32/src/bin/sdmmc.rs b/tests/stm32/src/bin/sdmmc.rs index c54d699444..ca392abdfb 100644 --- a/tests/stm32/src/bin/sdmmc.rs +++ b/tests/stm32/src/bin/sdmmc.rs @@ -86,7 +86,7 @@ async fn main(_spawner: Spawner) { assert_eq!(block, pattern2); info!("writing blocks [pattern1, pattern2]..."); - s.write_blocks(block_idx, [pattern1, pattern2]).await.unwrap(); + s.write_blocks(block_idx, &[pattern1, pattern2]).await.unwrap(); info!("reading blocks..."); s.read_blocks(block_idx, &mut blocks).await.unwrap(); @@ -143,7 +143,7 @@ async fn main(_spawner: Spawner) { assert_eq!(block, pattern2); info!("writing blocks [pattern1, pattern2]..."); - s.write_blocks(block_idx, [pattern1, pattern2]).await.unwrap(); + s.write_blocks(block_idx, &[pattern1, pattern2]).await.unwrap(); info!("reading blocks..."); s.read_blocks(block_idx, &mut blocks).await.unwrap();