aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/sdmmc/sdio.rs
diff options
context:
space:
mode:
authorRaul Alimbekov <[email protected]>2025-12-16 09:05:22 +0300
committerGitHub <[email protected]>2025-12-16 09:05:22 +0300
commitc9a04b4b732b7a3b696eb8223664c1a7942b1875 (patch)
tree6dbe5c02e66eed8d8762f13f95afd24f8db2b38c /embassy-stm32/src/sdmmc/sdio.rs
parentcde24a3ef1117653ba5ed4184102b33f745782fb (diff)
parent5ae6e060ec1c90561719aabdc29d5b6e7b8b0a82 (diff)
Merge branch 'main' into main
Diffstat (limited to 'embassy-stm32/src/sdmmc/sdio.rs')
-rw-r--r--embassy-stm32/src/sdmmc/sdio.rs178
1 files changed, 178 insertions, 0 deletions
diff --git a/embassy-stm32/src/sdmmc/sdio.rs b/embassy-stm32/src/sdmmc/sdio.rs
new file mode 100644
index 000000000..e436d68cb
--- /dev/null
+++ b/embassy-stm32/src/sdmmc/sdio.rs
@@ -0,0 +1,178 @@
1use core::ops::{Deref, DerefMut};
2
3use aligned::{A4, Aligned};
4use sdio_host::common_cmd::{R1, Rz, cmd};
5use sdio_host::sd::BusWidth;
6use sdio_host::sd_cmd;
7
8use crate::sdmmc::{DatapathMode, Error, Sdmmc, aligned_mut, aligned_ref, block_size, slice8_mut, slice8_ref};
9use crate::time::Hertz;
10
11/// Aligned data block for SDMMC transfers.
12///
13/// This is a 64-byte array, aligned to 4 bytes to satisfy DMA requirements.
14#[repr(align(4))]
15#[derive(Debug, Clone, PartialEq, Eq)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub struct DataBlock(pub [u32; 16]);
18
19impl DataBlock {
20 /// Create a new DataBlock
21 pub const fn new() -> Self {
22 DataBlock([0u32; 16])
23 }
24}
25
26impl Deref for DataBlock {
27 type Target = [u8; 64];
28
29 fn deref(&self) -> &Self::Target {
30 unwrap!(slice8_ref(&self.0[..]).try_into())
31 }
32}
33
34impl DerefMut for DataBlock {
35 fn deref_mut(&mut self) -> &mut Self::Target {
36 unwrap!(slice8_mut(&mut self.0[..]).try_into())
37 }
38}
39
40/// Storage Device
41pub struct SerialDataInterface<'a, 'b> {
42 /// Inner member
43 sdmmc: &'a mut Sdmmc<'b>,
44}
45
46/// Card Storage Device
47impl<'a, 'b> SerialDataInterface<'a, 'b> {
48 /// Create a new SD card
49 pub async fn new(sdmmc: &'a mut Sdmmc<'b>, freq: Hertz) -> Result<Self, Error> {
50 let mut s = Self { sdmmc };
51
52 s.acquire(freq).await?;
53
54 Ok(s)
55 }
56
57 /// Initializes the card into a known state (or at least tries to).
58 async fn acquire(&mut self, _freq: Hertz) -> Result<(), Error> {
59 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
60
61 let _bus_width = match self.sdmmc.bus_width() {
62 BusWidth::Eight => return Err(Error::BusWidth),
63 bus_width => bus_width,
64 };
65
66 // While the SD/SDIO card or eMMC is in identification mode,
67 // the SDMMC_CK frequency must be no more than 400 kHz.
68 self.sdmmc.init_idle()?;
69
70 self.sdmmc.cmd(cmd::<Rz>(5, 0), false)?;
71
72 // Get RCA
73 let rca = self.sdmmc.cmd(sd_cmd::send_relative_address(), false)?;
74
75 // Select the card with RCA
76 self.sdmmc.select_card(Some(rca.try_into().unwrap()))?;
77
78 Ok(())
79 }
80
81 /// Set the bus to the 4-bit high-speed frequency
82 pub fn set_bus_to_high_speed(&mut self, frequency: Hertz) -> Result<(), Error> {
83 self.sdmmc.clkcr_set_clkdiv(frequency, BusWidth::Four)?;
84
85 Ok(())
86 }
87
88 /// Run cmd52
89 pub async fn cmd52(&mut self, arg: u32) -> Result<u32, Error> {
90 self.sdmmc.cmd(cmd::<R1>(52, arg), false)
91 }
92
93 /// Read in block mode using cmd53
94 pub async fn cmd53_block_read(&mut self, arg: u32, blocks: &mut [DataBlock]) -> Result<(), Error> {
95 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
96
97 // NOTE(unsafe) reinterpret buffer as &mut [u32]
98 let buffer = unsafe {
99 core::slice::from_raw_parts_mut(
100 blocks.as_mut_ptr() as *mut u32,
101 blocks.len() * size_of::<DataBlock>() / size_of::<u32>(),
102 )
103 };
104
105 let transfer = self.sdmmc.prepare_datapath_read(
106 aligned_mut(buffer),
107 DatapathMode::Block(block_size(size_of::<DataBlock>())),
108 );
109 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
110
111 self.sdmmc.complete_datapath_transfer(transfer, false).await?;
112 self.sdmmc.clear_interrupt_flags();
113
114 Ok(())
115 }
116
117 /// Read in multibyte mode using cmd53
118 pub async fn cmd53_byte_read(&mut self, arg: u32, buffer: &mut Aligned<A4, [u8]>) -> Result<(), Error> {
119 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
120
121 let transfer = self.sdmmc.prepare_datapath_read(buffer, DatapathMode::Byte);
122 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
123
124 self.sdmmc.complete_datapath_transfer(transfer, false).await?;
125 self.sdmmc.clear_interrupt_flags();
126
127 Ok(())
128 }
129
130 /// Write in block mode using cmd53
131 pub async fn cmd53_block_write(&mut self, arg: u32, blocks: &[DataBlock]) -> Result<(), Error> {
132 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
133
134 // NOTE(unsafe) reinterpret buffer as &mut [u32]
135 let buffer = unsafe {
136 core::slice::from_raw_parts_mut(
137 blocks.as_ptr() as *mut u32,
138 blocks.len() * size_of::<DataBlock>() / size_of::<u32>(),
139 )
140 };
141
142 #[cfg(sdmmc_v1)]
143 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
144
145 let transfer = self.sdmmc.prepare_datapath_write(
146 aligned_ref(buffer),
147 DatapathMode::Block(block_size(size_of::<DataBlock>())),
148 );
149
150 #[cfg(sdmmc_v2)]
151 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
152
153 self.sdmmc.complete_datapath_transfer(transfer, false).await?;
154 self.sdmmc.clear_interrupt_flags();
155
156 Ok(())
157 }
158
159 /// Write in multibyte mode using cmd53
160 pub async fn cmd53_byte_write(&mut self, arg: u32, buffer: &[u32]) -> Result<(), Error> {
161 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
162
163 #[cfg(sdmmc_v1)]
164 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
165
166 let transfer = self
167 .sdmmc
168 .prepare_datapath_write(aligned_ref(buffer), DatapathMode::Byte);
169
170 #[cfg(sdmmc_v2)]
171 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
172
173 self.sdmmc.complete_datapath_transfer(transfer, false).await?;
174 self.sdmmc.clear_interrupt_flags();
175
176 Ok(())
177 }
178}