diff options
| -rw-r--r-- | embassy-stm32/src/sdmmc/mod.rs | 86 |
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))] | ||
| 102 | pub struct CmdBlock(pub [u32; 16]); | ||
| 103 | |||
| 104 | impl CmdBlock { | ||
| 105 | /// Creates a new instance of CmdBlock | ||
| 106 | pub const fn new() -> Self { | ||
| 107 | Self([0u32; 16]) | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | impl Deref for CmdBlock { | ||
| 112 | type Target = [u32; 16]; | ||
| 113 | |||
| 114 | fn deref(&self) -> &Self::Target { | ||
| 115 | &self.0 | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | impl 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 | ||
| 297 | const CLK_AF: AfType = AfType::output(OutputType::PushPull, Speed::VeryHigh); | 329 | 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> { | |||
| 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 | ||
| 1296 | 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> { |
