diff options
| author | David Haig <[email protected]> | 2024-07-17 15:37:56 +0100 |
|---|---|---|
| committer | David Haig <[email protected]> | 2024-07-17 17:12:37 +0100 |
| commit | 32019ed9b788adb4572437713ff5a233d2218adf (patch) | |
| tree | adc4ee4328b556212d6ea3cc072216e5e2a3275a | |
| parent | e54c753537b4b12c3d2fd03ad8e8ba9eaaded06e (diff) | |
Allow cmd buffer to be passed in for dma memory
| -rw-r--r-- | embassy-stm32/src/sdmmc/mod.rs | 91 |
1 files changed, 73 insertions, 18 deletions
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index ee5539518..2490db4c6 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)] |
| @@ -678,7 +706,11 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 678 | /// Attempt to set a new signalling mode. The selected | 706 | /// Attempt to set a new signalling mode. The selected |
| 679 | /// signalling mode is returned. Expects the current clock | 707 | /// signalling mode is returned. Expects the current clock |
| 680 | /// frequency to be > 12.5MHz. | 708 | /// frequency to be > 12.5MHz. |
| 681 | async fn switch_signalling_mode(&mut self, signalling: Signalling) -> Result<Signalling, Error> { | 709 | async fn switch_signalling_mode( |
| 710 | &mut self, | ||
| 711 | signalling: Signalling, | ||
| 712 | cmd_buffer: &mut CmdBlock, | ||
| 713 | ) -> Result<Signalling, Error> { | ||
| 682 | // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not | 714 | // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not |
| 683 | // necessary" | 715 | // necessary" |
| 684 | 716 | ||
| @@ -692,13 +724,13 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 692 | Signalling::SDR12 => 0xFF_FF00, | 724 | Signalling::SDR12 => 0xFF_FF00, |
| 693 | }; | 725 | }; |
| 694 | 726 | ||
| 695 | let mut status = [0u32; 16]; | 727 | let status = cmd_buffer.as_mut(); |
| 696 | 728 | ||
| 697 | // Arm `OnDrop` after the buffer, so it will be dropped first | 729 | // Arm `OnDrop` after the buffer, so it will be dropped first |
| 698 | let regs = T::regs(); | 730 | let regs = T::regs(); |
| 699 | let on_drop = OnDrop::new(|| Self::on_drop()); | 731 | let on_drop = OnDrop::new(|| Self::on_drop()); |
| 700 | 732 | ||
| 701 | let transfer = self.prepare_datapath_read(&mut status, 64, 6); | 733 | let transfer = self.prepare_datapath_read(status, 64, 6); |
| 702 | InterruptHandler::<T>::data_interrupts(true); | 734 | InterruptHandler::<T>::data_interrupts(true); |
| 703 | Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6 | 735 | Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6 |
| 704 | 736 | ||
| @@ -766,20 +798,20 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 766 | } | 798 | } |
| 767 | 799 | ||
| 768 | /// Reads the SD Status (ACMD13) | 800 | /// Reads the SD Status (ACMD13) |
| 769 | async fn read_sd_status(&mut self) -> Result<(), Error> { | 801 | async fn read_sd_status(&mut self, cmd_buffer: &mut CmdBlock) -> Result<(), Error> { |
| 770 | let card = self.card.as_mut().ok_or(Error::NoCard)?; | 802 | let card = self.card.as_mut().ok_or(Error::NoCard)?; |
| 771 | let rca = card.rca; | 803 | let rca = card.rca; |
| 772 | 804 | ||
| 773 | Self::cmd(Cmd::set_block_length(64), false)?; // CMD16 | 805 | Self::cmd(Cmd::set_block_length(64), false)?; // CMD16 |
| 774 | Self::cmd(Cmd::app_cmd(rca << 16), false)?; // APP | 806 | Self::cmd(Cmd::app_cmd(rca << 16), false)?; // APP |
| 775 | 807 | ||
| 776 | let mut status = [0u32; 16]; | 808 | let status = cmd_buffer; |
| 777 | 809 | ||
| 778 | // Arm `OnDrop` after the buffer, so it will be dropped first | 810 | // Arm `OnDrop` after the buffer, so it will be dropped first |
| 779 | let regs = T::regs(); | 811 | let regs = T::regs(); |
| 780 | let on_drop = OnDrop::new(|| Self::on_drop()); | 812 | let on_drop = OnDrop::new(|| Self::on_drop()); |
| 781 | 813 | ||
| 782 | let transfer = self.prepare_datapath_read(&mut status, 64, 6); | 814 | let transfer = self.prepare_datapath_read(status.as_mut(), 64, 6); |
| 783 | InterruptHandler::<T>::data_interrupts(true); | 815 | InterruptHandler::<T>::data_interrupts(true); |
| 784 | Self::cmd(Cmd::card_status(0), true)?; | 816 | Self::cmd(Cmd::card_status(0), true)?; |
| 785 | 817 | ||
| @@ -813,7 +845,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 813 | for byte in status.iter_mut() { | 845 | for byte in status.iter_mut() { |
| 814 | *byte = u32::from_be(*byte); | 846 | *byte = u32::from_be(*byte); |
| 815 | } | 847 | } |
| 816 | self.card.as_mut().unwrap().status = status.into(); | 848 | self.card.as_mut().unwrap().status = status.0.into(); |
| 817 | } | 849 | } |
| 818 | res | 850 | res |
| 819 | } | 851 | } |
| @@ -867,18 +899,18 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 867 | }); | 899 | }); |
| 868 | } | 900 | } |
| 869 | 901 | ||
| 870 | async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { | 902 | async fn get_scr(&mut self, card: &mut Card, cmd_buffer: &mut CmdBlock) -> Result<(), Error> { |
| 871 | // Read the the 64-bit SCR register | 903 | // Read the the 64-bit SCR register |
| 872 | Self::cmd(Cmd::set_block_length(8), false)?; // CMD16 | 904 | Self::cmd(Cmd::set_block_length(8), false)?; // CMD16 |
| 873 | Self::cmd(Cmd::app_cmd(card.rca << 16), false)?; | 905 | Self::cmd(Cmd::app_cmd(card.rca << 16), false)?; |
| 874 | 906 | ||
| 875 | let mut scr = [0u32; 2]; | 907 | let scr = &mut cmd_buffer.0[..2]; |
| 876 | 908 | ||
| 877 | // Arm `OnDrop` after the buffer, so it will be dropped first | 909 | // Arm `OnDrop` after the buffer, so it will be dropped first |
| 878 | let regs = T::regs(); | 910 | let regs = T::regs(); |
| 879 | let on_drop = OnDrop::new(|| Self::on_drop()); | 911 | let on_drop = OnDrop::new(|| Self::on_drop()); |
| 880 | 912 | ||
| 881 | let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3); | 913 | let transfer = self.prepare_datapath_read(scr, 8, 3); |
| 882 | InterruptHandler::<T>::data_interrupts(true); | 914 | InterruptHandler::<T>::data_interrupts(true); |
| 883 | Self::cmd(Cmd::cmd51(), true)?; | 915 | Self::cmd(Cmd::cmd51(), true)?; |
| 884 | 916 | ||
| @@ -910,7 +942,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 910 | drop(transfer); | 942 | drop(transfer); |
| 911 | 943 | ||
| 912 | unsafe { | 944 | unsafe { |
| 913 | let scr_bytes = &*(&scr as *const [u32; 2] as *const [u8; 8]); | 945 | let scr_bytes = &*(&scr as *const _ as *const [u8; 8]); |
| 914 | card.scr = SCR(u64::from_be_bytes(*scr_bytes)); | 946 | card.scr = SCR(u64::from_be_bytes(*scr_bytes)); |
| 915 | } | 947 | } |
| 916 | } | 948 | } |
| @@ -1002,9 +1034,18 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1002 | Self::stop_datapath(); | 1034 | Self::stop_datapath(); |
| 1003 | } | 1035 | } |
| 1004 | 1036 | ||
| 1005 | /// Initializes card (if present) and sets the bus at the | 1037 | /// 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> { | 1038 | 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> { | ||
| 1008 | let regs = T::regs(); | 1049 | let regs = T::regs(); |
| 1009 | let ker_ck = T::frequency(); | 1050 | let ker_ck = T::frequency(); |
| 1010 | 1051 | ||
| @@ -1093,7 +1134,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1093 | 1134 | ||
| 1094 | self.select_card(Some(&card))?; | 1135 | self.select_card(Some(&card))?; |
| 1095 | 1136 | ||
| 1096 | self.get_scr(&mut card).await?; | 1137 | self.get_scr(&mut card, cmd_buffer).await?; |
| 1097 | 1138 | ||
| 1098 | // Set bus width | 1139 | // Set bus width |
| 1099 | let (width, acmd_arg) = match bus_width { | 1140 | let (width, acmd_arg) = match bus_width { |
| @@ -1128,11 +1169,11 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1128 | self.card = Some(card); | 1169 | self.card = Some(card); |
| 1129 | 1170 | ||
| 1130 | // Read status | 1171 | // Read status |
| 1131 | self.read_sd_status().await?; | 1172 | self.read_sd_status(cmd_buffer).await?; |
| 1132 | 1173 | ||
| 1133 | if freq.0 > 25_000_000 { | 1174 | if freq.0 > 25_000_000 { |
| 1134 | // Switch to SDR25 | 1175 | // Switch to SDR25 |
| 1135 | self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?; | 1176 | self.signalling = self.switch_signalling_mode(Signalling::SDR25, cmd_buffer).await?; |
| 1136 | 1177 | ||
| 1137 | if self.signalling == Signalling::SDR25 { | 1178 | if self.signalling == Signalling::SDR25 { |
| 1138 | // Set final clock frequency | 1179 | // Set final clock frequency |
| @@ -1143,8 +1184,9 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1143 | } | 1184 | } |
| 1144 | } | 1185 | } |
| 1145 | } | 1186 | } |
| 1187 | |||
| 1146 | // Read status after signalling change | 1188 | // Read status after signalling change |
| 1147 | self.read_sd_status().await?; | 1189 | self.read_sd_status(cmd_buffer).await?; |
| 1148 | 1190 | ||
| 1149 | Ok(()) | 1191 | Ok(()) |
| 1150 | } | 1192 | } |
| @@ -1204,6 +1246,19 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1204 | 1246 | ||
| 1205 | /// Write a data block. | 1247 | /// Write a data block. |
| 1206 | pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { | 1248 | 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> { | ||
| 1207 | let card = self.card.as_mut().ok_or(Error::NoCard)?; | 1262 | let card = self.card.as_mut().ok_or(Error::NoCard)?; |
| 1208 | 1263 | ||
| 1209 | // NOTE(unsafe) DataBlock uses align 4 | 1264 | // NOTE(unsafe) DataBlock uses align 4 |
| @@ -1263,7 +1318,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1263 | 1318 | ||
| 1264 | // Try to read card status (ACMD13) | 1319 | // Try to read card status (ACMD13) |
| 1265 | while timeout > 0 { | 1320 | while timeout > 0 { |
| 1266 | match self.read_sd_status().await { | 1321 | match self.read_sd_status(cmd_buffer).await { |
| 1267 | Ok(_) => return Ok(()), | 1322 | Ok(_) => return Ok(()), |
| 1268 | Err(Error::Timeout) => (), // Try again | 1323 | Err(Error::Timeout) => (), // Try again |
| 1269 | Err(e) => return Err(e), | 1324 | Err(e) => return Err(e), |
