diff --git a/CHANGELOG.md b/CHANGELOG.md index 26857c2e..0c77ae85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ * MSRV increased to 1.65.0 * add `IntoAf` trait to restrict `into_alternate` [#346] * sdmmc: Introduce `write_blocks` [#453] +* sdmmc-fat: Optimize writing speeds [#456] ## [v0.14.0] 2023-03-22 diff --git a/examples/sdmmc_fat.rs b/examples/sdmmc_fat.rs index e75c3c7b..c451de98 100644 --- a/examples/sdmmc_fat.rs +++ b/examples/sdmmc_fat.rs @@ -2,7 +2,7 @@ #![no_std] use { - embedded_sdmmc::{Controller, VolumeIdx}, + embedded_sdmmc::{Controller, Mode, VolumeIdx}, stm32h7xx_hal::sdmmc::{SdCard, Sdmmc}, stm32h7xx_hal::{pac, prelude::*, rcc}, }; @@ -89,14 +89,55 @@ unsafe fn main() -> ! { // See https://github.com/rust-embedded-community/embedded-sdmmc-rs for docs // and more examples + log::info!("Initialize file system manager"); let mut sd_fatfs = Controller::new(sd.sdmmc_block_device(), TimeSource); - let sd_fatfs_volume = sd_fatfs.get_volume(VolumeIdx(0)).unwrap(); + let mut sd_fatfs_volume = sd_fatfs.get_volume(VolumeIdx(0)).unwrap(); let sd_fatfs_root_dir = sd_fatfs.open_root_dir(&sd_fatfs_volume).unwrap(); + + log::info!("List all the directories and their info"); sd_fatfs .iterate_dir(&sd_fatfs_volume, &sd_fatfs_root_dir, |entry| { log::info!("{:?}", entry); }) .unwrap(); + + const WRITE_BUFFER: [u8; 8 * 1024] = [b'B'; 8 * 1024]; + + for (filename, length) in + &[("small.txt", 8), ("big.txt", WRITE_BUFFER.len())] + { + log::info!("Open file {:?}", filename); + let mut file = sd_fatfs + .open_file_in_dir( + &mut sd_fatfs_volume, + &sd_fatfs_root_dir, + filename, + Mode::ReadWriteCreateOrTruncate, + ) + .unwrap(); + + log::info!("Write {:?} characters in it", length); + sd_fatfs + .write(&mut sd_fatfs_volume, &mut file, &WRITE_BUFFER[0..*length]) + .unwrap(); + + log::info!("Read it back and confirm it contains the expected content"); + file.seek_from_start(0).unwrap(); + while !file.eof() { + let mut buffer = [0u8; 1024]; + let num_read = sd_fatfs + .read(&sd_fatfs_volume, &mut file, &mut buffer) + .unwrap(); + for b in &buffer[0..num_read] { + assert_eq!(*b as char, 'B'); + } + } + + sd_fatfs.close_file(&sd_fatfs_volume, file).unwrap(); + } + + log::info!("Test successfully finished"); + sd_fatfs.close_dir(&sd_fatfs_volume, sd_fatfs_root_dir); loop { diff --git a/src/sdmmc.rs b/src/sdmmc.rs index 847e327a..b72e61cd 100644 --- a/src/sdmmc.rs +++ b/src/sdmmc.rs @@ -804,12 +804,23 @@ macro_rules! sdmmc { &mut self, address: u32, buffer: &[u8] + ) -> Result<(), Error> { + self.write_blocks_begin(address, buffer.len())?; + self.write_blocks_feed(buffer); + self.write_blocks_conclude()?; + Ok(()) + } + + fn write_blocks_begin( + &mut self, + address: u32, + buffer_len: usize, ) -> Result<(), Error> { let _card = self.card()?; - assert!(buffer.len() % 512 == 0, + assert!(buffer_len % 512 == 0, "Buffer length must be a multiple of 512"); - let n_blocks = buffer.len() / 512; + let n_blocks = buffer_len / 512; if !self.cmd16_illegal { self.cmd(common_cmd::set_block_length(512))?; // CMD16 @@ -819,6 +830,10 @@ macro_rules! sdmmc { self.start_datapath_transfer(512 * n_blocks as u32, 9, Dir::HostToCard); self.cmd(common_cmd::write_multiple_blocks(address))?; // CMD25 + Ok(()) + } + + fn write_blocks_feed(&mut self, buffer: &[u8]) { let mut i = 0; let mut status; while { @@ -842,6 +857,10 @@ macro_rules! sdmmc { break } } + } + + fn write_blocks_conclude(&mut self) -> Result<(), Error> { + let mut status; while { status = self.sdmmc.star.read(); @@ -850,6 +869,7 @@ macro_rules! sdmmc { || status.dtimeout().bit() || status.dataend().bit()) } {} + self.cmd(common_cmd::stop_transmission())?; // CMD12 err_from_datapath_sm!(status); @@ -1339,10 +1359,17 @@ macro_rules! sdmmc { blocks: &[embedded_sdmmc::Block], start_block_idx: embedded_sdmmc::BlockIdx, ) -> Result<(), Self::Error> { - let start = start_block_idx.0; let mut sdmmc = self.sdmmc.borrow_mut(); - for block_idx in start..(start + blocks.len() as u32) { - sdmmc.write_block(block_idx, &blocks[(block_idx - start) as usize].contents)?; + let start = start_block_idx.0; + if blocks.len() == 1 { + sdmmc.write_block(start, &blocks[0].contents)?; + } else { + let total_length = embedded_sdmmc::Block::LEN * blocks.len(); + sdmmc.write_blocks_begin(start, total_length)?; + for block in blocks.iter() { + sdmmc.write_blocks_feed(&block.contents); + } + sdmmc.write_blocks_conclude()?; } Ok(()) }