diff options
| author | David Haig <[email protected]> | 2024-07-19 02:03:53 +0100 |
|---|---|---|
| committer | David Haig <[email protected]> | 2024-07-19 02:03:53 +0100 |
| commit | e7270e00f62af13cef68e52a0330f66260901b68 (patch) | |
| tree | da10e1a582853ae9bdcf28fa67a3a7922c230833 | |
| parent | 32019ed9b788adb4572437713ff5a233d2218adf (diff) | |
Added set_cmd_block for dma memory compatibility
| -rw-r--r-- | embassy-stm32/src/sdmmc/mod.rs | 93 |
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 | ||
| 325 | const CLK_AF: AfType = AfType::output(OutputType::PushPull, Speed::VeryHigh); | 329 | const 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 | ||
| 1351 | impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> { | 1350 | impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> { |
