aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Haig <[email protected]>2024-07-19 02:03:53 +0100
committerDavid Haig <[email protected]>2024-07-19 02:03:53 +0100
commite7270e00f62af13cef68e52a0330f66260901b68 (patch)
treeda10e1a582853ae9bdcf28fa67a3a7922c230833
parent32019ed9b788adb4572437713ff5a233d2218adf (diff)
Added set_cmd_block for dma memory compatibility
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs93
1 files changed, 46 insertions, 47 deletions
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index 2490db4c6..44ff9fcd5 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -320,6 +320,10 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> {
320 signalling: Signalling, 320 signalling: Signalling,
321 /// Card 321 /// Card
322 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>,
323} 327}
324 328
325const CLK_AF: AfType = AfType::output(OutputType::PushPull, Speed::VeryHigh); 329const CLK_AF: AfType = AfType::output(OutputType::PushPull, Speed::VeryHigh);
@@ -523,6 +527,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
523 clock: SD_INIT_FREQ, 527 clock: SD_INIT_FREQ,
524 signalling: Default::default(), 528 signalling: Default::default(),
525 card: None, 529 card: None,
530 cmd_block: None,
526 } 531 }
527 } 532 }
528 533
@@ -559,8 +564,10 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
559 /// # Safety 564 /// # Safety
560 /// 565 ///
561 /// `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)]
562 fn prepare_datapath_read<'a>( 568 fn prepare_datapath_read<'a>(
563 &'a mut self, 569 config: &Config,
570 dma: &'a mut PeripheralRef<'d, Dma>,
564 buffer: &'a mut [u32], 571 buffer: &'a mut [u32],
565 length_bytes: u32, 572 length_bytes: u32,
566 block_size: u8, 573 block_size: u8,
@@ -572,15 +579,14 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
572 Self::wait_idle(); 579 Self::wait_idle();
573 Self::clear_interrupt_flags(); 580 Self::clear_interrupt_flags();
574 581
575 regs.dtimer() 582 regs.dtimer().write(|w| w.set_datatime(config.data_transfer_timeout));
576 .write(|w| w.set_datatime(self.config.data_transfer_timeout));
577 regs.dlenr().write(|w| w.set_datalength(length_bytes)); 583 regs.dlenr().write(|w| w.set_datalength(length_bytes));
578 584
579 #[cfg(sdmmc_v1)] 585 #[cfg(sdmmc_v1)]
580 let transfer = unsafe { 586 let transfer = unsafe {
581 let request = self.dma.request(); 587 let request = dma.request();
582 Transfer::new_read( 588 Transfer::new_read(
583 &mut self.dma, 589 dma,
584 request, 590 request,
585 regs.fifor().as_ptr() as *mut u32, 591 regs.fifor().as_ptr() as *mut u32,
586 buffer, 592 buffer,
@@ -706,11 +712,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
706 /// Attempt to set a new signalling mode. The selected 712 /// Attempt to set a new signalling mode. The selected
707 /// signalling mode is returned. Expects the current clock 713 /// signalling mode is returned. Expects the current clock
708 /// frequency to be > 12.5MHz. 714 /// frequency to be > 12.5MHz.
709 async fn switch_signalling_mode( 715 async fn switch_signalling_mode(&mut self, signalling: Signalling) -> Result<Signalling, Error> {
710 &mut self,
711 signalling: Signalling,
712 cmd_buffer: &mut CmdBlock,
713 ) -> Result<Signalling, Error> {
714 // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not 716 // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not
715 // necessary" 717 // necessary"
716 718
@@ -724,13 +726,16 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
724 Signalling::SDR12 => 0xFF_FF00, 726 Signalling::SDR12 => 0xFF_FF00,
725 }; 727 };
726 728
727 let status = cmd_buffer.as_mut(); 729 let status = match self.cmd_block.as_deref_mut() {
730 Some(x) => x,
731 None => &mut CmdBlock::new(),
732 };
728 733
729 // Arm `OnDrop` after the buffer, so it will be dropped first 734 // Arm `OnDrop` after the buffer, so it will be dropped first
730 let regs = T::regs(); 735 let regs = T::regs();
731 let on_drop = OnDrop::new(|| Self::on_drop()); 736 let on_drop = OnDrop::new(|| Self::on_drop());
732 737
733 let transfer = self.prepare_datapath_read(status, 64, 6); 738 let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, status.as_mut(), 64, 6);
734 InterruptHandler::<T>::data_interrupts(true); 739 InterruptHandler::<T>::data_interrupts(true);
735 Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6 740 Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6
736 741
@@ -798,20 +803,25 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
798 } 803 }
799 804
800 /// Reads the SD Status (ACMD13) 805 /// Reads the SD Status (ACMD13)
801 async fn read_sd_status(&mut self, cmd_buffer: &mut CmdBlock) -> Result<(), Error> { 806 async fn read_sd_status(&mut self) -> Result<(), Error> {
802 let card = self.card.as_mut().ok_or(Error::NoCard)?; 807 let card = self.card.as_mut().ok_or(Error::NoCard)?;
803 let rca = card.rca; 808 let rca = card.rca;
804 809
810 let cmd_block = match self.cmd_block.as_deref_mut() {
811 Some(x) => x,
812 None => &mut CmdBlock::new(),
813 };
814
805 Self::cmd(Cmd::set_block_length(64), false)?; // CMD16 815 Self::cmd(Cmd::set_block_length(64), false)?; // CMD16
806 Self::cmd(Cmd::app_cmd(rca << 16), false)?; // APP 816 Self::cmd(Cmd::app_cmd(rca << 16), false)?; // APP
807 817
808 let status = cmd_buffer; 818 let status = cmd_block;
809 819
810 // Arm `OnDrop` after the buffer, so it will be dropped first 820 // Arm `OnDrop` after the buffer, so it will be dropped first
811 let regs = T::regs(); 821 let regs = T::regs();
812 let on_drop = OnDrop::new(|| Self::on_drop()); 822 let on_drop = OnDrop::new(|| Self::on_drop());
813 823
814 let transfer = self.prepare_datapath_read(status.as_mut(), 64, 6); 824 let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, status.as_mut(), 64, 6);
815 InterruptHandler::<T>::data_interrupts(true); 825 InterruptHandler::<T>::data_interrupts(true);
816 Self::cmd(Cmd::card_status(0), true)?; 826 Self::cmd(Cmd::card_status(0), true)?;
817 827
@@ -899,18 +909,22 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
899 }); 909 });
900 } 910 }
901 911
902 async fn get_scr(&mut self, card: &mut Card, cmd_buffer: &mut CmdBlock) -> Result<(), Error> { 912 async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> {
903 // Read the the 64-bit SCR register 913 // Read the the 64-bit SCR register
904 Self::cmd(Cmd::set_block_length(8), false)?; // CMD16 914 Self::cmd(Cmd::set_block_length(8), false)?; // CMD16
905 Self::cmd(Cmd::app_cmd(card.rca << 16), false)?; 915 Self::cmd(Cmd::app_cmd(card.rca << 16), false)?;
906 916
907 let scr = &mut cmd_buffer.0[..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];
908 922
909 // Arm `OnDrop` after the buffer, so it will be dropped first 923 // Arm `OnDrop` after the buffer, so it will be dropped first
910 let regs = T::regs(); 924 let regs = T::regs();
911 let on_drop = OnDrop::new(|| Self::on_drop()); 925 let on_drop = OnDrop::new(|| Self::on_drop());
912 926
913 let transfer = self.prepare_datapath_read(scr, 8, 3); 927 let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, scr, 8, 3);
914 InterruptHandler::<T>::data_interrupts(true); 928 InterruptHandler::<T>::data_interrupts(true);
915 Self::cmd(Cmd::cmd51(), true)?; 929 Self::cmd(Cmd::cmd51(), true)?;
916 930
@@ -1036,16 +1050,6 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1036 1050
1037 /// Initializes card (if present) and sets the bus at the specified frequency. 1051 /// Initializes card (if present) and sets the bus at the specified frequency.
1038 pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> { 1052 pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> {
1039 let mut cmd_buffer = CmdBlock::new();
1040 self.init_card_with_cmd_buffer(freq, &mut cmd_buffer).await
1041 }
1042
1043 /// Initializes card (if present) and sets the bus at the specified frequency.
1044 /// A cmd_buffer should be passed in if the DMA requirements mean that
1045 /// stack memory can't be used (the default in `init_card`).
1046 /// This usually manifests itself as an indefinite wait on a dma transfer because the
1047 /// dma peripheral cannot access the memory.
1048 pub async fn init_card_with_cmd_buffer(&mut self, freq: Hertz, cmd_buffer: &mut CmdBlock) -> Result<(), Error> {
1049 let regs = T::regs(); 1053 let regs = T::regs();
1050 let ker_ck = T::frequency(); 1054 let ker_ck = T::frequency();
1051 1055
@@ -1134,7 +1138,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1134 1138
1135 self.select_card(Some(&card))?; 1139 self.select_card(Some(&card))?;
1136 1140
1137 self.get_scr(&mut card, cmd_buffer).await?; 1141 self.get_scr(&mut card).await?;
1138 1142
1139 // Set bus width 1143 // Set bus width
1140 let (width, acmd_arg) = match bus_width { 1144 let (width, acmd_arg) = match bus_width {
@@ -1169,11 +1173,11 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1169 self.card = Some(card); 1173 self.card = Some(card);
1170 1174
1171 // Read status 1175 // Read status
1172 self.read_sd_status(cmd_buffer).await?; 1176 self.read_sd_status().await?;
1173 1177
1174 if freq.0 > 25_000_000 { 1178 if freq.0 > 25_000_000 {
1175 // Switch to SDR25 1179 // Switch to SDR25
1176 self.signalling = self.switch_signalling_mode(Signalling::SDR25, cmd_buffer).await?; 1180 self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?;
1177 1181
1178 if self.signalling == Signalling::SDR25 { 1182 if self.signalling == Signalling::SDR25 {
1179 // Set final clock frequency 1183 // Set final clock frequency
@@ -1186,7 +1190,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1186 } 1190 }
1187 1191
1188 // Read status after signalling change 1192 // Read status after signalling change
1189 self.read_sd_status(cmd_buffer).await?; 1193 self.read_sd_status().await?;
1190 1194
1191 Ok(()) 1195 Ok(())
1192 } 1196 }
@@ -1210,7 +1214,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1210 let regs = T::regs(); 1214 let regs = T::regs();
1211 let on_drop = OnDrop::new(|| Self::on_drop()); 1215 let on_drop = OnDrop::new(|| Self::on_drop());
1212 1216
1213 let transfer = self.prepare_datapath_read(buffer, 512, 9); 1217 let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, buffer, 512, 9);
1214 InterruptHandler::<T>::data_interrupts(true); 1218 InterruptHandler::<T>::data_interrupts(true);
1215 Self::cmd(Cmd::read_single_block(address), true)?; 1219 Self::cmd(Cmd::read_single_block(address), true)?;
1216 1220
@@ -1246,19 +1250,6 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1246 1250
1247 /// Write a data block. 1251 /// Write a data block.
1248 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { 1252 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> {
1249 let mut cmd_buffer = CmdBlock::new();
1250 self.write_block_with_cmd_buffer(block_idx, buffer, &mut cmd_buffer)
1251 .await
1252 }
1253
1254 /// Write a data block and pass in a cmd buffer rather than using a stack allocated one.
1255 /// This is required if stack RAM cannot be used with DMA
1256 pub async fn write_block_with_cmd_buffer(
1257 &mut self,
1258 block_idx: u32,
1259 buffer: &DataBlock,
1260 cmd_buffer: &mut CmdBlock,
1261 ) -> Result<(), Error> {
1262 let card = self.card.as_mut().ok_or(Error::NoCard)?; 1253 let card = self.card.as_mut().ok_or(Error::NoCard)?;
1263 1254
1264 // NOTE(unsafe) DataBlock uses align 4 1255 // NOTE(unsafe) DataBlock uses align 4
@@ -1318,7 +1309,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1318 1309
1319 // Try to read card status (ACMD13) 1310 // Try to read card status (ACMD13)
1320 while timeout > 0 { 1311 while timeout > 0 {
1321 match self.read_sd_status(cmd_buffer).await { 1312 match self.read_sd_status().await {
1322 Ok(_) => return Ok(()), 1313 Ok(_) => return Ok(()),
1323 Err(Error::Timeout) => (), // Try again 1314 Err(Error::Timeout) => (), // Try again
1324 Err(e) => return Err(e), 1315 Err(e) => return Err(e),
@@ -1346,6 +1337,14 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1346 pub fn clock(&self) -> Hertz { 1337 pub fn clock(&self) -> Hertz {
1347 self.clock 1338 self.clock
1348 } 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 }
1349} 1348}
1350 1349
1351impl<'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> {