Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce SDMMC write_blocks #453

Merged
merged 2 commits into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Update `smoltcp` dependency to `0.9.0`
* MSRV increased to 1.65.0
* add `IntoAf` trait to restrict `into_alternate` [#346]
* sdmmc: Introduce `write_blocks` [#453]

## [v0.14.0] 2023-03-22

Expand Down
60 changes: 24 additions & 36 deletions examples/sdmmc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,57 +144,45 @@ fn main() -> ! {
info!("----------------------");
info!("");

// Read test
let mut buffer = [0u8; 5120];

cp.DWT.enable_cycle_counter();
let start = pac::DWT::cycle_count();

for i in 0..10 {
// Read 10 blocks
sdmmc.read_blocks(10 * i, &mut buffer).unwrap();
}

// Write single block test
let write_buffer = [0x34; 512];
let start = pac::DWT::cycle_count();
sdmmc.write_block(0, &write_buffer).unwrap();
let end = pac::DWT::cycle_count();
let duration = (end - start) as f32 / ccdr.clocks.c_ck().raw() as f32;
info!("Wrote single block at {} bytes/s", 512.0 / duration);

info!("Read 10 blocks at {} bytes/s", 5120. / duration);
info!("");

let write_buffer = [0x34; 512];
// Write multiple blocks test
let write_buffer = [0x34; 512 * 16];
let start = pac::DWT::cycle_count();
sdmmc.write_blocks(0, &write_buffer).unwrap();
let end = pac::DWT::cycle_count();
let duration = (end - start) as f32 / ccdr.clocks.c_ck().raw() as f32;
info!("Wrote 16 blocks at {} bytes/s", (512.0 * 16.0) / duration);

for i in 0..10 {
if let Err(err) = sdmmc.write_block(i, &write_buffer) {
info!("Failed to write block {}: {:?}", i, err);
}
}

// Read single block test
let mut buffer = [0u8; 512];
let start = pac::DWT::cycle_count();
sdmmc.read_block(0, &mut buffer).unwrap();
let end = pac::DWT::cycle_count();
let duration = (end - start) as f32 / ccdr.clocks.c_ck().raw() as f32;
info!("Read single block at {} bytes/s", 512.0 / duration);

info!("Wrote 10 blocks at {} bytes/s", 5120. / duration);
info!("");
// Read multiple blocks test
let mut buffer = [0u8; 512 * 16];
let start = pac::DWT::cycle_count();
sdmmc.read_blocks(0, &mut buffer).unwrap();
let end = pac::DWT::cycle_count();
let duration = (end - start) as f32 / ccdr.clocks.c_ck().raw() as f32;
info!("Read 16 blocks at {} bytes/s", (512.0 * 16.0) / duration);

info!("Verification test...");
// Write 10 blocks
for i in 0..10 {
if let Err(err) = sdmmc.write_block(i, &write_buffer) {
info!("Failed to write block {}: {:?}", i, err);
} else {
info!("Wrote block {}", i);
}

// Read back
sdmmc.read_blocks(0, &mut buffer).unwrap();
}

// Check the read
for byte in buffer.iter() {
assert_eq!(*byte, 0x34);
}
info!("Verified 10 blocks");
info!("");
info!("Verified all blocks");

info!("Done!");

Expand Down
74 changes: 74 additions & 0 deletions src/sdmmc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ pub enum Error {
Crc,
DataCrcFail,
RxOverFlow,
TxUnderFlow,
NoCard,
BadClock,
InvalidConfiguration,
Expand Down Expand Up @@ -342,6 +343,8 @@ macro_rules! err_from_datapath_sm {
return Err(Error::DataCrcFail);
} else if $status.rxoverr().bit() {
return Err(Error::RxOverFlow);
} else if $status.txunderr().bit() {
return Err(Error::TxUnderFlow);
} else if $status.dtimeout().bit() {
return Err(Error::Timeout);
}
Expand Down Expand Up @@ -793,6 +796,77 @@ macro_rules! sdmmc {
Err(Error::SoftwareTimeout)
}

/// Write multiple blocks to card. The length of the buffer
/// must be multiple of 512.
///
/// `address` is the block address.
pub fn write_blocks(
&mut self,
address: u32,
buffer: &[u8]
) -> Result<(), Error> {
let _card = self.card()?;

assert!(buffer.len() % 512 == 0,
"Buffer length must be a multiple of 512");
let n_blocks = buffer.len() / 512;

if !self.cmd16_illegal {
self.cmd(common_cmd::set_block_length(512))?; // CMD16
}

// Setup write command
self.start_datapath_transfer(512 * n_blocks as u32, 9, Dir::HostToCard);
self.cmd(common_cmd::write_multiple_blocks(address))?; // CMD25

let mut i = 0;
let mut status;
while {
status = self.sdmmc.star.read();
!(status.txunderr().bit()
|| status.dcrcfail().bit()
|| status.dtimeout().bit()
|| status.dataend().bit())
} {
if status.txfifohe().bit() {
for _ in 0..8 {
let mut wb = [0u8; 4];
wb.copy_from_slice(&buffer[i..i + 4]);
let word = u32::from_le_bytes(wb);
self.sdmmc.fifor.write(|w| unsafe { w.bits(word) });
i += 4;
}
}

if i >= buffer.len() {
break
}
}

while {
status = self.sdmmc.star.read();
!(status.txunderr().bit()
|| status.dcrcfail().bit()
|| status.dtimeout().bit()
|| status.dataend().bit())
} {}
self.cmd(common_cmd::stop_transmission())?; // CMD12

err_from_datapath_sm!(status);
self.clear_static_interrupt_flags();

let mut timeout: u32 = 0xFFFF_FFFF;

// Try to read card status (CMD13)
while timeout > 0 {
if self.card_ready()? {
return Ok(());
}
timeout -= 1;
}
Err(Error::SoftwareTimeout)
}

/// Query the card status (CMD13, returns R1)
///
fn read_status(&self) -> Result<CardStatus<P>, Error> {
Expand Down
Loading