diff options
| -rw-r--r-- | embassy-stm32/src/sdmmc/mod.rs | 192 | ||||
| -rw-r--r-- | tests/stm32/src/bin/sdmmc.rs | 20 |
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"); |
