Skip to content

Commit ca40dc7

Browse files
authored
Merge pull request #3843 from ost-ing/sdmmc-multiblocks
STM32 SDMMC multiple block read/write support
2 parents 3ffee5e + eb83d04 commit ca40dc7

File tree

2 files changed

+195
-17
lines changed

2 files changed

+195
-17
lines changed

embassy-stm32/src/sdmmc/mod.rs

+177-15
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ pub enum Error {
151151
BadClock,
152152
/// Signaling switch failed.
153153
SignalingSwitchFailed,
154+
/// Underrun error
155+
Underrun,
154156
/// ST bit error.
155157
#[cfg(sdmmc_v1)]
156158
StBitErr,
@@ -1025,6 +1027,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
10251027
if status.dtimeout() {
10261028
return Poll::Ready(Err(Error::Timeout));
10271029
}
1030+
if status.txunderr() {
1031+
return Poll::Ready(Err(Error::Underrun));
1032+
}
10281033
#[cfg(sdmmc_v1)]
10291034
if status.stbiterr() {
10301035
return Poll::Ready(Err(Error::StBitErr));
@@ -1080,6 +1085,73 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
10801085
res
10811086
}
10821087

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+
10831155
/// Write a data block.
10841156
pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> {
10851157
let card = self.card.as_mut().ok_or(Error::NoCard)?;
@@ -1088,7 +1160,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
10881160
let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) };
10891161

10901162
// 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
10921164
let address = match card.get_capacity() {
10931165
CardCapacity::StandardCapacity => block_idx * 512,
10941166
_ => block_idx,
@@ -1136,6 +1208,94 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
11361208
}
11371209
}
11381210

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+
11391299
/// Get a reference to the initialized card
11401300
///
11411301
/// # Errors
@@ -1699,33 +1859,35 @@ impl<'d, T: Instance> block_device_driver::BlockDevice<512> for Sdmmc<'d, T> {
16991859

17001860
async fn read(
17011861
&mut self,
1702-
mut block_address: u32,
1862+
block_address: u32,
17031863
buf: &mut [aligned::Aligned<Self::Align, [u8; 512]>],
17041864
) -> Result<(), Self::Error> {
1705-
// FIXME/TODO because of missing read_blocks multiple we have to do this one block at a time
1706-
for block in buf.iter_mut() {
1707-
// safety aligned by block device
1708-
let block = unsafe { &mut *(block as *mut _ as *mut crate::sdmmc::DataBlock) };
1865+
// TODO: I think block_address needs to be adjusted by the partition start offset
1866+
if buf.len() == 1 {
1867+
let block = unsafe { &mut *(&mut buf[0] as *mut _ as *mut crate::sdmmc::DataBlock) };
17091868
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?;
17111873
}
1712-
17131874
Ok(())
17141875
}
17151876

17161877
async fn write(
17171878
&mut self,
1718-
mut block_address: u32,
1879+
block_address: u32,
17191880
buf: &[aligned::Aligned<Self::Align, [u8; 512]>],
17201881
) -> Result<(), Self::Error> {
1721-
// FIXME/TODO because of missing read_blocks multiple we have to do this one block at a time
1722-
for block in buf.iter() {
1723-
// safety aligned by block device
1724-
let block = unsafe { &*(block as *const _ as *const crate::sdmmc::DataBlock) };
1882+
// TODO: I think block_address needs to be adjusted by the partition start offset
1883+
if buf.len() == 1 {
1884+
let block = unsafe { &*(&buf[0] as *const _ as *const crate::sdmmc::DataBlock) };
17251885
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?;
17271890
}
1728-
17291891
Ok(())
17301892
}
17311893

tests/stm32/src/bin/sdmmc.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@ async fn main(_spawner: Spawner) {
3434
pattern1[i] = i as u8;
3535
pattern2[i] = !i as u8;
3636
}
37+
let patterns = [pattern1.clone(), pattern2.clone()];
3738

3839
let mut block = DataBlock([0u8; 512]);
40+
let mut blocks = [DataBlock([0u8; 512]), DataBlock([0u8; 512])];
3941

4042
// ======== Try 4bit. ==============
4143
info!("initializing in 4-bit mode...");
@@ -84,6 +86,13 @@ async fn main(_spawner: Spawner) {
8486
s.read_block(block_idx, &mut block).await.unwrap();
8587
assert_eq!(block, pattern2);
8688

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+
8796
drop(s);
8897

8998
// ======== Try 1bit. ==============
@@ -116,9 +125,9 @@ async fn main(_spawner: Spawner) {
116125
info!("Card: {:#?}", Debug2Format(card));
117126
info!("Clock: {}", s.clock());
118127

119-
info!("reading pattern2 written in 4bit mode...");
128+
info!("reading pattern1 written in 4bit mode...");
120129
s.read_block(block_idx, &mut block).await.unwrap();
121-
assert_eq!(block, pattern2);
130+
assert_eq!(block, pattern1);
122131

123132
info!("writing pattern1...");
124133
s.write_block(block_idx, &pattern1).await.unwrap();
@@ -134,6 +143,13 @@ async fn main(_spawner: Spawner) {
134143
s.read_block(block_idx, &mut block).await.unwrap();
135144
assert_eq!(block, pattern2);
136145

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+
137153
drop(s);
138154

139155
info!("Test OK");

0 commit comments

Comments
 (0)