Skip to content

Commit d847580

Browse files
committed
Add glue to make embedded-sdmmc work nicely
1 parent fc623b7 commit d847580

File tree

3 files changed

+173
-2
lines changed

3 files changed

+173
-2
lines changed

Cargo.toml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,12 @@ embedded-dma = "0.1.2"
3030
cortex-m = "^0.7.1"
3131
stm32h7 = "^0.14.0"
3232
void = { version = "1.0.2", default-features = false }
33-
cast = { version = "0.2.3", default-features = false }
33+
cast = { version = "0.3.0", default-features = false }
3434
nb = "1.0.0"
3535
paste = "1.0.1"
3636
bare-metal = "1.0.0"
37-
sdio-host = { version = "0.4", optional = true }
37+
sdio-host = { version = "0.5", optional = true }
38+
embedded-sdmmc = { version = "0.3", optional = true }
3839
stm32-fmc = { version = "0.2", optional = true }
3940
synopsys-usb-otg = { version = "^0.2.4", features = ["cortex-m"], optional = true }
4041
embedded-display-controller = { version = "^0.1.0", optional = true }
@@ -87,6 +88,7 @@ ltdc = ["embedded-display-controller"]
8788
quadspi = []
8889
fmc = ["stm32-fmc"]
8990
sdmmc = ["sdio-host"]
91+
sdmmc-fatfs = ["embedded-sdmmc", "sdmmc"]
9092
ethernet = ["smoltcp"]
9193
rtc = ["chrono"]
9294
crc = []
@@ -151,6 +153,10 @@ required-features = ["quadspi", "rm0433"]
151153
name = "sdmmc"
152154
required-features = ["sdmmc", "rm0433"]
153155

156+
[[example]]
157+
name = "sdmmc_fat"
158+
required-features = ["sdmmc", "sdmmc-fatfs", "stm32h747cm7"]
159+
154160
[[example]]
155161
name = "ethernet-stm32h747i-disco"
156162
required-features = ["rt", "stm32h747cm7", "ethernet"]

examples/sdmmc_fat.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#![no_main]
2+
#![no_std]
3+
4+
use {
5+
embedded_sdmmc::{Controller, VolumeIdx},
6+
log,
7+
stm32h7xx_hal::{pac, prelude::*, rcc},
8+
};
9+
10+
#[macro_use]
11+
mod utilities;
12+
13+
// This is just a placeholder TimeSource. In a real world application
14+
// one would probably use the RTC to provide time.
15+
pub struct TimeSource;
16+
17+
impl embedded_sdmmc::TimeSource for TimeSource {
18+
fn get_timestamp(&self) -> embedded_sdmmc::Timestamp {
19+
embedded_sdmmc::Timestamp {
20+
year_since_1970: 0,
21+
zero_indexed_month: 0,
22+
zero_indexed_day: 0,
23+
hours: 0,
24+
minutes: 0,
25+
seconds: 0,
26+
}
27+
}
28+
}
29+
30+
#[cortex_m_rt::entry]
31+
unsafe fn main() -> ! {
32+
utilities::logger::init();
33+
34+
// Get peripherals
35+
let cp = cortex_m::Peripherals::take().unwrap();
36+
let dp = pac::Peripherals::take().unwrap();
37+
38+
// Constrain and Freeze power
39+
let pwr = dp.PWR.constrain();
40+
let pwrcfg = example_power!(pwr).freeze();
41+
42+
// Constrain and Freeze clock
43+
let ccdr = dp
44+
.RCC
45+
.constrain()
46+
.sys_ck(480.mhz())
47+
.pll1_strategy(rcc::PllConfigStrategy::Iterative)
48+
.pll1_q_ck(100.mhz())
49+
.pll2_strategy(rcc::PllConfigStrategy::Iterative)
50+
.pll3_strategy(rcc::PllConfigStrategy::Iterative)
51+
.freeze(pwrcfg, &dp.SYSCFG);
52+
53+
// Get the delay provider.
54+
let mut delay = cp.SYST.delay(ccdr.clocks);
55+
56+
let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB);
57+
let gpiod = dp.GPIOD.split(ccdr.peripheral.GPIOD);
58+
59+
let mut sd = dp.SDMMC2.sdmmc(
60+
(
61+
gpiod.pd6.into_alternate_af11(),
62+
gpiod.pd7.into_alternate_af11(),
63+
gpiob.pb14.into_alternate_af9(),
64+
gpiob.pb15.into_alternate_af9(),
65+
gpiob.pb3.into_alternate_af9(),
66+
gpiob.pb4.into_alternate_af9(),
67+
),
68+
ccdr.peripheral.SDMMC2,
69+
&ccdr.clocks,
70+
);
71+
72+
// Loop until we have a card
73+
loop {
74+
// On most development boards this can be increased up to 50MHz. We choose a
75+
// lower frequency here so that it should work even with flying leads
76+
// connected to a SD card breakout.
77+
match sd.init_card(2.mhz()) {
78+
Ok(_) => break,
79+
Err(err) => {
80+
log::info!("Init err: {:?}", err);
81+
}
82+
}
83+
84+
log::info!("Waiting for card...");
85+
86+
delay.delay_ms(1000u32);
87+
}
88+
89+
// See https://github.com/rust-embedded-community/embedded-sdmmc-rs for docs
90+
// and more examples
91+
92+
let mut sd_fatfs = Controller::new(sd.sdmmc_block_device(), TimeSource);
93+
let sd_fatfs_volume = sd_fatfs.get_volume(VolumeIdx(0)).unwrap();
94+
let sd_fatfs_root_dir = sd_fatfs.open_root_dir(&sd_fatfs_volume).unwrap();
95+
sd_fatfs
96+
.iterate_dir(&sd_fatfs_volume, &sd_fatfs_root_dir, |entry| {
97+
log::info!("{:?}", entry);
98+
})
99+
.unwrap();
100+
sd_fatfs.close_dir(&sd_fatfs_volume, sd_fatfs_root_dir);
101+
102+
loop {
103+
cortex_m::asm::nop()
104+
}
105+
}

src/sdmmc.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,6 +1138,54 @@ macro_rules! sdmmc {
11381138
Ok(())
11391139
}
11401140

1141+
#[cfg(feature = "sdmmc-fatfs")]
1142+
pub fn sdmmc_block_device(self) -> SdmmcBlockDevice<Sdmmc<$SDMMCX>> {
1143+
SdmmcBlockDevice {
1144+
sdmmc: core::cell::RefCell::new(self)
1145+
}
1146+
}
1147+
1148+
}
1149+
1150+
#[cfg(feature = "sdmmc-fatfs")]
1151+
impl embedded_sdmmc::BlockDevice for SdmmcBlockDevice<Sdmmc<$SDMMCX>> {
1152+
type Error = Error;
1153+
1154+
fn read(
1155+
&self,
1156+
blocks: &mut [embedded_sdmmc::Block],
1157+
start_block_idx: embedded_sdmmc::BlockIdx,
1158+
_reason: &str,
1159+
) -> Result<(), Self::Error> {
1160+
let start = start_block_idx.0;
1161+
let mut sdmmc = self.sdmmc.borrow_mut();
1162+
for block_idx in start..(start + blocks.len() as u32) {
1163+
sdmmc.read_block(
1164+
block_idx,
1165+
&mut blocks[(block_idx - start) as usize].contents,
1166+
)?;
1167+
}
1168+
Ok(())
1169+
}
1170+
1171+
fn write(
1172+
&self,
1173+
blocks: &[embedded_sdmmc::Block],
1174+
start_block_idx: embedded_sdmmc::BlockIdx,
1175+
) -> Result<(), Self::Error> {
1176+
let start = start_block_idx.0;
1177+
let mut sdmmc = self.sdmmc.borrow_mut();
1178+
for block_idx in start..(start + blocks.len() as u32) {
1179+
sdmmc.write_block(block_idx, &blocks[(block_idx - start) as usize].contents)?;
1180+
}
1181+
Ok(())
1182+
}
1183+
1184+
fn num_blocks(&self) -> Result<embedded_sdmmc::BlockCount, Self::Error> {
1185+
let sdmmc = self.sdmmc.borrow_mut();
1186+
Ok(embedded_sdmmc::BlockCount(sdmmc.card()?.size() as u32 / 512u32))
1187+
}
1188+
11411189
}
11421190
)+
11431191
};
@@ -1234,3 +1282,15 @@ impl Cmd {
12341282
Cmd::new(55, rca, Response::Short)
12351283
}
12361284
}
1285+
1286+
#[cfg(feature = "sdmmc-fatfs")]
1287+
pub struct SdmmcBlockDevice<SDMMC> {
1288+
sdmmc: core::cell::RefCell<SDMMC>,
1289+
}
1290+
1291+
#[cfg(feature = "sdmmc-fatfs")]
1292+
impl<SDMMC> SdmmcBlockDevice<SDMMC> {
1293+
pub fn free(self) -> SDMMC {
1294+
self.sdmmc.into_inner()
1295+
}
1296+
}

0 commit comments

Comments
 (0)