aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-07-22 19:44:00 +0000
committerGitHub <[email protected]>2024-07-22 19:44:00 +0000
commit2537fc6f4fcbdaa0fcea45a37382d61f59cc5767 (patch)
tree298df348f25afe96d8a985f7558737e16cda5b1f
parentea4c2ca95d640e09da13d6ffab51ec943d3fc667 (diff)
parente7270e00f62af13cef68e52a0330f66260901b68 (diff)
Merge pull request #3188 from ninjasource/sdmmc-dma-buffers
embassy-stm32: Allow cmd block to be passed in for sdmmc dma transfers
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs86
1 files changed, 70 insertions, 16 deletions
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index ee5539518..44ff9fcd5 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -94,6 +94,34 @@ impl DerefMut for DataBlock {
94 } 94 }
95} 95}
96 96
97/// Command Block buffer for SDMMC command transfers.
98///
99/// This is a 16-word array, exposed so that DMA commpatible memory can be used if required.
100#[derive(Debug, Clone, PartialEq, Eq)]
101#[cfg_attr(feature = "defmt", derive(defmt::Format))]
102pub struct CmdBlock(pub [u32; 16]);
103
104impl CmdBlock {
105 /// Creates a new instance of CmdBlock
106 pub const fn new() -> Self {
107 Self([0u32; 16])
108 }
109}
110
111impl Deref for CmdBlock {
112 type Target = [u32; 16];
113
114 fn deref(&self) -> &Self::Target {
115 &self.0
116 }
117}
118
119impl DerefMut for CmdBlock {
120 fn deref_mut(&mut self) -> &mut Self::Target {
121 &mut self.0
122 }
123}
124
97/// Errors 125/// Errors
98#[non_exhaustive] 126#[non_exhaustive]
99#[derive(Debug, Copy, Clone, PartialEq, Eq)] 127#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -292,6 +320,10 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> {
292 signalling: Signalling, 320 signalling: Signalling,
293 /// Card 321 /// Card
294 card: Option<Card>, 322 card: Option<Card>,
323
324 /// An optional buffer to be used for commands
325 /// This should be used if there are special memory location requirements for dma
326 cmd_block: Option<&'d mut CmdBlock>,
295} 327}
296 328
297const CLK_AF: AfType = AfType::output(OutputType::PushPull, Speed::VeryHigh); 329const 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> {
495 clock: SD_INIT_FREQ, 527 clock: SD_INIT_FREQ,
496 signalling: Default::default(), 528 signalling: Default::default(),
497 card: None, 529 card: None,
530 cmd_block: None,
498 } 531 }
499 } 532 }
500 533
@@ -531,8 +564,10 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
531 /// # Safety 564 /// # Safety
532 /// 565 ///
533 /// `buffer` must be valid for the whole transfer and word aligned 566 /// `buffer` must be valid for the whole transfer and word aligned
567 #[allow(unused_variables)]
534 fn prepare_datapath_read<'a>( 568 fn prepare_datapath_read<'a>(
535 &'a mut self, 569 config: &Config,
570 dma: &'a mut PeripheralRef<'d, Dma>,
536 buffer: &'a mut [u32], 571 buffer: &'a mut [u32],
537 length_bytes: u32, 572 length_bytes: u32,
538 block_size: u8, 573 block_size: u8,
@@ -544,15 +579,14 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
544 Self::wait_idle(); 579 Self::wait_idle();
545 Self::clear_interrupt_flags(); 580 Self::clear_interrupt_flags();
546 581
547 regs.dtimer() 582 regs.dtimer().write(|w| w.set_datatime(config.data_transfer_timeout));
548 .write(|w| w.set_datatime(self.config.data_transfer_timeout));
549 regs.dlenr().write(|w| w.set_datalength(length_bytes)); 583 regs.dlenr().write(|w| w.set_datalength(length_bytes));
550 584
551 #[cfg(sdmmc_v1)] 585 #[cfg(sdmmc_v1)]
552 let transfer = unsafe { 586 let transfer = unsafe {
553 let request = self.dma.request(); 587 let request = dma.request();
554 Transfer::new_read( 588 Transfer::new_read(
555 &mut self.dma, 589 dma,
556 request, 590 request,
557 regs.fifor().as_ptr() as *mut u32, 591 regs.fifor().as_ptr() as *mut u32,
558 buffer, 592 buffer,
@@ -692,13 +726,16 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
692 Signalling::SDR12 => 0xFF_FF00, 726 Signalling::SDR12 => 0xFF_FF00,
693 }; 727 };
694 728
695 let mut status = [0u32; 16]; 729 let status = match self.cmd_block.as_deref_mut() {
730 Some(x) => x,
731 None => &mut CmdBlock::new(),
732 };
696 733
697 // Arm `OnDrop` after the buffer, so it will be dropped first 734 // Arm `OnDrop` after the buffer, so it will be dropped first
698 let regs = T::regs(); 735 let regs = T::regs();
699 let on_drop = OnDrop::new(|| Self::on_drop()); 736 let on_drop = OnDrop::new(|| Self::on_drop());
700 737
701 let transfer = self.prepare_datapath_read(&mut status, 64, 6); 738 let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, status.as_mut(), 64, 6);
702 InterruptHandler::<T>::data_interrupts(true); 739 InterruptHandler::<T>::data_interrupts(true);
703 Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6 740 Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6
704 741
@@ -770,16 +807,21 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
770 let card = self.card.as_mut().ok_or(Error::NoCard)?; 807 let card = self.card.as_mut().ok_or(Error::NoCard)?;
771 let rca = card.rca; 808 let rca = card.rca;
772 809
810 let cmd_block = match self.cmd_block.as_deref_mut() {
811 Some(x) => x,
812 None => &mut CmdBlock::new(),
813 };
814
773 Self::cmd(Cmd::set_block_length(64), false)?; // CMD16 815 Self::cmd(Cmd::set_block_length(64), false)?; // CMD16
774 Self::cmd(Cmd::app_cmd(rca << 16), false)?; // APP 816 Self::cmd(Cmd::app_cmd(rca << 16), false)?; // APP
775 817
776 let mut status = [0u32; 16]; 818 let status = cmd_block;
777 819
778 // Arm `OnDrop` after the buffer, so it will be dropped first 820 // Arm `OnDrop` after the buffer, so it will be dropped first
779 let regs = T::regs(); 821 let regs = T::regs();
780 let on_drop = OnDrop::new(|| Self::on_drop()); 822 let on_drop = OnDrop::new(|| Self::on_drop());
781 823
782 let transfer = self.prepare_datapath_read(&mut status, 64, 6); 824 let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, status.as_mut(), 64, 6);
783 InterruptHandler::<T>::data_interrupts(true); 825 InterruptHandler::<T>::data_interrupts(true);
784 Self::cmd(Cmd::card_status(0), true)?; 826 Self::cmd(Cmd::card_status(0), true)?;
785 827
@@ -813,7 +855,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
813 for byte in status.iter_mut() { 855 for byte in status.iter_mut() {
814 *byte = u32::from_be(*byte); 856 *byte = u32::from_be(*byte);
815 } 857 }
816 self.card.as_mut().unwrap().status = status.into(); 858 self.card.as_mut().unwrap().status = status.0.into();
817 } 859 }
818 res 860 res
819 } 861 }
@@ -872,13 +914,17 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
872 Self::cmd(Cmd::set_block_length(8), false)?; // CMD16 914 Self::cmd(Cmd::set_block_length(8), false)?; // CMD16
873 Self::cmd(Cmd::app_cmd(card.rca << 16), false)?; 915 Self::cmd(Cmd::app_cmd(card.rca << 16), false)?;
874 916
875 let mut scr = [0u32; 2]; 917 let cmd_block = match self.cmd_block.as_deref_mut() {
918 Some(x) => x,
919 None => &mut CmdBlock::new(),
920 };
921 let scr = &mut cmd_block.0[..2];
876 922
877 // Arm `OnDrop` after the buffer, so it will be dropped first 923 // Arm `OnDrop` after the buffer, so it will be dropped first
878 let regs = T::regs(); 924 let regs = T::regs();
879 let on_drop = OnDrop::new(|| Self::on_drop()); 925 let on_drop = OnDrop::new(|| Self::on_drop());
880 926
881 let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3); 927 let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, scr, 8, 3);
882 InterruptHandler::<T>::data_interrupts(true); 928 InterruptHandler::<T>::data_interrupts(true);
883 Self::cmd(Cmd::cmd51(), true)?; 929 Self::cmd(Cmd::cmd51(), true)?;
884 930
@@ -910,7 +956,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
910 drop(transfer); 956 drop(transfer);
911 957
912 unsafe { 958 unsafe {
913 let scr_bytes = &*(&scr as *const [u32; 2] as *const [u8; 8]); 959 let scr_bytes = &*(&scr as *const _ as *const [u8; 8]);
914 card.scr = SCR(u64::from_be_bytes(*scr_bytes)); 960 card.scr = SCR(u64::from_be_bytes(*scr_bytes));
915 } 961 }
916 } 962 }
@@ -1002,8 +1048,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1002 Self::stop_datapath(); 1048 Self::stop_datapath();
1003 } 1049 }
1004 1050
1005 /// Initializes card (if present) and sets the bus at the 1051 /// Initializes card (if present) and sets the bus at the specified frequency.
1006 /// specified frequency.
1007 pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> { 1052 pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> {
1008 let regs = T::regs(); 1053 let regs = T::regs();
1009 let ker_ck = T::frequency(); 1054 let ker_ck = T::frequency();
@@ -1143,6 +1188,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1143 } 1188 }
1144 } 1189 }
1145 } 1190 }
1191
1146 // Read status after signalling change 1192 // Read status after signalling change
1147 self.read_sd_status().await?; 1193 self.read_sd_status().await?;
1148 1194
@@ -1168,7 +1214,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1168 let regs = T::regs(); 1214 let regs = T::regs();
1169 let on_drop = OnDrop::new(|| Self::on_drop()); 1215 let on_drop = OnDrop::new(|| Self::on_drop());
1170 1216
1171 let transfer = self.prepare_datapath_read(buffer, 512, 9); 1217 let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, buffer, 512, 9);
1172 InterruptHandler::<T>::data_interrupts(true); 1218 InterruptHandler::<T>::data_interrupts(true);
1173 Self::cmd(Cmd::read_single_block(address), true)?; 1219 Self::cmd(Cmd::read_single_block(address), true)?;
1174 1220
@@ -1291,6 +1337,14 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1291 pub fn clock(&self) -> Hertz { 1337 pub fn clock(&self) -> Hertz {
1292 self.clock 1338 self.clock
1293 } 1339 }
1340
1341 /// Set a specific cmd buffer rather than using the default stack allocated one.
1342 /// This is required if stack RAM cannot be used with DMA and usually manifests
1343 /// itself as an indefinite wait on a dma transfer because the dma peripheral
1344 /// cannot access the memory.
1345 pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) {
1346 self.cmd_block = Some(cmd_block)
1347 }
1294} 1348}
1295 1349
1296impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> { 1350impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> {