aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver <[email protected]>2025-02-04 12:15:22 +1100
committerDario Nieuwenhuis <[email protected]>2025-04-18 14:21:29 +0200
commiteb83d049c7fe1919b435878012de5da886e9fc62 (patch)
tree0d26acf1b4432b5fcf20039516b8259b6cb7c980
parent7a620661da85c0a4b550abbde7df7e248fe0f155 (diff)
stm32/sdmmc: add support for multiple block reads and writes.
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs192
-rw-r--r--tests/stm32/src/bin/sdmmc.rs20
2 files changed, 195 insertions, 17 deletions
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index 63868e5ae..6a02aae70 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -151,6 +151,8 @@ pub enum Error {
151 BadClock, 151 BadClock,
152 /// Signaling switch failed. 152 /// Signaling switch failed.
153 SignalingSwitchFailed, 153 SignalingSwitchFailed,
154 /// Underrun error
155 Underrun,
154 /// ST bit error. 156 /// ST bit error.
155 #[cfg(sdmmc_v1)] 157 #[cfg(sdmmc_v1)]
156 StBitErr, 158 StBitErr,
@@ -1025,6 +1027,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
1025 if status.dtimeout() { 1027 if status.dtimeout() {
1026 return Poll::Ready(Err(Error::Timeout)); 1028 return Poll::Ready(Err(Error::Timeout));
1027 } 1029 }
1030 if status.txunderr() {
1031 return Poll::Ready(Err(Error::Underrun));
1032 }
1028 #[cfg(sdmmc_v1)] 1033 #[cfg(sdmmc_v1)]
1029 if status.stbiterr() { 1034 if status.stbiterr() {
1030 return Poll::Ready(Err(Error::StBitErr)); 1035 return Poll::Ready(Err(Error::StBitErr));
@@ -1080,6 +1085,73 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
1080 res 1085 res
1081 } 1086 }
1082 1087
1088 /// Read multiple data blocks.
1089 #[inline]
1090 pub async fn read_blocks(&mut self, block_idx: u32, blocks: &mut [DataBlock]) -> Result<(), Error> {
1091 let card_capacity = self.card()?.get_capacity();
1092
1093 // NOTE(unsafe) reinterpret buffer as &mut [u32]
1094 let buffer = unsafe {
1095 let ptr = blocks.as_mut_ptr() as *mut u32;
1096 let len = blocks.len() * 128;
1097 core::slice::from_raw_parts_mut(ptr, len)
1098 };
1099
1100 // Always read 1 block of 512 bytes
1101 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
1102 let address = match card_capacity {
1103 CardCapacity::StandardCapacity => block_idx * 512,
1104 _ => block_idx,
1105 };
1106 Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16
1107
1108 let regs = T::regs();
1109 let on_drop = OnDrop::new(|| Self::on_drop());
1110
1111 let transfer = Self::prepare_datapath_read(
1112 &self.config,
1113 #[cfg(sdmmc_v1)]
1114 &mut self.dma,
1115 buffer,
1116 512 * blocks.len() as u32,
1117 9,
1118 );
1119 InterruptHandler::<T>::data_interrupts(true);
1120
1121 Self::cmd(common_cmd::read_multiple_blocks(address), true)?;
1122
1123 let res = poll_fn(|cx| {
1124 T::state().register(cx.waker());
1125 let status = regs.star().read();
1126
1127 if status.dcrcfail() {
1128 return Poll::Ready(Err(Error::Crc));
1129 }
1130 if status.dtimeout() {
1131 return Poll::Ready(Err(Error::Timeout));
1132 }
1133 #[cfg(sdmmc_v1)]
1134 if status.stbiterr() {
1135 return Poll::Ready(Err(Error::StBitErr));
1136 }
1137 if status.dataend() {
1138 return Poll::Ready(Ok(()));
1139 }
1140 Poll::Pending
1141 })
1142 .await;
1143
1144 Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12
1145 Self::clear_interrupt_flags();
1146
1147 if res.is_ok() {
1148 on_drop.defuse();
1149 Self::stop_datapath();
1150 drop(transfer);
1151 }
1152 res
1153 }
1154
1083 /// Write a data block. 1155 /// Write a data block.
1084 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { 1156 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> {
1085 let card = self.card.as_mut().ok_or(Error::NoCard)?; 1157 let card = self.card.as_mut().ok_or(Error::NoCard)?;
@@ -1088,7 +1160,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
1088 let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) }; 1160 let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) };
1089 1161
1090 // Always read 1 block of 512 bytes 1162 // Always read 1 block of 512 bytes
1091 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes 1163 // cards are byte addressed hence the blockaddress is in multiples of 512 bytes
1092 let address = match card.get_capacity() { 1164 let address = match card.get_capacity() {
1093 CardCapacity::StandardCapacity => block_idx * 512, 1165 CardCapacity::StandardCapacity => block_idx * 512,
1094 _ => block_idx, 1166 _ => block_idx,
@@ -1136,6 +1208,94 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
1136 } 1208 }
1137 } 1209 }
1138 1210
1211 /// Write multiple data blocks.
1212 pub async fn write_blocks(&mut self, block_idx: u32, blocks: &[DataBlock]) -> Result<(), Error> {
1213 let card = self.card.as_mut().ok_or(Error::NoCard)?;
1214
1215 // NOTE(unsafe) reinterpret buffer as &[u32]
1216 let buffer = unsafe {
1217 let ptr = blocks.as_ptr() as *const u32;
1218 let len = blocks.len() * 128;
1219 core::slice::from_raw_parts(ptr, len)
1220 };
1221
1222 // Always read 1 block of 512 bytes
1223 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
1224 let address = match card.get_capacity() {
1225 CardCapacity::StandardCapacity => block_idx * 512,
1226 _ => block_idx,
1227 };
1228
1229 Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16
1230
1231 let block_count = blocks.len();
1232
1233 let regs = T::regs();
1234 let on_drop = OnDrop::new(|| Self::on_drop());
1235
1236 #[cfg(sdmmc_v1)]
1237 Self::cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25
1238
1239 // Setup write command
1240 let transfer = self.prepare_datapath_write(buffer, 512 * block_count as u32, 9);
1241 InterruptHandler::<T>::data_interrupts(true);
1242
1243 #[cfg(sdmmc_v2)]
1244 Self::cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25
1245
1246 let res = poll_fn(|cx| {
1247 T::state().register(cx.waker());
1248
1249 let status = regs.star().read();
1250
1251 if status.dcrcfail() {
1252 return Poll::Ready(Err(Error::Crc));
1253 }
1254 if status.dtimeout() {
1255 return Poll::Ready(Err(Error::Timeout));
1256 }
1257 if status.txunderr() {
1258 return Poll::Ready(Err(Error::Underrun));
1259 }
1260 #[cfg(sdmmc_v1)]
1261 if status.stbiterr() {
1262 return Poll::Ready(Err(Error::StBitErr));
1263 }
1264 if status.dataend() {
1265 return Poll::Ready(Ok(()));
1266 }
1267
1268 Poll::Pending
1269 })
1270 .await;
1271
1272 Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12
1273 Self::clear_interrupt_flags();
1274
1275 match res {
1276 Ok(_) => {
1277 on_drop.defuse();
1278 Self::stop_datapath();
1279 drop(transfer);
1280
1281 // TODO: Make this configurable
1282 let mut timeout: u32 = 0x00FF_FFFF;
1283
1284 // Try to read card status (ACMD13)
1285 while timeout > 0 {
1286 match self.read_sd_status().await {
1287 Ok(_) => return Ok(()),
1288 Err(Error::Timeout) => (), // Try again
1289 Err(e) => return Err(e),
1290 }
1291 timeout -= 1;
1292 }
1293 Err(Error::SoftwareTimeout)
1294 }
1295 Err(e) => Err(e),
1296 }
1297 }
1298
1139 /// Get a reference to the initialized card 1299 /// Get a reference to the initialized card
1140 /// 1300 ///
1141 /// # Errors 1301 /// # Errors
@@ -1699,33 +1859,35 @@ impl<'d, T: Instance> block_device_driver::BlockDevice<512> for Sdmmc<'d, T> {
1699 1859
1700 async fn read( 1860 async fn read(
1701 &mut self, 1861 &mut self,
1702 mut block_address: u32, 1862 block_address: u32,
1703 buf: &mut [aligned::Aligned<Self::Align, [u8; 512]>], 1863 buf: &mut [aligned::Aligned<Self::Align, [u8; 512]>],
1704 ) -> Result<(), Self::Error> { 1864 ) -> Result<(), Self::Error> {
1705 // FIXME/TODO because of missing read_blocks multiple we have to do this one block at a time 1865 // TODO: I think block_address needs to be adjusted by the partition start offset
1706 for block in buf.iter_mut() { 1866 if buf.len() == 1 {
1707 // safety aligned by block device 1867 let block = unsafe { &mut *(&mut buf[0] as *mut _ as *mut crate::sdmmc::DataBlock) };
1708 let block = unsafe { &mut *(block as *mut _ as *mut crate::sdmmc::DataBlock) };
1709 self.read_block(block_address, block).await?; 1868 self.read_block(block_address, block).await?;
1710 block_address += 1; 1869 } else {
1870 let blocks: &mut [DataBlock] =
1871 unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut DataBlock, buf.len()) };
1872 self.read_blocks(block_address, blocks).await?;
1711 } 1873 }
1712
1713 Ok(()) 1874 Ok(())
1714 } 1875 }
1715 1876
1716 async fn write( 1877 async fn write(
1717 &mut self, 1878 &mut self,
1718 mut block_address: u32, 1879 block_address: u32,
1719 buf: &[aligned::Aligned<Self::Align, [u8; 512]>], 1880 buf: &[aligned::Aligned<Self::Align, [u8; 512]>],
1720 ) -> Result<(), Self::Error> { 1881 ) -> Result<(), Self::Error> {
1721 // FIXME/TODO because of missing read_blocks multiple we have to do this one block at a time 1882 // TODO: I think block_address needs to be adjusted by the partition start offset
1722 for block in buf.iter() { 1883 if buf.len() == 1 {
1723 // safety aligned by block device 1884 let block = unsafe { &*(&buf[0] as *const _ as *const crate::sdmmc::DataBlock) };
1724 let block = unsafe { &*(block as *const _ as *const crate::sdmmc::DataBlock) };
1725 self.write_block(block_address, block).await?; 1885 self.write_block(block_address, block).await?;
1726 block_address += 1; 1886 } else {
1887 let blocks: &[DataBlock] =
1888 unsafe { core::slice::from_raw_parts(buf.as_ptr() as *const DataBlock, buf.len()) };
1889 self.write_blocks(block_address, blocks).await?;
1727 } 1890 }
1728
1729 Ok(()) 1891 Ok(())
1730 } 1892 }
1731 1893
diff --git a/tests/stm32/src/bin/sdmmc.rs b/tests/stm32/src/bin/sdmmc.rs
index c1ed45588..34a53a725 100644
--- a/tests/stm32/src/bin/sdmmc.rs
+++ b/tests/stm32/src/bin/sdmmc.rs
@@ -34,8 +34,10 @@ async fn main(_spawner: Spawner) {
34 pattern1[i] = i as u8; 34 pattern1[i] = i as u8;
35 pattern2[i] = !i as u8; 35 pattern2[i] = !i as u8;
36 } 36 }
37 let patterns = [pattern1.clone(), pattern2.clone()];
37 38
38 let mut block = DataBlock([0u8; 512]); 39 let mut block = DataBlock([0u8; 512]);
40 let mut blocks = [DataBlock([0u8; 512]), DataBlock([0u8; 512])];
39 41
40 // ======== Try 4bit. ============== 42 // ======== Try 4bit. ==============
41 info!("initializing in 4-bit mode..."); 43 info!("initializing in 4-bit mode...");
@@ -84,6 +86,13 @@ async fn main(_spawner: Spawner) {
84 s.read_block(block_idx, &mut block).await.unwrap(); 86 s.read_block(block_idx, &mut block).await.unwrap();
85 assert_eq!(block, pattern2); 87 assert_eq!(block, pattern2);
86 88
89 info!("writing blocks [pattern1, pattern2]...");
90 s.write_blocks(block_idx, &patterns).await.unwrap();
91
92 info!("reading blocks...");
93 s.read_blocks(block_idx, &mut blocks).await.unwrap();
94 assert_eq!(&blocks, &patterns);
95
87 drop(s); 96 drop(s);
88 97
89 // ======== Try 1bit. ============== 98 // ======== Try 1bit. ==============
@@ -116,9 +125,9 @@ async fn main(_spawner: Spawner) {
116 info!("Card: {:#?}", Debug2Format(card)); 125 info!("Card: {:#?}", Debug2Format(card));
117 info!("Clock: {}", s.clock()); 126 info!("Clock: {}", s.clock());
118 127
119 info!("reading pattern2 written in 4bit mode..."); 128 info!("reading pattern1 written in 4bit mode...");
120 s.read_block(block_idx, &mut block).await.unwrap(); 129 s.read_block(block_idx, &mut block).await.unwrap();
121 assert_eq!(block, pattern2); 130 assert_eq!(block, pattern1);
122 131
123 info!("writing pattern1..."); 132 info!("writing pattern1...");
124 s.write_block(block_idx, &pattern1).await.unwrap(); 133 s.write_block(block_idx, &pattern1).await.unwrap();
@@ -134,6 +143,13 @@ async fn main(_spawner: Spawner) {
134 s.read_block(block_idx, &mut block).await.unwrap(); 143 s.read_block(block_idx, &mut block).await.unwrap();
135 assert_eq!(block, pattern2); 144 assert_eq!(block, pattern2);
136 145
146 info!("writing blocks [pattern1, pattern2]...");
147 s.write_blocks(block_idx, &patterns).await.unwrap();
148
149 info!("reading blocks...");
150 s.read_blocks(block_idx, &mut blocks).await.unwrap();
151 assert_eq!(&blocks, &patterns);
152
137 drop(s); 153 drop(s);
138 154
139 info!("Test OK"); 155 info!("Test OK");