use core::fmt;
use crate::sd_registers::*;
use stm32h7xx_hal::gpio::gpioa::PA0;
use stm32h7xx_hal::gpio::gpiob::{PB14, PB15, PB3, PB4, PB8, PB9};
use stm32h7xx_hal::gpio::gpioc::{PC1, PC10, PC11, PC12, PC6, PC7, PC8, PC9};
use stm32h7xx_hal::gpio::gpiod::{PD2, PD6, PD7};
use stm32h7xx_hal::gpio::gpiog::PG11;
use stm32h7xx_hal::time::Hertz;
use stm32h7xx_hal::gpio::{Alternate, AF10, AF11, AF12, AF9};
use stm32h7xx_hal::rcc::rec::{ResetEnable, SdmmcClkSelGetter};
use stm32h7xx_hal::rcc::{rec, CoreClocks};
use stm32h7xx_hal::stm32::{SDMMC1, SDMMC2};
pub trait PinClk<SDMMC> {}
pub trait PinCmd<SDMMC> {}
pub trait PinD0<SDMMC> {}
pub trait PinD1<SDMMC> {}
pub trait PinD2<SDMMC> {}
pub trait PinD3<SDMMC> {}
pub trait PinD4<SDMMC> {}
pub trait PinD5<SDMMC> {}
pub trait PinD6<SDMMC> {}
pub trait PinD7<SDMMC> {}
pub trait Pins<SDMMC> {
const BUSWIDTH: BusWidth;
}
impl<SDMMC, CLK, CMD, D0, D1, D2, D3, D4, D5, D6, D7> Pins<SDMMC>
for (CLK, CMD, D0, D1, D2, D3, D4, D5, D6, D7)
where
CLK: PinClk<SDMMC>,
CMD: PinCmd<SDMMC>,
D0: PinD0<SDMMC>,
D1: PinD1<SDMMC>,
D2: PinD2<SDMMC>,
D3: PinD3<SDMMC>,
D4: PinD4<SDMMC>,
D5: PinD5<SDMMC>,
D6: PinD6<SDMMC>,
D7: PinD7<SDMMC>,
{
const BUSWIDTH: BusWidth = BusWidth::Eight;
}
impl<SDMMC, CLK, CMD, D0, D1, D2, D3> Pins<SDMMC> for (CLK, CMD, D0, D1, D2, D3)
where
CLK: PinClk<SDMMC>,
CMD: PinCmd<SDMMC>,
D0: PinD0<SDMMC>,
D1: PinD1<SDMMC>,
D2: PinD2<SDMMC>,
D3: PinD3<SDMMC>,
{
const BUSWIDTH: BusWidth = BusWidth::Four;
}
impl<SDMMC, CLK, CMD, D0> Pins<SDMMC> for (CLK, CMD, D0)
where
CLK: PinClk<SDMMC>,
CMD: PinCmd<SDMMC>,
D0: PinD0<SDMMC>,
{
const BUSWIDTH: BusWidth = BusWidth::One;
}
macro_rules! pins {
($($SDMMCX:ty: CLK: [$($CLK:ty),*] CMD: [$($CMD:ty),*]
D0: [$($D0:ty),*] D1: [$($D1:ty),*] D2: [$($D2:ty),*] D3: [$($D3:ty),*]
D4: [$($D4:ty),*] D5: [$($D5:ty),*] D6: [$($D6:ty),*] D7: [$($D7:ty),*]
CKIN: [$($CKIN:ty),*] CDIR: [$($CDIR:ty),*]
D0DIR: [$($D0DIR:ty),*] D123DIR: [$($D123DIR:ty),*]
)+) => {
$(
$(
impl PinClk<$SDMMCX> for $CLK {}
)*
$(
impl PinCmd<$SDMMCX> for $CMD {}
)*
$(
impl PinD0<$SDMMCX> for $D0 {}
)*
$(
impl PinD1<$SDMMCX> for $D1 {}
)*
$(
impl PinD2<$SDMMCX> for $D2 {}
)*
$(
impl PinD3<$SDMMCX> for $D3 {}
)*
$(
impl PinD4<$SDMMCX> for $D4 {}
)*
$(
impl PinD5<$SDMMCX> for $D5 {}
)*
$(
impl PinD6<$SDMMCX> for $D6 {}
)*
$(
impl PinD7<$SDMMCX> for $D7 {}
)*
)+
}
}
pins! {
SDMMC1:
CLK: [PC12<Alternate<AF12>>]
CMD: [PD2<Alternate<AF12>>]
D0: [PC8<Alternate<AF12>>]
D1: [PC9<Alternate<AF12>>]
D2: [PC10<Alternate<AF12>>]
D3: [PC11<Alternate<AF12>>]
D4: [PB8<Alternate<AF12>>]
D5: [PB9<Alternate<AF12>>]
D6: [PC6<Alternate<AF12>>]
D7: [PC7<Alternate<AF12>>]
CKIN: [PB8<Alternate<AF7>>]
CDIR: [PB9<Alternate<AF7>>]
D0DIR: [PC6<Alternate<AF8>>]
D123DIR: [PC7<Alternate<AF8>>]
SDMMC2:
CLK: [PC1<Alternate<AF9>>, PD6<Alternate<AF11>>]
CMD: [PA0<Alternate<AF9>>, PD7<Alternate<AF11>>]
D0: [PB14<Alternate<AF9>>]
D1: [PB15<Alternate<AF9>>]
D2: [PB3<Alternate<AF9>>, PG11<Alternate<AF10>>]
D3: [PB4<Alternate<AF9>>]
D4: [PB8<Alternate<AF10>>]
D5: [PB9<Alternate<AF10>>]
D6: [PC6<Alternate<AF10>>]
D7: [PC7<Alternate<AF10>>]
CKIN: []
CDIR: []
D0DIR: []
D123DIR: []
}
#[derive(Copy, Clone, Debug)]
#[allow(missing_docs)]
pub enum BusWidth {
One = 1,
Four = 4,
Eight = 8,
}
#[derive(Debug, Copy, Clone)]
#[non_exhaustive]
pub enum CardType {
SDSC,
SDHC,
}
impl Default for CardType {
fn default() -> Self {
CardType::SDSC
}
}
#[non_exhaustive]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum Signalling {
SDR12,
SDR25,
SDR50,
SDR104,
DDR50,
}
impl Default for Signalling {
fn default() -> Self {
Signalling::SDR12
}
}
#[non_exhaustive]
#[allow(missing_docs)]
#[derive(Debug, Copy, Clone)]
pub enum Error {
Timeout,
SoftwareTimeout,
UnsupportedCardVersion,
UnsupportedCardType,
Crc,
DataCrcFail,
RxOverFlow,
NoCard,
BadClock,
SignalingSwitchFailed,
}
struct Cmd {
cmd: u8,
arg: u32,
resp: Response,
}
#[derive(Clone, Copy, Debug, Default)]
pub struct Card {
pub card_type: CardType,
pub ocr: OCR,
pub rca: u32,
pub cid: CID,
pub csd: CSD,
pub scr: SCR,
pub status: SDStatus,
}
impl Card {
pub fn size(&self) -> u64 {
u64::from(self.csd.block_count()) * 512 * 1024
}
}
macro_rules! err_from_datapath_sm {
($status:ident) => {
if $status.dcrcfail().bit() {
return Err(Error::DataCrcFail);
} else if $status.rxoverr().bit() {
return Err(Error::RxOverFlow);
} else if $status.dtimeout().bit() {
return Err(Error::Timeout);
}
};
}
enum Dir {
CardToHost,
HostToCard,
}
enum PowerCtrl {
Off = 0b00,
On = 0b11,
}
#[repr(u32)]
#[allow(dead_code)]
#[allow(non_camel_case_types)]
enum CmdAppOper {
VOLTAGE_WINDOW_SD = 0x8010_0000,
HIGH_CAPACITY = 0x4000_0000,
SDMMC_STD_CAPACITY = 0x0000_0000,
SDMMC_CHECK_PATTERN = 0x0000_01AA,
SD_SWITCH_1_8V_CAPACITY = 0x0100_0000,
}
#[derive(Eq, PartialEq, Copy, Clone)]
enum Response {
None = 0,
Short = 1,
Long = 3,
}
#[derive(Eq, PartialEq, Copy, Clone)]
#[allow(dead_code)]
enum CardStatus {
Ready = 1,
Identification = 2,
Standby = 3,
Transfer = 4,
Sending = 5,
Receiving = 6,
Programming = 7,
Disconnected = 8,
Error,
}
impl From<u8> for CardStatus {
fn from(n: u8) -> Self {
match n {
1 => Self::Ready,
2 => Self::Identification,
3 => Self::Standby,
4 => Self::Transfer,
5 => Self::Sending,
6 => Self::Receiving,
7 => Self::Programming,
8 => Self::Disconnected,
_ => Self::Error,
}
}
}
pub struct Sdmmc<SDMMC> {
sdmmc: SDMMC,
ker_ck: Hertz,
hclk: Hertz,
bus_width: BusWidth,
clock: Hertz,
signalling: Signalling,
card: Option<Card>,
}
impl<SDMMC> fmt::Debug for Sdmmc<SDMMC> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SDMMC Peripheral")
.field("Card detected", &self.card.is_some())
.field("Bus Width (bits)", &self.bus_width)
.field("Signalling", &self.signalling)
.field("Bus Clock", &self.clock)
.finish()
}
}
pub trait SdmmcExt<SDMMC>: Sized {
type Rec: ResetEnable;
fn sdmmc<PINS>(
self,
_pins: PINS,
prec: Self::Rec,
clocks: &CoreClocks,
) -> Sdmmc<SDMMC>
where
PINS: Pins<SDMMC>;
fn sdmmc_unchecked(
self,
bus_width: BusWidth,
prec: Self::Rec,
clocks: &CoreClocks,
) -> Sdmmc<SDMMC>;
}
impl<S> Sdmmc<S> {
fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(u16, Hertz), Error> {
match (ker_ck.0 + sdmmc_ck - 1) / sdmmc_ck {
0 | 1 => Ok((0, ker_ck)),
x @ 2..=2046 => {
let clk_div = ((x + 1) / 2) as u16;
let clk = Hertz(ker_ck.0 / (clk_div as u32 * 2));
Ok((clk_div, clk))
}
_ => Err(Error::BadClock),
}
}
}
macro_rules! sdmmc {
($($SDMMCX:ident: ($sdmmcX:ident, $Rec:ident),)+) => {
$(
impl SdmmcExt<$SDMMCX> for $SDMMCX {
type Rec = rec::$Rec;
fn sdmmc<PINS>(self, _pins: PINS,
prec: rec::$Rec,
clocks: &CoreClocks) -> Sdmmc<$SDMMCX>
where
PINS: Pins<$SDMMCX>,
{
Sdmmc::$sdmmcX(self, PINS::BUSWIDTH, prec, clocks)
}
fn sdmmc_unchecked(self, bus_width: BusWidth,
prec: rec::$Rec,
clocks: &CoreClocks) -> Sdmmc<$SDMMCX>
{
Sdmmc::$sdmmcX(self, bus_width, prec, clocks)
}
}
impl Sdmmc<$SDMMCX> {
fn clkcr_set_clkdiv(
&mut self,
freq: u32,
width: BusWidth,
) -> Result<(), Error> {
let (clkdiv, new_clock) = Self::clk_div(self.ker_ck, freq)?;
let sdmmc_bus_bandwidth = new_clock.0 * (width as u32);
debug_assert!(self.hclk.0 > 3 * sdmmc_bus_bandwidth / 32);
self.clock = new_clock;
while self.sdmmc.star.read().dpsmact().bit_is_set()
|| self.sdmmc.star.read().cpsmact().bit_is_set()
{}
self.sdmmc
.clkcr
.modify(|_, w| unsafe { w.clkdiv().bits(clkdiv) });
Ok(())
}
pub fn $sdmmcX(
sdmmc: $SDMMCX,
bus_width: BusWidth,
prec: rec::$Rec,
clocks: &CoreClocks,
) -> Self {
let prec = prec.enable().reset();
let hclk = clocks.hclk();
let ker_ck = match prec.get_kernel_clk_mux() {
rec::SdmmcClkSel::PLL1_Q => clocks.pll1_q_ck(),
rec::SdmmcClkSel::PLL2_R => clocks.pll2_r_ck(),
}
.expect("sdmmc_ker_ck not running!");
let (clkdiv, clock) = Self::clk_div(ker_ck, 400_000)
.expect("SDMMC too slow. Cannot be generated from ker_ck");
sdmmc.clkcr.write(|w| unsafe {
w.widbus()
.bits(0)
.clkdiv()
.bits(clkdiv)
.pwrsav()
.clear_bit()
.negedge()
.clear_bit()
.hwfc_en()
.set_bit()
});
sdmmc
.power
.modify(|_, w| unsafe { w.pwrctrl().bits(PowerCtrl::Off as u8) });
Sdmmc {
sdmmc,
ker_ck,
hclk,
bus_width,
card: None,
clock,
signalling: Default::default(),
}
}
pub fn init_card(&mut self, freq: impl Into<Hertz>) -> Result<(), Error> {
let freq = freq.into();
self.sdmmc
.power
.modify(|_, w| unsafe { w.pwrctrl().bits(PowerCtrl::On as u8) });
self.cmd(Cmd::idle())?;
self.cmd(Cmd::hs_send_ext_csd(0x1AA))?;
let r1 = self.sdmmc.resp1r.read().bits();
let mut card = if r1 == 0x1AA {
Card::default()
} else {
return Err(Error::UnsupportedCardVersion);
};
let ocr = loop {
self.cmd(Cmd::app_cmd(0))?;
let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32
| CmdAppOper::HIGH_CAPACITY as u32
| CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32;
match self.cmd(Cmd::app_op_cmd(arg)) {
Ok(_) => (),
Err(Error::Crc) => (),
Err(err) => return Err(err),
}
let ocr = OCR(self.sdmmc.resp1r.read().bits());
if !ocr.is_busy() {
break ocr;
}
};
if ocr.ccs() {
card.card_type = CardType::SDHC;
} else {
return Err(Error::UnsupportedCardType);
}
card.ocr = ocr;
self.cmd(Cmd::all_send_cid())?;
let cid = ((self.sdmmc.resp1r.read().bits() as u128) << 96)
| ((self.sdmmc.resp2r.read().bits() as u128) << 64)
| ((self.sdmmc.resp3r.read().bits() as u128) << 32)
| self.sdmmc.resp4r.read().bits() as u128;
card.cid = CID::new(cid);
self.cmd(Cmd::send_rel_addr())?;
card.rca = self.sdmmc.resp1r.read().bits() >> 16;
self.cmd(Cmd::send_csd(card.rca << 16))?;
let csd = ((self.sdmmc.resp1r.read().bits() as u128) << 96)
| ((self.sdmmc.resp2r.read().bits() as u128) << 64)
| ((self.sdmmc.resp3r.read().bits() as u128) << 32)
| self.sdmmc.resp4r.read().bits() as u128;
card.csd = CSD(csd);
self.select_card(Some(&card))?;
self.get_scr(&mut card)?;
let (width, acmd_arg) = match self.bus_width {
BusWidth::Eight => unimplemented!(),
BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2),
_ => (BusWidth::One, 0),
};
self.cmd(Cmd::app_cmd(card.rca << 16))?;
self.cmd(Cmd::cmd6(acmd_arg))?;
while self.sdmmc.star.read().dpsmact().bit_is_set()
|| self.sdmmc.star.read().cpsmact().bit_is_set()
{}
self.sdmmc.clkcr.modify(|_, w| unsafe {
w.widbus().bits(match width {
BusWidth::One => 0,
BusWidth::Four => 1,
BusWidth::Eight => 2,
})
});
if freq.0 <= 25_000_000 {
self.clkcr_set_clkdiv(freq.0, width)?;
} else {
self.clkcr_set_clkdiv(25_000_000, width)?;
sdmmc_trace!("Set intermediate clock frequency of 25MHz (SDR12 signalling");
}
let _old = self.card.replace(card);
self.read_sd_status()?;
if freq.0 > 25_000_000 {
self.signalling = self.switch_signalling_mode(Signalling::SDR25)?;
if self.signalling == Signalling::SDR25 {
self.clkcr_set_clkdiv(freq.0, width)?;
if self.send_status()? != CardStatus::Transfer {
return Err(Error::SignalingSwitchFailed);
}
}
sdmmc_trace!("Set final clock frequency of {}", freq.0);
}
Ok(())
}
pub fn card(&self) -> Result<&Card, Error> {
self.card.as_ref().ok_or(Error::NoCard)
}
pub fn clock(&self) -> Hertz {
self.clock
}
fn start_datapath_transfer(
&self,
length_bytes: u32,
block_size: u8,
direction: Dir,
) {
assert!(block_size <= 14);
let ddr = self.sdmmc.clkcr.read().ddr().bit_is_set();
assert!(
!ddr || block_size != 0,
"Block size must be >= 1, or >= 2 is DDR mode"
);
let dtdir = match direction {
Dir::CardToHost => true,
_ => false,
};
while self.sdmmc.star.read().dpsmact().bit_is_set()
|| self.sdmmc.star.read().cpsmact().bit_is_set()
{}
self.sdmmc
.dtimer
.write(|w| unsafe { w.datatime().bits(5_000_000) });
self.sdmmc
.dlenr
.write(|w| unsafe { w.datalength().bits(length_bytes) });
self.sdmmc.dctrl.write(|w| unsafe {
w.dblocksize()
.bits(block_size)
.dtdir()
.bit(dtdir)
.dten()
.set_bit()
});
}
pub fn read_block(
&mut self,
address: u32,
buffer: &mut [u8; 512],
) -> Result<(), Error> {
let _card = self.card()?;
self.cmd(Cmd::set_block_length(512))?;
self.start_datapath_transfer(512, 9, Dir::CardToHost);
self.cmd(Cmd::read_single_block(address))?;
let mut i = 0;
let mut status;
while {
status = self.sdmmc.star.read();
!(status.rxoverr().bit()
|| status.dcrcfail().bit()
|| status.dtimeout().bit()
|| status.dataend().bit())
} {
if status.rxfifohf().bit() {
for _ in 0..8 {
let bytes = self.sdmmc.fifor.read().bits().to_le_bytes();
buffer[i..i + 4].copy_from_slice(&bytes);
i += 4;
}
}
if i >= buffer.len() {
break;
}
}
err_from_datapath_sm!(status);
Ok(())
}
pub fn read_blocks(
&mut self,
address: u32,
buffer: &mut [u8],
) -> Result<(), Error> {
let _card = self.card()?;
assert!(buffer.len() % 512 == 0);
let n_blocks = buffer.len() / 512;
self.cmd(Cmd::set_block_length(512))?;
self.start_datapath_transfer(512 * n_blocks as u32, 9, Dir::CardToHost);
self.cmd(Cmd::read_multiple_blocks(address))?;
let mut i = 0;
let mut status;
while {
status = self.sdmmc.star.read();
!(status.rxoverr().bit()
|| status.dcrcfail().bit()
|| status.dtimeout().bit()
|| status.dataend().bit())
} {
if status.rxfifohf().bit() {
for _ in 0..8 {
let bytes = self.sdmmc.fifor.read().bits().to_le_bytes();
buffer[i..i + 4].copy_from_slice(&bytes);
i += 4;
}
}
if i >= buffer.len() {
break;
}
}
self.cmd(Cmd::stop_transmission())?;
err_from_datapath_sm!(status);
Ok(())
}
pub fn write_block(
&mut self,
address: u32,
buffer: &[u8; 512]
) -> Result<(), Error> {
let _card = self.card()?;
self.cmd(Cmd::set_block_length(512))?;
self.start_datapath_transfer(512, 9, Dir::HostToCard);
self.cmd(Cmd::write_single_block(address))?;
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;
}
}
err_from_datapath_sm!(status);
self.clear_static_interrupt_flags();
let mut timeout: u32 = 0xFFFF_FFFF;
while timeout > 0 {
match self.read_sd_status() {
Ok(_) => return Ok(()),
Err(Error::Timeout) => (),
Err(e) => return Err(e),
}
timeout -= 1;
}
Err(Error::SoftwareTimeout)
}
fn send_status(&self) -> Result<CardStatus, Error> {
let card = self.card()?;
self.cmd(Cmd::card_status(card.rca << 16))?;
let r1 = self.sdmmc.resp1r.read().bits();
let cardstate = (r1 >> 9) as u8 & 0xF;
Ok(cardstate.into())
}
fn read_sd_status(&mut self) -> Result<(), Error> {
let card = self.card()?;
self.cmd(Cmd::set_block_length(64))?;
self.cmd(Cmd::app_cmd(card.rca << 16))?;
self.start_datapath_transfer(64, 6, Dir::CardToHost);
self.cmd(Cmd::card_status(0))?;
let mut status = [0u32; 16];
let mut idx = 0;
let mut sta_reg;
while {
sta_reg = self.sdmmc.star.read();
!(sta_reg.rxoverr().bit()
|| sta_reg.dcrcfail().bit()
|| sta_reg.dtimeout().bit()
|| sta_reg.dbckend().bit())
} {
if sta_reg.rxfifohf().bit() {
for _ in 0..8 {
status[idx] = self.sdmmc.fifor.read().bits();
idx += 1;
}
}
if idx == status.len() {
break;
}
}
err_from_datapath_sm!(sta_reg);
let card = self.card.as_mut().ok_or(Error::NoCard)?;
card.status = SDStatus::new(status);
Ok(())
}
fn get_scr(&self, card: &mut Card) -> Result<(), Error> {
self.cmd(Cmd::set_block_length(8))?;
self.cmd(Cmd::app_cmd(card.rca << 16))?;
self.start_datapath_transfer(8, 3, Dir::CardToHost);
self.cmd(Cmd::cmd51())?;
let mut scr = [0; 2];
let mut i = 0;
let mut status;
while {
status = self.sdmmc.star.read();
!(status.rxoverr().bit()
|| status.dcrcfail().bit()
|| status.dtimeout().bit()
|| status.dbckend().bit())
} {
if status.rxfifoe().bit_is_clear() {
scr[i] = self.sdmmc.fifor.read().bits();
i += 1;
}
if i == 2 {
break;
}
}
err_from_datapath_sm!(status);
let scr = ((scr[1] as u64) << 32) | scr[0] as u64;
card.scr = SCR(u64::from_be(scr));
Ok(())
}
fn switch_signalling_mode(
&self,
signalling: Signalling,
) -> Result<Signalling, Error> {
let set_function = 0x8000_0000
| match signalling {
Signalling::DDR50 => 0xFF_FF04,
Signalling::SDR104 => 0xFF_1F03,
Signalling::SDR50 => 0xFF_1F02,
Signalling::SDR25 => 0xFF_FF01,
Signalling::SDR12 => 0xFF_FF00,
};
self.start_datapath_transfer(64, 6, Dir::CardToHost);
self.cmd(Cmd::cmd6(set_function))?;
let mut status = [0u32; 16];
let mut idx = 0;
let mut sta_reg;
while {
sta_reg = self.sdmmc.star.read();
!(sta_reg.rxoverr().bit()
|| sta_reg.dcrcfail().bit()
|| sta_reg.dtimeout().bit()
|| sta_reg.dbckend().bit())
} {
if sta_reg.rxfifohf().bit() {
for _ in 0..8 {
status[idx] = self.sdmmc.fifor.read().bits();
idx += 1;
}
}
if idx == status.len() {
break;
}
}
err_from_datapath_sm!(sta_reg);
for _ in 0..300 {
cortex_m::asm::nop();
}
let _support_bits = u32::from_be(status[3]) >> 16;
let selection = (u32::from_be(status[4]) >> 24) & 0xF;
match selection {
0 => Ok(Signalling::SDR12),
1 => Ok(Signalling::SDR25),
2 => Ok(Signalling::SDR50),
3 => Ok(Signalling::SDR104),
4 => Ok(Signalling::DDR50),
_ => Err(Error::UnsupportedCardType),
}
}
fn select_card(&self, card: Option<&Card>) -> Result<(), Error> {
let rca = card.map(|c| c.rca << 16).unwrap_or(0);
let r = self.cmd(Cmd::sel_desel_card(rca));
match (r, rca) {
(Err(Error::Timeout), 0) => Ok(()),
_ => r,
}
}
fn clear_static_interrupt_flags(&self) {
self.sdmmc.icr.modify(|_, w| {
w.dcrcfailc()
.set_bit()
.dtimeoutc()
.set_bit()
.txunderrc()
.set_bit()
.rxoverrc()
.set_bit()
.dataendc()
.set_bit()
.dholdc()
.set_bit()
.dbckendc()
.set_bit()
.dabortc()
.set_bit()
.idmatec()
.set_bit()
.idmabtcc()
.set_bit()
});
}
fn cmd(&self, cmd: Cmd) -> Result<(), Error> {
self.sdmmc.icr.modify(|_, w| {
w.ccrcfailc()
.set_bit()
.ctimeoutc()
.set_bit()
.cmdrendc()
.set_bit()
.cmdsentc()
.set_bit()
.dataendc()
.set_bit()
.dbckendc()
.set_bit()
.dcrcfailc()
.set_bit()
.dtimeoutc()
.set_bit()
.sdioitc()
.set_bit()
.rxoverrc()
.set_bit()
.txunderrc()
.set_bit()
});
while self.sdmmc.star.read().cpsmact().bit_is_set() {}
self.sdmmc
.argr
.write(|w| unsafe { w.cmdarg().bits(cmd.arg) });
let cpsm_stop_transmission = (cmd.cmd == 12);
self.sdmmc.cmdr.write(|w| unsafe {
w.waitint()
.clear_bit()
.waitresp()
.bits(cmd.resp as u8)
.cmdstop()
.bit(cpsm_stop_transmission)
.cmdindex()
.bits(cmd.cmd)
.cpsmen()
.set_bit()
});
let mut timeout: u32 = 0xFFFF_FFFF;
let mut status;
if cmd.resp == Response::None {
while {
status = self.sdmmc.star.read();
!(status.ctimeout().bit() || status.cmdsent().bit())
&& timeout > 0
} {
timeout -= 1;
}
} else {
while {
status = self.sdmmc.star.read();
!(status.ctimeout().bit()
|| status.cmdrend().bit()
|| status.ccrcfail().bit())
&& timeout > 0
} {
timeout -= 1;
}
}
if status.ctimeout().bit_is_set() {
return Err(Error::Timeout);
} else if timeout == 0 {
return Err(Error::SoftwareTimeout);
} else if status.ccrcfail().bit() {
return Err(Error::Crc);
}
Ok(())
}
}
)+
};
}
sdmmc! {
SDMMC1: (sdmmc1, Sdmmc1),
SDMMC2: (sdmmc2, Sdmmc2),
}
impl Cmd {
const fn new(cmd: u8, arg: u32, resp: Response) -> Cmd {
Cmd { cmd, arg, resp }
}
const fn idle() -> Cmd {
Cmd::new(0, 0, Response::None)
}
const fn all_send_cid() -> Cmd {
Cmd::new(2, 0, Response::Long)
}
const fn send_rel_addr() -> Cmd {
Cmd::new(3, 0, Response::Short)
}
const fn cmd6(arg: u32) -> Cmd {
Cmd::new(6, arg, Response::Short)
}
const fn sel_desel_card(rca: u32) -> Cmd {
Cmd::new(7, rca, Response::Short)
}
const fn hs_send_ext_csd(arg: u32) -> Cmd {
Cmd::new(8, arg, Response::Short)
}
const fn send_csd(rca: u32) -> Cmd {
Cmd::new(9, rca, Response::Long)
}
const fn stop_transmission() -> Cmd {
Cmd::new(12, 0, Response::Short)
}
const fn card_status(rca: u32) -> Cmd {
Cmd::new(13, rca, Response::Short)
}
const fn set_block_length(blocklen: u32) -> Cmd {
Cmd::new(16, blocklen, Response::Short)
}
const fn read_single_block(addr: u32) -> Cmd {
Cmd::new(17, addr, Response::Short)
}
const fn read_multiple_blocks(addr: u32) -> Cmd {
Cmd::new(18, addr, Response::Short)
}
const fn write_single_block(addr: u32) -> Cmd {
Cmd::new(24, addr, Response::Short)
}
const fn app_op_cmd(arg: u32) -> Cmd {
Cmd::new(41, arg, Response::Short)
}
const fn cmd51() -> Cmd {
Cmd::new(51, 0, Response::Short)
}
const fn app_cmd(rca: u32) -> Cmd {
Cmd::new(55, rca, Response::Short)
}
}