Skip to content

Commit 152b55d

Browse files
committed
Implement SDMMC writing.
1 parent 21fe2a9 commit 152b55d

File tree

3 files changed

+139
-67
lines changed

3 files changed

+139
-67
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 4 deletions
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" }
29-
- { id: stm32l486, additional-features: ",otg_fs" }
30-
- { id: stm32l496, additional-features: ",otg_fs" }
31-
- { id: stm32l4a6, additional-features: ",otg_fs" }
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" }
3232

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

Cargo.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ embedded-dma = "0.1"
2828
bxcan = ">=0.4, <0.7"
2929
fugit = "0.3.5"
3030
bitfield = "0.13.2"
31-
sdio-host = "0.7.0"
32-
embedded-sdmmc = "0.3.0"
31+
sdio-host = { version = "0.7.0", optional = true }
32+
embedded-sdmmc = { version = "0.3.0", optional = true }
3333

3434
[dependencies.rand_core]
3535
version = "0.6.2"
@@ -71,6 +71,8 @@ features = ["rt", "stm32l432", "stm32-usbd"]
7171
rt = ["stm32l4/rt"]
7272
unproven = ["embedded-hal/unproven"]
7373
otg_fs = ["synopsys-usb-otg"]
74+
sdmmc = ["dep:sdio-host"]
75+
embedded-sdmmc = ["dep:embedded-sdmmc", "sdmmc"]
7476

7577
# L4x1
7678
stm32l431 = [ "stm32l4/stm32l4x1" ]

src/sdmmc.rs

Lines changed: 131 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
use core::{fmt, ops::ControlFlow};
1+
#![cfg(feature = "sdmmc")]
2+
3+
use core::{
4+
fmt,
5+
ops::{ControlFlow, Deref, DerefMut},
6+
};
27

38
use fugit::HertzU32 as Hertz;
49
use sdio_host::{
@@ -12,7 +17,6 @@ use crate::{
1217
pac::{sdmmc1, SDMMC1},
1318
rcc::{Clocks, Enable, Reset, APB2},
1419
};
15-
1620
pub trait PinClk {}
1721
pub trait PinCmd {}
1822
pub trait PinD0 {}
@@ -147,12 +151,8 @@ pub enum Error {
147151
WrongResponseSize,
148152
}
149153

150-
macro_rules! try_datapath {
151-
($sta:ident) => {
152-
if $sta.rxoverr().bit() {
153-
return Err(Error::RxOverFlow);
154-
}
155-
154+
macro_rules! datapath_err {
155+
($sta:expr) => {
156156
if $sta.dcrcfail().bit() {
157157
return Err(Error::DataCrcFail);
158158
}
@@ -163,6 +163,26 @@ macro_rules! try_datapath {
163163
};
164164
}
165165

166+
macro_rules! datapath_rx_err {
167+
($sta:expr) => {
168+
if $sta.rxoverr().bit() {
169+
return Err(Error::RxOverFlow);
170+
}
171+
172+
datapath_err!($sta)
173+
};
174+
}
175+
176+
macro_rules! datapath_tx_err {
177+
($sta:expr) => {
178+
if $sta.rxoverr().bit() {
179+
return Err(Error::RxOverFlow);
180+
}
181+
182+
datapath_err!($sta)
183+
};
184+
}
185+
166186
fn clear_all_interrupts(icr: &sdmmc1::ICR) {
167187
icr.modify(|_, w| {
168188
w.ccrcfailc()
@@ -385,7 +405,21 @@ impl Sdmmc {
385405
Ok(())
386406
}
387407

388-
pub fn read_block(&mut self, addr: u32, buf: &mut [u8; 512]) -> Result<(), Error> {
408+
#[inline]
409+
pub fn read_block<B: DerefMut<Target = [u8; 512]>>(
410+
&mut self,
411+
addr: u32,
412+
block: B,
413+
) -> Result<(), Error> {
414+
self.read_blocks(addr, &mut [block])
415+
}
416+
417+
#[inline]
418+
pub fn read_blocks<B: DerefMut<Target = [u8; 512]>>(
419+
&mut self,
420+
addr: u32,
421+
blocks: &mut [B],
422+
) -> Result<(), Error> {
389423
let card = self.card()?;
390424

391425
let addr = match card.capacity() {
@@ -395,17 +429,28 @@ impl Sdmmc {
395429

396430
self.cmd(common_cmd::set_block_length(512))?;
397431

398-
self.start_datapath_transfer(512, 9, Dir::CardToHost);
399-
self.cmd(common_cmd::read_single_block(addr))?;
432+
let bytes = blocks.len() * 512;
433+
self.start_datapath_transfer(bytes as u32, 9, Dir::CardToHost);
434+
435+
match blocks.len() {
436+
0 => return Ok(()),
437+
1 => self.cmd(common_cmd::read_single_block(addr))?,
438+
_ => self.cmd(common_cmd::read_multiple_blocks(addr))?,
439+
}
400440

401441
let mut i = 0;
402442
loop {
403443
match self.read_fifo_hf(|bits| {
404-
buf[i..(i + 4)].copy_from_slice(&bits.to_be_bytes());
444+
let start = i % 512;
445+
blocks[i / 512][start..(start + 4)].copy_from_slice(&bits.to_be_bytes());
405446
i += 4;
406447
})? {
407448
ControlFlow::Break(()) => {
408-
if i == buf.len() {
449+
if blocks.len() > 1 {
450+
self.cmd(common_cmd::stop_transmission())?;
451+
}
452+
453+
if i == bytes {
409454
return Ok(());
410455
} else {
411456
return Err(Error::WrongResponseSize);
@@ -416,60 +461,89 @@ impl Sdmmc {
416461
}
417462
}
418463

419-
#[inline]
420-
pub fn read_blocks(&mut self, addr: u32, buf: &mut [u8]) -> Result<(), Error> {
421-
let card = self.card()?;
464+
pub fn write_block<B: Deref<Target = [u8; 512]>>(
465+
&mut self,
466+
addr: u32,
467+
block: B,
468+
) -> Result<(), Error> {
469+
self.write_blocks(addr, &[block])
470+
}
422471

423-
assert!(
424-
buf.len() % 512 == 0,
425-
"Buffer length must be a multiple of 512."
426-
);
472+
fn write_blocks<B: Deref<Target = [u8; 512]>>(
473+
&mut self,
474+
addr: u32,
475+
blocks: &[B],
476+
) -> Result<(), Error> {
477+
let card = self.card()?;
427478

428479
let addr = match card.capacity() {
429480
CardCapacity::StandardCapacity => addr * 512,
430481
_ => addr,
431482
};
432483

484+
let bytes = blocks.len() * 512;
433485
self.cmd(common_cmd::set_block_length(512))?;
486+
self.start_datapath_transfer(bytes as u32, 9, Dir::HostToCard);
434487

435-
self.start_datapath_transfer(buf.len() as u32, 9, Dir::CardToHost);
436-
self.cmd(common_cmd::read_multiple_blocks(addr))?;
488+
match blocks.len() {
489+
0 => return Ok(()),
490+
1 => self.cmd(common_cmd::write_single_block(addr))?,
491+
_ => self.cmd(common_cmd::write_multiple_blocks(addr))?,
492+
}
437493

438494
let mut i = 0;
439495
loop {
440-
match self.read_fifo_hf(|bits| {
441-
buf[i..(i + 4)].copy_from_slice(&bits.to_be_bytes());
442-
i += 4;
443-
})? {
444-
ControlFlow::Break(()) => {
445-
self.cmd(common_cmd::stop_transmission())?;
496+
let sta = self.sdmmc.sta.read();
446497

447-
if i == buf.len() {
448-
return Ok(());
449-
} else {
450-
return Err(Error::WrongResponseSize);
498+
datapath_tx_err!(sta);
499+
500+
if i == bytes {
501+
// If we sent all data, wait for transfer to end.
502+
if sta.dbckend().bit() {
503+
if blocks.len() > 1 {
504+
self.cmd(common_cmd::stop_transmission())?;
505+
}
506+
507+
break;
508+
}
509+
} else {
510+
// If the FIFO is half-empty, send some data.
511+
if sta.txfifohe().bit() {
512+
for _ in 0..8 {
513+
let block = &blocks[i / 512];
514+
let start = i % 512;
515+
516+
let bits = u32::from_be_bytes([
517+
block[start],
518+
block[start + 1],
519+
block[start + 2],
520+
block[start + 3],
521+
]);
522+
self.sdmmc.fifo.write(|w| unsafe { w.bits(bits.to_be()) });
523+
i += 4;
451524
}
452525
}
453-
ControlFlow::Continue(()) => continue,
454526
}
455527
}
456-
}
457528

458-
pub fn write_block(&mut self, addr: u32, block: &[u8; 512]) -> Result<(), Error> {
459-
self.card()?;
529+
let timeout: u32 = 0xffff_ffff;
530+
for _ in 0..timeout {
531+
if self.card_ready()? {
532+
return Ok(());
533+
}
534+
}
460535

461-
todo!()
536+
Err(Error::SoftwareTimeout)
462537
}
463538

464539
/// Read eight 32-bit values from a half-full FIFO.
465540
#[inline]
466541
fn read_fifo_hf(&mut self, mut f: impl FnMut(u32) -> ()) -> Result<ControlFlow<(), ()>, Error> {
467-
// TODO: Better timeout value.
468542
let timeout: u32 = 0xffff_ffff;
469543
for _ in 0..timeout {
470544
let sta = self.sdmmc.sta.read();
471545

472-
try_datapath!(sta);
546+
datapath_rx_err!(sta);
473547

474548
if sta.dbckend().bit() {
475549
return Ok(ControlFlow::Break(()));
@@ -556,26 +630,31 @@ impl Sdmmc {
556630

557631
let mut scr = [0; 2];
558632

559-
'outer: for n in scr.iter_mut().rev() {
560-
loop {
561-
let sta = self.sdmmc.sta.read();
633+
let mut i = scr.len();
562634

563-
try_datapath!(sta);
635+
let timeout: u32 = 0xffff_ffff;
636+
for _ in 0..timeout {
637+
let sta = self.sdmmc.sta.read();
564638

565-
if sta.dataend().bit() {
566-
break 'outer;
567-
}
639+
datapath_rx_err!(sta);
568640

641+
if i == 0 {
642+
if sta.dbckend().bit() {
643+
return Ok(SCR::from(scr));
644+
}
645+
} else {
569646
if sta.rxdavl().bit_is_set() {
647+
i -= 1;
648+
570649
let bits = u32::from_be(self.sdmmc.fifo.read().bits());
571-
*n = bits.to_le();
650+
scr[i] = bits.to_le();
572651

573-
continue 'outer;
652+
continue;
574653
}
575654
}
576655
}
577656

578-
return Ok(SCR::from(scr));
657+
return Err(Error::SoftwareTimeout);
579658
}
580659

581660
pub fn power_card(&mut self, on: bool) {
@@ -719,6 +798,7 @@ pub struct SdmmcBlockDevice<SDMMC> {
719798
sdmmc: core::cell::RefCell<SDMMC>,
720799
}
721800

801+
#[cfg(feature = "embedded-sdmmc")]
722802
impl embedded_sdmmc::BlockDevice for SdmmcBlockDevice<Sdmmc> {
723803
type Error = Error;
724804

@@ -728,15 +808,8 @@ impl embedded_sdmmc::BlockDevice for SdmmcBlockDevice<Sdmmc> {
728808
start_block_idx: embedded_sdmmc::BlockIdx,
729809
_reason: &str,
730810
) -> Result<(), Self::Error> {
731-
let start = start_block_idx.0;
732811
let mut sdmmc = self.sdmmc.borrow_mut();
733-
for block_idx in start..(start + blocks.len() as u32) {
734-
sdmmc.read_block(
735-
block_idx,
736-
&mut blocks[(block_idx - start) as usize].contents,
737-
)?;
738-
}
739-
Ok(())
812+
sdmmc.read_blocks(start_block_idx.0, blocks)
740813
}
741814

742815
fn write(
@@ -746,10 +819,7 @@ impl embedded_sdmmc::BlockDevice for SdmmcBlockDevice<Sdmmc> {
746819
) -> Result<(), Self::Error> {
747820
let start = start_block_idx.0;
748821
let mut sdmmc = self.sdmmc.borrow_mut();
749-
for block_idx in start..(start + blocks.len() as u32) {
750-
sdmmc.write_block(block_idx, &blocks[(block_idx - start) as usize].contents)?;
751-
}
752-
Ok(())
822+
sdmmc.write_blocks(start_block_idx.0, blocks)
753823
}
754824

755825
fn num_blocks(&self) -> Result<embedded_sdmmc::BlockCount, Self::Error> {

0 commit comments

Comments
 (0)