aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Haig <[email protected]>2024-07-17 15:37:56 +0100
committerDavid Haig <[email protected]>2024-07-17 17:12:37 +0100
commit32019ed9b788adb4572437713ff5a233d2218adf (patch)
treeadc4ee4328b556212d6ea3cc072216e5e2a3275a
parente54c753537b4b12c3d2fd03ad8e8ba9eaaded06e (diff)
Allow cmd buffer to be passed in for dma memory
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs91
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))]
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)]
@@ -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),