mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-22 06:42:32 +00:00
Merge pull request #3188 from ninjasource/sdmmc-dma-buffers
embassy-stm32: Allow cmd block to be passed in for sdmmc dma transfers
This commit is contained in:
commit
2537fc6f4f
@ -94,6 +94,34 @@ impl DerefMut for DataBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Command Block buffer for SDMMC command transfers.
|
||||||
|
///
|
||||||
|
/// This is a 16-word array, exposed so that DMA commpatible memory can be used if required.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub struct CmdBlock(pub [u32; 16]);
|
||||||
|
|
||||||
|
impl CmdBlock {
|
||||||
|
/// Creates a new instance of CmdBlock
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self([0u32; 16])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for CmdBlock {
|
||||||
|
type Target = [u32; 16];
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for CmdBlock {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Errors
|
/// Errors
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
@ -292,6 +320,10 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> {
|
|||||||
signalling: Signalling,
|
signalling: Signalling,
|
||||||
/// Card
|
/// Card
|
||||||
card: Option<Card>,
|
card: Option<Card>,
|
||||||
|
|
||||||
|
/// An optional buffer to be used for commands
|
||||||
|
/// This should be used if there are special memory location requirements for dma
|
||||||
|
cmd_block: Option<&'d mut CmdBlock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const CLK_AF: AfType = AfType::output(OutputType::PushPull, Speed::VeryHigh);
|
const CLK_AF: AfType = AfType::output(OutputType::PushPull, Speed::VeryHigh);
|
||||||
@ -495,6 +527,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
clock: SD_INIT_FREQ,
|
clock: SD_INIT_FREQ,
|
||||||
signalling: Default::default(),
|
signalling: Default::default(),
|
||||||
card: None,
|
card: None,
|
||||||
|
cmd_block: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -531,8 +564,10 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// `buffer` must be valid for the whole transfer and word aligned
|
/// `buffer` must be valid for the whole transfer and word aligned
|
||||||
|
#[allow(unused_variables)]
|
||||||
fn prepare_datapath_read<'a>(
|
fn prepare_datapath_read<'a>(
|
||||||
&'a mut self,
|
config: &Config,
|
||||||
|
dma: &'a mut PeripheralRef<'d, Dma>,
|
||||||
buffer: &'a mut [u32],
|
buffer: &'a mut [u32],
|
||||||
length_bytes: u32,
|
length_bytes: u32,
|
||||||
block_size: u8,
|
block_size: u8,
|
||||||
@ -544,15 +579,14 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
Self::wait_idle();
|
Self::wait_idle();
|
||||||
Self::clear_interrupt_flags();
|
Self::clear_interrupt_flags();
|
||||||
|
|
||||||
regs.dtimer()
|
regs.dtimer().write(|w| w.set_datatime(config.data_transfer_timeout));
|
||||||
.write(|w| w.set_datatime(self.config.data_transfer_timeout));
|
|
||||||
regs.dlenr().write(|w| w.set_datalength(length_bytes));
|
regs.dlenr().write(|w| w.set_datalength(length_bytes));
|
||||||
|
|
||||||
#[cfg(sdmmc_v1)]
|
#[cfg(sdmmc_v1)]
|
||||||
let transfer = unsafe {
|
let transfer = unsafe {
|
||||||
let request = self.dma.request();
|
let request = dma.request();
|
||||||
Transfer::new_read(
|
Transfer::new_read(
|
||||||
&mut self.dma,
|
dma,
|
||||||
request,
|
request,
|
||||||
regs.fifor().as_ptr() as *mut u32,
|
regs.fifor().as_ptr() as *mut u32,
|
||||||
buffer,
|
buffer,
|
||||||
@ -692,13 +726,16 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
Signalling::SDR12 => 0xFF_FF00,
|
Signalling::SDR12 => 0xFF_FF00,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut status = [0u32; 16];
|
let status = match self.cmd_block.as_deref_mut() {
|
||||||
|
Some(x) => x,
|
||||||
|
None => &mut CmdBlock::new(),
|
||||||
|
};
|
||||||
|
|
||||||
// Arm `OnDrop` after the buffer, so it will be dropped first
|
// Arm `OnDrop` after the buffer, so it will be dropped first
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
let on_drop = OnDrop::new(|| Self::on_drop());
|
let on_drop = OnDrop::new(|| Self::on_drop());
|
||||||
|
|
||||||
let transfer = self.prepare_datapath_read(&mut status, 64, 6);
|
let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, status.as_mut(), 64, 6);
|
||||||
InterruptHandler::<T>::data_interrupts(true);
|
InterruptHandler::<T>::data_interrupts(true);
|
||||||
Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6
|
Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6
|
||||||
|
|
||||||
@ -770,16 +807,21 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
let card = self.card.as_mut().ok_or(Error::NoCard)?;
|
let card = self.card.as_mut().ok_or(Error::NoCard)?;
|
||||||
let rca = card.rca;
|
let rca = card.rca;
|
||||||
|
|
||||||
|
let cmd_block = match self.cmd_block.as_deref_mut() {
|
||||||
|
Some(x) => x,
|
||||||
|
None => &mut CmdBlock::new(),
|
||||||
|
};
|
||||||
|
|
||||||
Self::cmd(Cmd::set_block_length(64), false)?; // CMD16
|
Self::cmd(Cmd::set_block_length(64), false)?; // CMD16
|
||||||
Self::cmd(Cmd::app_cmd(rca << 16), false)?; // APP
|
Self::cmd(Cmd::app_cmd(rca << 16), false)?; // APP
|
||||||
|
|
||||||
let mut status = [0u32; 16];
|
let status = cmd_block;
|
||||||
|
|
||||||
// Arm `OnDrop` after the buffer, so it will be dropped first
|
// Arm `OnDrop` after the buffer, so it will be dropped first
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
let on_drop = OnDrop::new(|| Self::on_drop());
|
let on_drop = OnDrop::new(|| Self::on_drop());
|
||||||
|
|
||||||
let transfer = self.prepare_datapath_read(&mut status, 64, 6);
|
let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, status.as_mut(), 64, 6);
|
||||||
InterruptHandler::<T>::data_interrupts(true);
|
InterruptHandler::<T>::data_interrupts(true);
|
||||||
Self::cmd(Cmd::card_status(0), true)?;
|
Self::cmd(Cmd::card_status(0), true)?;
|
||||||
|
|
||||||
@ -813,7 +855,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
for byte in status.iter_mut() {
|
for byte in status.iter_mut() {
|
||||||
*byte = u32::from_be(*byte);
|
*byte = u32::from_be(*byte);
|
||||||
}
|
}
|
||||||
self.card.as_mut().unwrap().status = status.into();
|
self.card.as_mut().unwrap().status = status.0.into();
|
||||||
}
|
}
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
@ -872,13 +914,17 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
Self::cmd(Cmd::set_block_length(8), false)?; // CMD16
|
Self::cmd(Cmd::set_block_length(8), false)?; // CMD16
|
||||||
Self::cmd(Cmd::app_cmd(card.rca << 16), false)?;
|
Self::cmd(Cmd::app_cmd(card.rca << 16), false)?;
|
||||||
|
|
||||||
let mut scr = [0u32; 2];
|
let cmd_block = match self.cmd_block.as_deref_mut() {
|
||||||
|
Some(x) => x,
|
||||||
|
None => &mut CmdBlock::new(),
|
||||||
|
};
|
||||||
|
let scr = &mut cmd_block.0[..2];
|
||||||
|
|
||||||
// Arm `OnDrop` after the buffer, so it will be dropped first
|
// Arm `OnDrop` after the buffer, so it will be dropped first
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
let on_drop = OnDrop::new(|| Self::on_drop());
|
let on_drop = OnDrop::new(|| Self::on_drop());
|
||||||
|
|
||||||
let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3);
|
let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, scr, 8, 3);
|
||||||
InterruptHandler::<T>::data_interrupts(true);
|
InterruptHandler::<T>::data_interrupts(true);
|
||||||
Self::cmd(Cmd::cmd51(), true)?;
|
Self::cmd(Cmd::cmd51(), true)?;
|
||||||
|
|
||||||
@ -910,7 +956,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
drop(transfer);
|
drop(transfer);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let scr_bytes = &*(&scr as *const [u32; 2] as *const [u8; 8]);
|
let scr_bytes = &*(&scr as *const _ as *const [u8; 8]);
|
||||||
card.scr = SCR(u64::from_be_bytes(*scr_bytes));
|
card.scr = SCR(u64::from_be_bytes(*scr_bytes));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1002,8 +1048,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
Self::stop_datapath();
|
Self::stop_datapath();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initializes card (if present) and sets the bus at the
|
/// Initializes card (if present) and sets the bus at the specified frequency.
|
||||||
/// specified frequency.
|
|
||||||
pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> {
|
pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
let ker_ck = T::frequency();
|
let ker_ck = T::frequency();
|
||||||
@ -1143,6 +1188,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read status after signalling change
|
// Read status after signalling change
|
||||||
self.read_sd_status().await?;
|
self.read_sd_status().await?;
|
||||||
|
|
||||||
@ -1168,7 +1214,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
let on_drop = OnDrop::new(|| Self::on_drop());
|
let on_drop = OnDrop::new(|| Self::on_drop());
|
||||||
|
|
||||||
let transfer = self.prepare_datapath_read(buffer, 512, 9);
|
let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, buffer, 512, 9);
|
||||||
InterruptHandler::<T>::data_interrupts(true);
|
InterruptHandler::<T>::data_interrupts(true);
|
||||||
Self::cmd(Cmd::read_single_block(address), true)?;
|
Self::cmd(Cmd::read_single_block(address), true)?;
|
||||||
|
|
||||||
@ -1291,6 +1337,14 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
pub fn clock(&self) -> Hertz {
|
pub fn clock(&self) -> Hertz {
|
||||||
self.clock
|
self.clock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set a specific cmd buffer rather than using the default stack allocated one.
|
||||||
|
/// This is required if stack RAM cannot be used with DMA and usually manifests
|
||||||
|
/// itself as an indefinite wait on a dma transfer because the dma peripheral
|
||||||
|
/// cannot access the memory.
|
||||||
|
pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) {
|
||||||
|
self.cmd_block = Some(cmd_block)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> {
|
impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> {
|
||||||
|
Loading…
Reference in New Issue
Block a user