Skip to content

Commit ab85cd6

Browse files
committed
Add fatfs implementation.
1 parent 3ac9a72 commit ab85cd6

File tree

3 files changed

+173
-12
lines changed

3 files changed

+173
-12
lines changed

.github/workflows/ci.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ jobs:
2525
- { id: stm32l462, additional-features: ",stm32-usbd" }
2626
- { id: stm32l471, additional-features: "" }
2727
- { id: stm32l475, additional-features: "" } # USB_OTG not supported by PAC
28-
- { id: stm32l476, additional-features: ",otg_fs,sdmmc,embedded-sdmmc" }
29-
- { id: stm32l486, additional-features: ",otg_fs,sdmmc,embedded-sdmmc" }
30-
- { id: stm32l496, additional-features: ",otg_fs,sdmmc,embedded-sdmmc" }
31-
- { id: stm32l4a6, additional-features: ",otg_fs,sdmmc,embedded-sdmmc" }
28+
- { id: stm32l476, additional-features: ",otg_fs,sdmmc,embedded-sdmmc,fatfs" }
29+
- { id: stm32l486, additional-features: ",otg_fs,sdmmc,embedded-sdmmc,fatfs" }
30+
- { id: stm32l496, additional-features: ",otg_fs,sdmmc,embedded-sdmmc,fatfs" }
31+
- { id: stm32l4a6, additional-features: ",otg_fs,sdmmc,embedded-sdmmc,fatfs" }
3232

3333
steps:
3434
- uses: actions/checkout@v2

Cargo.toml

+5
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ fugit = "0.3.5"
3030
bitfield = "0.13.2"
3131
sdio-host = { version = "0.7.0", optional = true }
3232
embedded-sdmmc = { version = "0.3.0", optional = true }
33+
fatfs = { version = "0.4.0", default-features = false, optional = true }
3334

3435
[dependencies.rand_core]
3536
version = "0.6.2"
@@ -73,6 +74,7 @@ unproven = ["embedded-hal/unproven"]
7374
otg_fs = ["synopsys-usb-otg"]
7475
sdmmc = ["dep:sdio-host"]
7576
embedded-sdmmc = ["dep:embedded-sdmmc", "sdmmc"]
77+
fatfs = ["dep:fatfs", "sdmmc"]
7678

7779
# L4x1
7880
stm32l431 = [ "stm32l4/stm32l4x1" ]
@@ -207,3 +209,6 @@ required-features = ["rt"]
207209
[[example]]
208210
name = "adc_dma"
209211
required-features = ["rt"]
212+
213+
[patch.crates-io]
214+
fatfs = { git = "https://github.com/rafalh/rust-fatfs" }

src/sdmmc.rs

+164-8
Original file line numberDiff line numberDiff line change
@@ -385,21 +385,21 @@ impl Sdmmc {
385385

386386
self.cmd(common_cmd::all_send_cid())?;
387387
card.cid = CID::from([
388-
self.sdmmc.resp4.read().bits().to_le(),
389-
self.sdmmc.resp3.read().bits().to_le(),
390-
self.sdmmc.resp2.read().bits().to_le(),
391-
self.sdmmc.resp1.read().bits().to_le(),
388+
self.sdmmc.resp4.read().bits().to_le(),
389+
self.sdmmc.resp3.read().bits().to_le(),
390+
self.sdmmc.resp2.read().bits().to_le(),
391+
self.sdmmc.resp1.read().bits().to_le(),
392392
]);
393393

394394
self.cmd(sd_cmd::send_relative_address())?;
395395
card.rca = RCA::from(self.sdmmc.resp1.read().bits().to_le());
396396

397397
self.cmd(common_cmd::send_csd(card.rca.address()))?;
398398
card.csd = CSD::from([
399-
self.sdmmc.resp4.read().bits().to_le(),
400-
self.sdmmc.resp3.read().bits().to_le(),
401-
self.sdmmc.resp2.read().bits().to_le(),
402-
self.sdmmc.resp1.read().bits().to_le(),
399+
self.sdmmc.resp4.read().bits().to_le(),
400+
self.sdmmc.resp3.read().bits().to_le(),
401+
self.sdmmc.resp2.read().bits().to_le(),
402+
self.sdmmc.resp1.read().bits().to_le(),
403403
]);
404404

405405
self.select_card(card.rca.address())?;
@@ -838,3 +838,159 @@ impl embedded_sdmmc::BlockDevice for SdmmcBlockDevice<Sdmmc> {
838838
))
839839
}
840840
}
841+
842+
#[cfg(feature = "fatfs")]
843+
use fatfs::{IntoStorage, IoBase, IoError, Read, Seek, SeekFrom, Write};
844+
845+
impl IoError for Error {
846+
fn is_interrupted(&self) -> bool {
847+
false
848+
}
849+
850+
fn new_unexpected_eof_error() -> Self {
851+
unimplemented!()
852+
}
853+
854+
fn new_write_zero_error() -> Self {
855+
unimplemented!()
856+
}
857+
}
858+
859+
#[derive(Debug)]
860+
pub struct FatFsCursor<SDMMC> {
861+
sdmmc: SDMMC,
862+
pos: u64,
863+
partition_info: Option<(u32, u32)>,
864+
}
865+
866+
impl FatFsCursor<Sdmmc> {
867+
pub fn new(sdmmc: Sdmmc) -> Self {
868+
Self {
869+
sdmmc,
870+
pos: 0,
871+
partition_info: None,
872+
}
873+
}
874+
875+
pub fn partition_info(&mut self) -> Result<(u32, u32), Error> {
876+
if let Some(partition_info) = self.partition_info {
877+
return Ok(partition_info);
878+
}
879+
880+
let mut block = [0; 512];
881+
self.sdmmc.read_block(0, &mut block)?;
882+
883+
// TODO: Support other partitions.
884+
let partition1_info = &block[446..][..16];
885+
let lba_start = u32::from_le_bytes([
886+
partition1_info[8],
887+
partition1_info[9],
888+
partition1_info[10],
889+
partition1_info[11],
890+
]);
891+
892+
let num_blocks = u32::from_le_bytes([
893+
partition1_info[12],
894+
partition1_info[13],
895+
partition1_info[14],
896+
partition1_info[15],
897+
]);
898+
899+
Ok(*self.partition_info.get_or_insert((lba_start, num_blocks)))
900+
}
901+
}
902+
903+
#[cfg(feature = "fatfs")]
904+
impl IntoStorage<FatFsCursor<Sdmmc>> for Sdmmc {
905+
fn into_storage(self) -> FatFsCursor<Sdmmc> {
906+
FatFsCursor::new(self)
907+
}
908+
}
909+
910+
#[cfg(feature = "fatfs")]
911+
impl<SDMMC> IoBase for FatFsCursor<SDMMC> {
912+
type Error = fatfs::Error<Error>;
913+
}
914+
915+
#[cfg(feature = "fatfs")]
916+
impl Seek for FatFsCursor<Sdmmc> {
917+
fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Error> {
918+
let itm = unsafe { &mut *cortex_m::peripheral::ITM::PTR };
919+
// cortex_m::itm::write_fmt(&mut itm.stim[0], format_args!("Seek from {} to {:?}\n", self.pos, pos));
920+
921+
// TODO: Use `checked_add_signed` when stable.
922+
let new_pos = match pos {
923+
SeekFrom::Start(offset) => offset as i128,
924+
SeekFrom::End(offset) => {
925+
let end = self.partition_info()?.1 * 512;
926+
end as i128 + offset as i128
927+
}
928+
SeekFrom::Current(offset) => self.pos as i128 + offset as i128,
929+
};
930+
931+
if new_pos < 0 || new_pos > u64::MAX as i128 {
932+
// Seek to negative or overflowing position.
933+
return Err(Self::Error::InvalidInput);
934+
}
935+
let new_pos = new_pos as u64;
936+
937+
self.pos = new_pos;
938+
Ok(self.pos)
939+
}
940+
}
941+
942+
#[cfg(feature = "fatfs")]
943+
impl Read for FatFsCursor<Sdmmc> {
944+
#[track_caller]
945+
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
946+
let (start, end) = self.partition_info()?;
947+
948+
let end = end as u64 * 512;
949+
let pos = self.pos.min(end);
950+
951+
let addr = start + (pos / 512) as u32;
952+
let offset = (pos % 512) as usize;
953+
let len = buf.len().min(512 - offset);
954+
955+
let mut block = [0; 512];
956+
self.sdmmc.read_block(addr, &mut block)?;
957+
buf[0..len].copy_from_slice(&block[offset..(offset + len)]);
958+
self.pos += len as u64;
959+
960+
Ok(len)
961+
}
962+
963+
// TODO: Add `read_exact` implementation which supports reading multiple blocks.
964+
}
965+
966+
#[cfg(feature = "fatfs")]
967+
impl Write for FatFsCursor<Sdmmc> {
968+
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
969+
let (start, end) = self.partition_info()?;
970+
971+
let end = end as u64 * 512;
972+
let pos = self.pos;
973+
974+
if pos + buf.len() as u64 >= end {
975+
return Err(Self::Error::NotEnoughSpace);
976+
}
977+
978+
let addr = start + (pos / 512) as u32;
979+
let offset = (pos % 512) as usize;
980+
let len = buf.len().min(512 - offset);
981+
982+
let mut block = [0; 512];
983+
self.sdmmc.read_block(addr, &mut block)?;
984+
block[offset..(offset + len)].copy_from_slice(&buf[0..len]);
985+
self.sdmmc.write_block(addr, &block)?;
986+
self.pos += len as u64;
987+
988+
Ok(len)
989+
}
990+
991+
// TODO: Add `write_exact` implementation which supports writing multiple blocks.
992+
993+
fn flush(&mut self) -> Result<(), Self::Error> {
994+
Ok(())
995+
}
996+
}

0 commit comments

Comments
 (0)