stm32: update stm32-metapac.

This commit is contained in:
Dario Nieuwenhuis
2023-06-19 03:07:26 +02:00
parent adaed307b4
commit 558918651e
68 changed files with 2893 additions and 3568 deletions

View File

@ -28,17 +28,14 @@ pub struct InterruptHandler<T: Instance> {
impl<T: Instance> InterruptHandler<T> {
fn data_interrupts(enable: bool) {
let regs = T::regs();
// NOTE(unsafe) Atomic write
unsafe {
regs.maskr().write(|w| {
w.set_dcrcfailie(enable);
w.set_dtimeoutie(enable);
w.set_dataendie(enable);
regs.maskr().write(|w| {
w.set_dcrcfailie(enable);
w.set_dtimeoutie(enable);
w.set_dataendie(enable);
#[cfg(sdmmc_v2)]
w.set_dabortie(enable);
});
}
#[cfg(sdmmc_v2)]
w.set_dabortie(enable);
});
}
}
@ -285,7 +282,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
) -> Self {
into_ref!(clk, cmd, d0);
critical_section::with(|_| unsafe {
critical_section::with(|_| {
clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
@ -322,7 +319,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
) -> Self {
into_ref!(clk, cmd, d0, d1, d2, d3);
critical_section::with(|_| unsafe {
critical_section::with(|_| {
clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
@ -364,7 +361,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
) -> Self {
into_ref!(clk, cmd, d0);
critical_section::with(|_| unsafe {
critical_section::with(|_| {
clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
@ -400,7 +397,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
) -> Self {
into_ref!(clk, cmd, d0, d1, d2, d3);
critical_section::with(|_| unsafe {
critical_section::with(|_| {
clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
@ -451,26 +448,24 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
unsafe { T::Interrupt::enable() };
let regs = T::regs();
unsafe {
regs.clkcr().write(|w| {
w.set_pwrsav(false);
w.set_negedge(false);
regs.clkcr().write(|w| {
w.set_pwrsav(false);
w.set_negedge(false);
// Hardware flow control is broken on SDIOv1 and causes clock glitches, which result in CRC errors.
// See chip erratas for more details.
#[cfg(sdmmc_v1)]
w.set_hwfc_en(false);
#[cfg(sdmmc_v2)]
w.set_hwfc_en(true);
// Hardware flow control is broken on SDIOv1 and causes clock glitches, which result in CRC errors.
// See chip erratas for more details.
#[cfg(sdmmc_v1)]
w.set_hwfc_en(false);
#[cfg(sdmmc_v2)]
w.set_hwfc_en(true);
#[cfg(sdmmc_v1)]
w.set_clken(true);
});
#[cfg(sdmmc_v1)]
w.set_clken(true);
});
// Power off, writen 00: Clock to the card is stopped;
// D[7:0], CMD, and CK are driven high.
regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8));
}
// Power off, writen 00: Clock to the card is stopped;
// D[7:0], CMD, and CK are driven high.
regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8));
Self {
_peri: sdmmc,
@ -495,14 +490,11 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
fn data_active() -> bool {
let regs = T::regs();
// NOTE(unsafe) Atomic read with no side-effects
unsafe {
let status = regs.star().read();
#[cfg(sdmmc_v1)]
return status.rxact() || status.txact();
#[cfg(sdmmc_v2)]
return status.dpsmact();
}
let status = regs.star().read();
#[cfg(sdmmc_v1)]
return status.rxact() || status.txact();
#[cfg(sdmmc_v2)]
return status.dpsmact();
}
/// Coammand transfer is in progress
@ -510,14 +502,11 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
fn cmd_active() -> bool {
let regs = T::regs();
// NOTE(unsafe) Atomic read with no side-effects
unsafe {
let status = regs.star().read();
#[cfg(sdmmc_v1)]
return status.cmdact();
#[cfg(sdmmc_v2)]
return status.cpsmact();
}
let status = regs.star().read();
#[cfg(sdmmc_v1)]
return status.cmdact();
#[cfg(sdmmc_v2)]
return status.cpsmact();
}
/// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2)
@ -542,44 +531,41 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
Self::wait_idle();
Self::clear_interrupt_flags();
// NOTE(unsafe) We have exclusive access to the regisers
unsafe {
regs.dtimer()
.write(|w| w.set_datatime(self.config.data_transfer_timeout));
regs.dlenr().write(|w| w.set_datalength(length_bytes));
regs.dtimer()
.write(|w| w.set_datatime(self.config.data_transfer_timeout));
regs.dlenr().write(|w| w.set_datalength(length_bytes));
#[cfg(sdmmc_v1)]
let transfer = unsafe {
let request = self.dma.request();
Transfer::new_read(
&mut self.dma,
request,
regs.fifor().as_ptr() as *mut u32,
buffer,
DMA_TRANSFER_OPTIONS,
)
};
#[cfg(sdmmc_v2)]
let transfer = {
regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32));
regs.idmactrlr().modify(|w| w.set_idmaen(true));
Transfer {
_dummy: core::marker::PhantomData,
}
};
regs.dctrl().modify(|w| {
w.set_dblocksize(block_size);
w.set_dtdir(true);
#[cfg(sdmmc_v1)]
let transfer = {
let request = self.dma.request();
Transfer::new_read(
&mut self.dma,
request,
regs.fifor().ptr() as *mut u32,
buffer,
DMA_TRANSFER_OPTIONS,
)
};
#[cfg(sdmmc_v2)]
let transfer = {
regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32));
regs.idmactrlr().modify(|w| w.set_idmaen(true));
Transfer {
_dummy: core::marker::PhantomData,
}
};
{
w.set_dmaen(true);
w.set_dten(true);
}
});
regs.dctrl().modify(|w| {
w.set_dblocksize(block_size);
w.set_dtdir(true);
#[cfg(sdmmc_v1)]
{
w.set_dmaen(true);
w.set_dten(true);
}
});
transfer
}
transfer
}
/// # Safety
@ -598,59 +584,54 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
Self::wait_idle();
Self::clear_interrupt_flags();
// NOTE(unsafe) We have exclusive access to the regisers
unsafe {
regs.dtimer()
.write(|w| w.set_datatime(self.config.data_transfer_timeout));
regs.dlenr().write(|w| w.set_datalength(length_bytes));
regs.dtimer()
.write(|w| w.set_datatime(self.config.data_transfer_timeout));
regs.dlenr().write(|w| w.set_datalength(length_bytes));
#[cfg(sdmmc_v1)]
let transfer = unsafe {
let request = self.dma.request();
Transfer::new_write(
&mut self.dma,
request,
buffer,
regs.fifor().as_ptr() as *mut u32,
DMA_TRANSFER_OPTIONS,
)
};
#[cfg(sdmmc_v2)]
let transfer = {
regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_ptr() as u32));
regs.idmactrlr().modify(|w| w.set_idmaen(true));
Transfer {
_dummy: core::marker::PhantomData,
}
};
regs.dctrl().modify(|w| {
w.set_dblocksize(block_size);
w.set_dtdir(false);
#[cfg(sdmmc_v1)]
let transfer = {
let request = self.dma.request();
Transfer::new_write(
&mut self.dma,
request,
buffer,
regs.fifor().ptr() as *mut u32,
DMA_TRANSFER_OPTIONS,
)
};
#[cfg(sdmmc_v2)]
let transfer = {
regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_ptr() as u32));
regs.idmactrlr().modify(|w| w.set_idmaen(true));
Transfer {
_dummy: core::marker::PhantomData,
}
};
{
w.set_dmaen(true);
w.set_dten(true);
}
});
regs.dctrl().modify(|w| {
w.set_dblocksize(block_size);
w.set_dtdir(false);
#[cfg(sdmmc_v1)]
{
w.set_dmaen(true);
w.set_dten(true);
}
});
transfer
}
transfer
}
/// Stops the DMA datapath
fn stop_datapath() {
let regs = T::regs();
unsafe {
#[cfg(sdmmc_v1)]
regs.dctrl().modify(|w| {
w.set_dmaen(false);
w.set_dten(false);
});
#[cfg(sdmmc_v2)]
regs.idmactrlr().modify(|w| w.set_idmaen(false));
}
#[cfg(sdmmc_v1)]
regs.dctrl().modify(|w| {
w.set_dmaen(false);
w.set_dten(false);
});
#[cfg(sdmmc_v2)]
regs.idmactrlr().modify(|w| w.set_idmaen(false));
}
/// Sets the CLKDIV field in CLKCR. Updates clock field in self
@ -673,16 +654,13 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32);
self.clock = new_clock;
// NOTE(unsafe) We have exclusive access to the regblock
unsafe {
// CPSMACT and DPSMACT must be 0 to set CLKDIV
Self::wait_idle();
regs.clkcr().modify(|w| {
w.set_clkdiv(clkdiv);
#[cfg(sdmmc_v1)]
w.set_bypass(_bypass);
});
}
// CPSMACT and DPSMACT must be 0 to set CLKDIV
Self::wait_idle();
regs.clkcr().modify(|w| {
w.set_clkdiv(clkdiv);
#[cfg(sdmmc_v1)]
w.set_bypass(_bypass);
});
Ok(())
}
@ -710,7 +688,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
// Arm `OnDrop` after the buffer, so it will be dropped first
let regs = T::regs();
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
let on_drop = OnDrop::new(|| Self::on_drop());
let transfer = self.prepare_datapath_read(&mut status, 64, 6);
InterruptHandler::<T>::data_interrupts(true);
@ -718,7 +696,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
let res = poll_fn(|cx| {
T::state().register(cx.waker());
let status = unsafe { regs.star().read() };
let status = regs.star().read();
if status.dcrcfail() {
return Poll::Ready(Err(Error::Crc));
@ -769,8 +747,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
Self::cmd(Cmd::card_status(rca << 16), false)?; // CMD13
// NOTE(unsafe) Atomic read with no side-effects
let r1 = unsafe { regs.respr(0).read().cardstatus() };
let r1 = regs.respr(0).read().cardstatus();
Ok(r1.into())
}
@ -786,7 +763,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
// Arm `OnDrop` after the buffer, so it will be dropped first
let regs = T::regs();
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
let on_drop = OnDrop::new(|| Self::on_drop());
let transfer = self.prepare_datapath_read(&mut status, 64, 6);
InterruptHandler::<T>::data_interrupts(true);
@ -794,7 +771,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
let res = poll_fn(|cx| {
T::state().register(cx.waker());
let status = unsafe { regs.star().read() };
let status = regs.star().read();
if status.dcrcfail() {
return Poll::Ready(Err(Error::Crc));
@ -840,35 +817,32 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
#[inline(always)]
fn clear_interrupt_flags() {
let regs = T::regs();
// NOTE(unsafe) Atomic write
unsafe {
regs.icr().write(|w| {
w.set_ccrcfailc(true);
w.set_dcrcfailc(true);
w.set_ctimeoutc(true);
w.set_dtimeoutc(true);
w.set_txunderrc(true);
w.set_rxoverrc(true);
w.set_cmdrendc(true);
w.set_cmdsentc(true);
w.set_dataendc(true);
w.set_dbckendc(true);
w.set_sdioitc(true);
regs.icr().write(|w| {
w.set_ccrcfailc(true);
w.set_dcrcfailc(true);
w.set_ctimeoutc(true);
w.set_dtimeoutc(true);
w.set_txunderrc(true);
w.set_rxoverrc(true);
w.set_cmdrendc(true);
w.set_cmdsentc(true);
w.set_dataendc(true);
w.set_dbckendc(true);
w.set_sdioitc(true);
#[cfg(sdmmc_v2)]
{
w.set_dholdc(true);
w.set_dabortc(true);
w.set_busyd0endc(true);
w.set_ackfailc(true);
w.set_acktimeoutc(true);
w.set_vswendc(true);
w.set_ckstopc(true);
w.set_idmatec(true);
w.set_idmabtcc(true);
}
});
}
#[cfg(sdmmc_v2)]
{
w.set_dholdc(true);
w.set_dabortc(true);
w.set_busyd0endc(true);
w.set_ackfailc(true);
w.set_acktimeoutc(true);
w.set_vswendc(true);
w.set_ckstopc(true);
w.set_idmatec(true);
w.set_idmabtcc(true);
}
});
}
async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> {
@ -880,7 +854,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
// Arm `OnDrop` after the buffer, so it will be dropped first
let regs = T::regs();
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
let on_drop = OnDrop::new(|| Self::on_drop());
let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3);
InterruptHandler::<T>::data_interrupts(true);
@ -888,7 +862,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
let res = poll_fn(|cx| {
T::state().register(cx.waker());
let status = unsafe { regs.star().read() };
let status = regs.star().read();
if status.dcrcfail() {
return Poll::Ready(Err(Error::Crc));
@ -921,59 +895,53 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
let regs = T::regs();
Self::clear_interrupt_flags();
// NOTE(safety) Atomic operations
unsafe {
// CP state machine must be idle
while Self::cmd_active() {}
// CP state machine must be idle
while Self::cmd_active() {}
// Command arg
regs.argr().write(|w| w.set_cmdarg(cmd.arg));
// Command arg
regs.argr().write(|w| w.set_cmdarg(cmd.arg));
// Command index and start CP State Machine
regs.cmdr().write(|w| {
w.set_waitint(false);
w.set_waitresp(cmd.resp as u8);
w.set_cmdindex(cmd.cmd);
w.set_cpsmen(true);
// Command index and start CP State Machine
regs.cmdr().write(|w| {
w.set_waitint(false);
w.set_waitresp(cmd.resp as u8);
w.set_cmdindex(cmd.cmd);
w.set_cpsmen(true);
#[cfg(sdmmc_v2)]
{
// Special mode in CP State Machine
// CMD12: Stop Transmission
let cpsm_stop_transmission = cmd.cmd == 12;
w.set_cmdstop(cpsm_stop_transmission);
w.set_cmdtrans(data);
}
});
let mut status;
if cmd.resp == Response::None {
// Wait for CMDSENT or a timeout
while {
status = regs.star().read();
!(status.ctimeout() || status.cmdsent())
} {}
} else {
// Wait for CMDREND or CCRCFAIL or a timeout
while {
status = regs.star().read();
!(status.ctimeout() || status.cmdrend() || status.ccrcfail())
} {}
#[cfg(sdmmc_v2)]
{
// Special mode in CP State Machine
// CMD12: Stop Transmission
let cpsm_stop_transmission = cmd.cmd == 12;
w.set_cmdstop(cpsm_stop_transmission);
w.set_cmdtrans(data);
}
});
if status.ctimeout() {
return Err(Error::Timeout);
} else if status.ccrcfail() {
return Err(Error::Crc);
}
Ok(())
let mut status;
if cmd.resp == Response::None {
// Wait for CMDSENT or a timeout
while {
status = regs.star().read();
!(status.ctimeout() || status.cmdsent())
} {}
} else {
// Wait for CMDREND or CCRCFAIL or a timeout
while {
status = regs.star().read();
!(status.ctimeout() || status.cmdrend() || status.ccrcfail())
} {}
}
if status.ctimeout() {
return Err(Error::Timeout);
} else if status.ccrcfail() {
return Err(Error::Crc);
}
Ok(())
}
/// # Safety
///
/// Ensure that `regs` has exclusive access to the regblocks
unsafe fn on_drop() {
fn on_drop() {
let regs = T::regs();
if Self::data_active() {
Self::clear_interrupt_flags();
@ -1017,141 +985,138 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
false => BusWidth::One,
};
// NOTE(unsafe) We have exclusive access to the peripheral
unsafe {
// While the SD/SDIO card or eMMC is in identification mode,
// the SDMMC_CK frequency must be no more than 400 kHz.
let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
self.clock = init_clock;
// While the SD/SDIO card or eMMC is in identification mode,
// the SDMMC_CK frequency must be no more than 400 kHz.
let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
self.clock = init_clock;
// CPSMACT and DPSMACT must be 0 to set WIDBUS
Self::wait_idle();
// CPSMACT and DPSMACT must be 0 to set WIDBUS
Self::wait_idle();
regs.clkcr().modify(|w| {
w.set_widbus(0);
w.set_clkdiv(clkdiv);
#[cfg(sdmmc_v1)]
w.set_bypass(_bypass);
});
regs.clkcr().modify(|w| {
w.set_widbus(0);
w.set_clkdiv(clkdiv);
#[cfg(sdmmc_v1)]
w.set_bypass(_bypass);
});
regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
Self::cmd(Cmd::idle(), false)?;
regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
Self::cmd(Cmd::idle(), false)?;
// Check if cards supports CMD8 (with pattern)
Self::cmd(Cmd::hs_send_ext_csd(0x1AA), false)?;
let r1 = regs.respr(0).read().cardstatus();
// Check if cards supports CMD8 (with pattern)
Self::cmd(Cmd::hs_send_ext_csd(0x1AA), false)?;
let r1 = regs.respr(0).read().cardstatus();
let mut card = if r1 == 0x1AA {
// Card echoed back the pattern. Must be at least v2
Card::default()
} else {
return Err(Error::UnsupportedCardVersion);
};
let mut card = if r1 == 0x1AA {
// Card echoed back the pattern. Must be at least v2
Card::default()
} else {
return Err(Error::UnsupportedCardVersion);
};
let ocr = loop {
// Signal that next command is a app command
Self::cmd(Cmd::app_cmd(0), false)?; // CMD55
let ocr = loop {
// Signal that next command is a app command
Self::cmd(Cmd::app_cmd(0), false)?; // CMD55
let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32
| CmdAppOper::HIGH_CAPACITY as u32
| CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32;
let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32
| CmdAppOper::HIGH_CAPACITY as u32
| CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32;
// Initialize card
match Self::cmd(Cmd::app_op_cmd(arg), false) {
// ACMD41
Ok(_) => (),
Err(Error::Crc) => (),
Err(err) => return Err(err),
}
let ocr: OCR = regs.respr(0).read().cardstatus().into();
if !ocr.is_busy() {
// Power up done
break ocr;
}
};
if ocr.high_capacity() {
// Card is SDHC or SDXC or SDUC
card.card_type = CardCapacity::SDHC;
} else {
card.card_type = CardCapacity::SDSC;
// Initialize card
match Self::cmd(Cmd::app_op_cmd(arg), false) {
// ACMD41
Ok(_) => (),
Err(Error::Crc) => (),
Err(err) => return Err(err),
}
card.ocr = ocr;
Self::cmd(Cmd::all_send_cid(), false)?; // CMD2
let cid0 = regs.respr(0).read().cardstatus() as u128;
let cid1 = regs.respr(1).read().cardstatus() as u128;
let cid2 = regs.respr(2).read().cardstatus() as u128;
let cid3 = regs.respr(3).read().cardstatus() as u128;
let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
card.cid = cid.into();
Self::cmd(Cmd::send_rel_addr(), false)?;
card.rca = regs.respr(0).read().cardstatus() >> 16;
Self::cmd(Cmd::send_csd(card.rca << 16), false)?;
let csd0 = regs.respr(0).read().cardstatus() as u128;
let csd1 = regs.respr(1).read().cardstatus() as u128;
let csd2 = regs.respr(2).read().cardstatus() as u128;
let csd3 = regs.respr(3).read().cardstatus() as u128;
let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
card.csd = csd.into();
self.select_card(Some(&card))?;
self.get_scr(&mut card).await?;
// Set bus width
let (width, acmd_arg) = match 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), false)?;
Self::cmd(Cmd::cmd6(acmd_arg), false)?;
// CPSMACT and DPSMACT must be 0 to set WIDBUS
Self::wait_idle();
regs.clkcr().modify(|w| {
w.set_widbus(match width {
BusWidth::One => 0,
BusWidth::Four => 1,
BusWidth::Eight => 2,
_ => panic!("Invalid Bus Width"),
})
});
// Set Clock
if freq.0 <= 25_000_000 {
// Final clock frequency
self.clkcr_set_clkdiv(freq.0, width)?;
} else {
// Switch to max clock for SDR12
self.clkcr_set_clkdiv(25_000_000, width)?;
let ocr: OCR = regs.respr(0).read().cardstatus().into();
if !ocr.is_busy() {
// Power up done
break ocr;
}
};
self.card = Some(card);
// Read status
self.read_sd_status().await?;
if freq.0 > 25_000_000 {
// Switch to SDR25
self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?;
if self.signalling == Signalling::SDR25 {
// Set final clock frequency
self.clkcr_set_clkdiv(freq.0, width)?;
if self.read_status(&card)?.state() != CurrentState::Transfer {
return Err(Error::SignalingSwitchFailed);
}
}
}
// Read status after signalling change
self.read_sd_status().await?;
if ocr.high_capacity() {
// Card is SDHC or SDXC or SDUC
card.card_type = CardCapacity::SDHC;
} else {
card.card_type = CardCapacity::SDSC;
}
card.ocr = ocr;
Self::cmd(Cmd::all_send_cid(), false)?; // CMD2
let cid0 = regs.respr(0).read().cardstatus() as u128;
let cid1 = regs.respr(1).read().cardstatus() as u128;
let cid2 = regs.respr(2).read().cardstatus() as u128;
let cid3 = regs.respr(3).read().cardstatus() as u128;
let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
card.cid = cid.into();
Self::cmd(Cmd::send_rel_addr(), false)?;
card.rca = regs.respr(0).read().cardstatus() >> 16;
Self::cmd(Cmd::send_csd(card.rca << 16), false)?;
let csd0 = regs.respr(0).read().cardstatus() as u128;
let csd1 = regs.respr(1).read().cardstatus() as u128;
let csd2 = regs.respr(2).read().cardstatus() as u128;
let csd3 = regs.respr(3).read().cardstatus() as u128;
let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
card.csd = csd.into();
self.select_card(Some(&card))?;
self.get_scr(&mut card).await?;
// Set bus width
let (width, acmd_arg) = match 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), false)?;
Self::cmd(Cmd::cmd6(acmd_arg), false)?;
// CPSMACT and DPSMACT must be 0 to set WIDBUS
Self::wait_idle();
regs.clkcr().modify(|w| {
w.set_widbus(match width {
BusWidth::One => 0,
BusWidth::Four => 1,
BusWidth::Eight => 2,
_ => panic!("Invalid Bus Width"),
})
});
// Set Clock
if freq.0 <= 25_000_000 {
// Final clock frequency
self.clkcr_set_clkdiv(freq.0, width)?;
} else {
// Switch to max clock for SDR12
self.clkcr_set_clkdiv(25_000_000, width)?;
}
self.card = Some(card);
// Read status
self.read_sd_status().await?;
if freq.0 > 25_000_000 {
// Switch to SDR25
self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?;
if self.signalling == Signalling::SDR25 {
// Set final clock frequency
self.clkcr_set_clkdiv(freq.0, width)?;
if self.read_status(&card)?.state() != CurrentState::Transfer {
return Err(Error::SignalingSwitchFailed);
}
}
}
// Read status after signalling change
self.read_sd_status().await?;
Ok(())
}
@ -1172,7 +1137,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
Self::cmd(Cmd::set_block_length(512), false)?; // CMD16
let regs = T::regs();
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
let on_drop = OnDrop::new(|| Self::on_drop());
let transfer = self.prepare_datapath_read(buffer, 512, 9);
InterruptHandler::<T>::data_interrupts(true);
@ -1180,7 +1145,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
let res = poll_fn(|cx| {
T::state().register(cx.waker());
let status = unsafe { regs.star().read() };
let status = regs.star().read();
if status.dcrcfail() {
return Poll::Ready(Err(Error::Crc));
@ -1217,7 +1182,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
Self::cmd(Cmd::set_block_length(512), false)?; // CMD16
let regs = T::regs();
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
let on_drop = OnDrop::new(|| Self::on_drop());
// sdmmc_v1 uses different cmd/dma order than v2, but only for writes
#[cfg(sdmmc_v1)]
@ -1231,7 +1196,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
let res = poll_fn(|cx| {
T::state().register(cx.waker());
let status = unsafe { regs.star().read() };
let status = regs.star().read();
if status.dcrcfail() {
return Poll::Ready(Err(Error::Crc));
@ -1289,9 +1254,9 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> {
fn drop(&mut self) {
T::Interrupt::disable();
unsafe { Self::on_drop() };
Self::on_drop();
critical_section::with(|_| unsafe {
critical_section::with(|_| {
self.clk.set_as_disconnected();
self.cmd.set_as_disconnected();
self.d0.set_as_disconnected();