aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-03-20 20:19:58 +0000
committerGitHub <[email protected]>2022-03-20 20:19:58 +0000
commit37ada65a33842f0cc19d2b13e379225c14c7600d (patch)
treed02f780eedc21ab502f060c3be4f59963fe9e19d
parentf0a071790d167e5627bdfae3384c1d8fe6382f34 (diff)
parenta9854924fa41991375f5e5019fb6e54fbc63370a (diff)
Merge #669
669: Add SDMMC v1 and SDIO support r=Dirbaio a=chemicstry SDMMC v2 peripheral is an extension of SDMMC v1 (or SDIO) so I managed to reuse most of the code, with some cfg's. Apart from small differeces in registers, the biggest change is that v2 uses internal DMA, while v1 has to use shared DMA peripheral. This makes code a bit uglier, because DMA channel for v1 has to be passed around. Not sure if it's possible to make it any cleaner. This also adds `TransferOptions` structure to DMA, because SDMMC v1 requires setting peripheral flow control and burst transfers. Let me know if some alternative way would be prefered. I tested this on STM32F429ZIT6 (with sd card) and STM32H745ZIT6 (with oscilloscope). Depends on: https://github.com/embassy-rs/stm32-data/pull/130 Co-authored-by: chemicstry <[email protected]>
-rw-r--r--embassy-stm32/build.rs24
-rw-r--r--embassy-stm32/src/dma/bdma.rs25
-rw-r--r--embassy-stm32/src/dma/dma.rs36
-rw-r--r--embassy-stm32/src/dma/mod.rs56
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs1555
-rw-r--r--embassy-stm32/src/sdmmc/v1.rs1
-rw-r--r--embassy-stm32/src/sdmmc/v2.rs1374
-rw-r--r--embassy-stm32/src/spi/mod.rs20
-rw-r--r--examples/stm32f4/src/bin/sdmmc.rs44
-rw-r--r--examples/stm32f7/src/bin/sdmmc.rs44
-rw-r--r--examples/stm32h7/src/bin/sdmmc.rs43
m---------stm32-data0
12 files changed, 1817 insertions, 1405 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 8b64aaaac..4cba1c669 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -407,17 +407,17 @@ fn main() {
407 (("timer", "BKIN2"), (quote!(crate::pwm::BreakInput2Pin), quote!())), 407 (("timer", "BKIN2"), (quote!(crate::pwm::BreakInput2Pin), quote!())),
408 (("timer", "BKIN2_COMP1"), (quote!(crate::pwm::BreakInput2Comparator1Pin), quote!())), 408 (("timer", "BKIN2_COMP1"), (quote!(crate::pwm::BreakInput2Comparator1Pin), quote!())),
409 (("timer", "BKIN2_COMP2"), (quote!(crate::pwm::BreakInput2Comparator2Pin), quote!())), 409 (("timer", "BKIN2_COMP2"), (quote!(crate::pwm::BreakInput2Comparator2Pin), quote!())),
410 (("sdmmc", "CK"), (quote!(crate::sdmmc::CkPin), quote!(#[cfg(feature="sdmmc-rs")]))), 410 (("sdmmc", "CK"), (quote!(crate::sdmmc::CkPin), quote!())),
411 (("sdmmc", "CMD"), (quote!(crate::sdmmc::CmdPin), quote!(#[cfg(feature="sdmmc-rs")]))), 411 (("sdmmc", "CMD"), (quote!(crate::sdmmc::CmdPin), quote!())),
412 (("sdmmc", "D0"), (quote!(crate::sdmmc::D0Pin), quote!(#[cfg(feature="sdmmc-rs")]))), 412 (("sdmmc", "D0"), (quote!(crate::sdmmc::D0Pin), quote!())),
413 (("sdmmc", "D1"), (quote!(crate::sdmmc::D1Pin), quote!(#[cfg(feature="sdmmc-rs")]))), 413 (("sdmmc", "D1"), (quote!(crate::sdmmc::D1Pin), quote!())),
414 (("sdmmc", "D2"), (quote!(crate::sdmmc::D2Pin), quote!(#[cfg(feature="sdmmc-rs")]))), 414 (("sdmmc", "D2"), (quote!(crate::sdmmc::D2Pin), quote!())),
415 (("sdmmc", "D3"), (quote!(crate::sdmmc::D3Pin), quote!(#[cfg(feature="sdmmc-rs")]))), 415 (("sdmmc", "D3"), (quote!(crate::sdmmc::D3Pin), quote!())),
416 (("sdmmc", "D4"), (quote!(crate::sdmmc::D4Pin), quote!(#[cfg(feature="sdmmc-rs")]))), 416 (("sdmmc", "D4"), (quote!(crate::sdmmc::D4Pin), quote!())),
417 (("sdmmc", "D5"), (quote!(crate::sdmmc::D5Pin), quote!(#[cfg(feature="sdmmc-rs")]))), 417 (("sdmmc", "D5"), (quote!(crate::sdmmc::D5Pin), quote!())),
418 (("sdmmc", "D6"), (quote!(crate::sdmmc::D6Pin), quote!(#[cfg(feature="sdmmc-rs")]))), 418 (("sdmmc", "D6"), (quote!(crate::sdmmc::D6Pin), quote!())),
419 (("sdmmc", "D6"), (quote!(crate::sdmmc::D7Pin), quote!(#[cfg(feature="sdmmc-rs")]))), 419 (("sdmmc", "D6"), (quote!(crate::sdmmc::D7Pin), quote!())),
420 (("sdmmc", "D8"), (quote!(crate::sdmmc::D8Pin), quote!(#[cfg(feature="sdmmc-rs")]))), 420 (("sdmmc", "D8"), (quote!(crate::sdmmc::D8Pin), quote!())),
421 ].into(); 421 ].into();
422 422
423 for p in METADATA.peripherals { 423 for p in METADATA.peripherals {
@@ -483,6 +483,8 @@ fn main() {
483 (("i2c", "TX"), quote!(crate::i2c::TxDma)), 483 (("i2c", "TX"), quote!(crate::i2c::TxDma)),
484 (("dcmi", "DCMI"), quote!(crate::dcmi::FrameDma)), 484 (("dcmi", "DCMI"), quote!(crate::dcmi::FrameDma)),
485 (("dcmi", "PSSI"), quote!(crate::dcmi::FrameDma)), 485 (("dcmi", "PSSI"), quote!(crate::dcmi::FrameDma)),
486 // SDMMCv1 uses the same channel for both directions, so just implement for RX
487 (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)),
486 ] 488 ]
487 .into(); 489 .into();
488 490
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index 79b114e6a..30d2a0b97 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -11,7 +11,7 @@ use crate::dma::Request;
11use crate::pac; 11use crate::pac;
12use crate::pac::bdma::vals; 12use crate::pac::bdma::vals;
13 13
14use super::{Word, WordSize}; 14use super::{TransferOptions, Word, WordSize};
15 15
16impl From<WordSize> for vals::Size { 16impl From<WordSize> for vals::Size {
17 fn from(raw: WordSize) -> Self { 17 fn from(raw: WordSize) -> Self {
@@ -55,7 +55,7 @@ foreach_dma_channel! {
55 ($channel_peri:ident, $dma_peri:ident, bdma, $channel_num:expr, $index:expr, $dmamux:tt) => { 55 ($channel_peri:ident, $dma_peri:ident, bdma, $channel_num:expr, $index:expr, $dmamux:tt) => {
56 impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri { 56 impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {
57 57
58 unsafe fn start_write<W: Word>(&mut self, _request: Request, buf: *const[W], reg_addr: *mut W) { 58 unsafe fn start_write<W: Word>(&mut self, _request: Request, buf: *const[W], reg_addr: *mut W, options: TransferOptions) {
59 let (ptr, len) = super::slice_ptr_parts(buf); 59 let (ptr, len) = super::slice_ptr_parts(buf);
60 low_level_api::start_transfer( 60 low_level_api::start_transfer(
61 pac::$dma_peri, 61 pac::$dma_peri,
@@ -68,6 +68,7 @@ foreach_dma_channel! {
68 len, 68 len,
69 true, 69 true,
70 vals::Size::from(W::bits()), 70 vals::Size::from(W::bits()),
71 options,
71 #[cfg(dmamux)] 72 #[cfg(dmamux)]
72 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, 73 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS,
73 #[cfg(dmamux)] 74 #[cfg(dmamux)]
@@ -76,7 +77,7 @@ foreach_dma_channel! {
76 } 77 }
77 78
78 79
79 unsafe fn start_write_repeated<W: Word>(&mut self, _request: Request, repeated: W, count: usize, reg_addr: *mut W) { 80 unsafe fn start_write_repeated<W: Word>(&mut self, _request: Request, repeated: W, count: usize, reg_addr: *mut W, options: TransferOptions) {
80 let buf = [repeated]; 81 let buf = [repeated];
81 low_level_api::start_transfer( 82 low_level_api::start_transfer(
82 pac::$dma_peri, 83 pac::$dma_peri,
@@ -89,6 +90,7 @@ foreach_dma_channel! {
89 count, 90 count,
90 false, 91 false,
91 vals::Size::from(W::bits()), 92 vals::Size::from(W::bits()),
93 options,
92 #[cfg(dmamux)] 94 #[cfg(dmamux)]
93 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, 95 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS,
94 #[cfg(dmamux)] 96 #[cfg(dmamux)]
@@ -96,7 +98,7 @@ foreach_dma_channel! {
96 ) 98 )
97 } 99 }
98 100
99 unsafe fn start_read<W: Word>(&mut self, _request: Request, reg_addr: *const W, buf: *mut [W]) { 101 unsafe fn start_read<W: Word>(&mut self, _request: Request, reg_addr: *const W, buf: *mut [W], options: TransferOptions) {
100 let (ptr, len) = super::slice_ptr_parts_mut(buf); 102 let (ptr, len) = super::slice_ptr_parts_mut(buf);
101 low_level_api::start_transfer( 103 low_level_api::start_transfer(
102 pac::$dma_peri, 104 pac::$dma_peri,
@@ -109,6 +111,7 @@ foreach_dma_channel! {
109 len, 111 len,
110 true, 112 true,
111 vals::Size::from(W::bits()), 113 vals::Size::from(W::bits()),
114 options,
112 #[cfg(dmamux)] 115 #[cfg(dmamux)]
113 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, 116 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS,
114 #[cfg(dmamux)] 117 #[cfg(dmamux)]
@@ -155,9 +158,23 @@ mod low_level_api {
155 mem_len: usize, 158 mem_len: usize,
156 incr_mem: bool, 159 incr_mem: bool,
157 data_size: vals::Size, 160 data_size: vals::Size,
161 options: TransferOptions,
158 #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, 162 #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux,
159 #[cfg(dmamux)] dmamux_ch_num: u8, 163 #[cfg(dmamux)] dmamux_ch_num: u8,
160 ) { 164 ) {
165 assert!(
166 options.mburst == crate::dma::Burst::Single,
167 "Burst mode not supported"
168 );
169 assert!(
170 options.pburst == crate::dma::Burst::Single,
171 "Burst mode not supported"
172 );
173 assert!(
174 options.flow_ctrl == crate::dma::FlowControl::Dma,
175 "Peripheral flow control not supported"
176 );
177
161 let ch = dma.ch(channel_number as _); 178 let ch = dma.ch(channel_number as _);
162 179
163 reset_status(dma, channel_number); 180 reset_status(dma, channel_number);
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index 9f88c1141..0bce37e48 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -9,7 +9,7 @@ use crate::interrupt;
9use crate::pac; 9use crate::pac;
10use crate::pac::dma::{regs, vals}; 10use crate::pac::dma::{regs, vals};
11 11
12use super::{Request, Word, WordSize}; 12use super::{Burst, FlowControl, Request, TransferOptions, Word, WordSize};
13 13
14impl From<WordSize> for vals::Size { 14impl From<WordSize> for vals::Size {
15 fn from(raw: WordSize) -> Self { 15 fn from(raw: WordSize) -> Self {
@@ -21,6 +21,26 @@ impl From<WordSize> for vals::Size {
21 } 21 }
22} 22}
23 23
24impl From<Burst> for vals::Burst {
25 fn from(burst: Burst) -> Self {
26 match burst {
27 Burst::Single => vals::Burst::SINGLE,
28 Burst::Incr4 => vals::Burst::INCR4,
29 Burst::Incr8 => vals::Burst::INCR8,
30 Burst::Incr16 => vals::Burst::INCR16,
31 }
32 }
33}
34
35impl From<FlowControl> for vals::Pfctrl {
36 fn from(flow: FlowControl) -> Self {
37 match flow {
38 FlowControl::Dma => vals::Pfctrl::DMA,
39 FlowControl::Peripheral => vals::Pfctrl::PERIPHERAL,
40 }
41 }
42}
43
24struct State { 44struct State {
25 ch_wakers: [AtomicWaker; DMA_CHANNEL_COUNT], 45 ch_wakers: [AtomicWaker; DMA_CHANNEL_COUNT],
26} 46}
@@ -49,7 +69,7 @@ pub(crate) unsafe fn init() {
49foreach_dma_channel! { 69foreach_dma_channel! {
50 ($channel_peri:ident, $dma_peri:ident, dma, $channel_num:expr, $index:expr, $dmamux:tt) => { 70 ($channel_peri:ident, $dma_peri:ident, dma, $channel_num:expr, $index:expr, $dmamux:tt) => {
51 impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri { 71 impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {
52 unsafe fn start_write<W: Word>(&mut self, request: Request, buf: *const [W], reg_addr: *mut W) { 72 unsafe fn start_write<W: Word>(&mut self, request: Request, buf: *const [W], reg_addr: *mut W, options: TransferOptions) {
53 let (ptr, len) = super::slice_ptr_parts(buf); 73 let (ptr, len) = super::slice_ptr_parts(buf);
54 low_level_api::start_transfer( 74 low_level_api::start_transfer(
55 pac::$dma_peri, 75 pac::$dma_peri,
@@ -61,6 +81,7 @@ foreach_dma_channel! {
61 len, 81 len,
62 true, 82 true,
63 vals::Size::from(W::bits()), 83 vals::Size::from(W::bits()),
84 options,
64 #[cfg(dmamux)] 85 #[cfg(dmamux)]
65 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, 86 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS,
66 #[cfg(dmamux)] 87 #[cfg(dmamux)]
@@ -68,7 +89,7 @@ foreach_dma_channel! {
68 ) 89 )
69 } 90 }
70 91
71 unsafe fn start_write_repeated<W: Word>(&mut self, request: Request, repeated: W, count: usize, reg_addr: *mut W) { 92 unsafe fn start_write_repeated<W: Word>(&mut self, request: Request, repeated: W, count: usize, reg_addr: *mut W, options: TransferOptions) {
72 let buf = [repeated]; 93 let buf = [repeated];
73 low_level_api::start_transfer( 94 low_level_api::start_transfer(
74 pac::$dma_peri, 95 pac::$dma_peri,
@@ -80,6 +101,7 @@ foreach_dma_channel! {
80 count, 101 count,
81 false, 102 false,
82 vals::Size::from(W::bits()), 103 vals::Size::from(W::bits()),
104 options,
83 #[cfg(dmamux)] 105 #[cfg(dmamux)]
84 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, 106 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS,
85 #[cfg(dmamux)] 107 #[cfg(dmamux)]
@@ -87,7 +109,7 @@ foreach_dma_channel! {
87 ) 109 )
88 } 110 }
89 111
90 unsafe fn start_read<W: Word>(&mut self, request: Request, reg_addr: *const W, buf: *mut [W]) { 112 unsafe fn start_read<W: Word>(&mut self, request: Request, reg_addr: *const W, buf: *mut [W], options: TransferOptions) {
91 let (ptr, len) = super::slice_ptr_parts_mut(buf); 113 let (ptr, len) = super::slice_ptr_parts_mut(buf);
92 low_level_api::start_transfer( 114 low_level_api::start_transfer(
93 pac::$dma_peri, 115 pac::$dma_peri,
@@ -99,6 +121,7 @@ foreach_dma_channel! {
99 len, 121 len,
100 true, 122 true,
101 vals::Size::from(W::bits()), 123 vals::Size::from(W::bits()),
124 options,
102 #[cfg(dmamux)] 125 #[cfg(dmamux)]
103 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, 126 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS,
104 #[cfg(dmamux)] 127 #[cfg(dmamux)]
@@ -146,6 +169,7 @@ mod low_level_api {
146 mem_len: usize, 169 mem_len: usize,
147 incr_mem: bool, 170 incr_mem: bool,
148 data_size: vals::Size, 171 data_size: vals::Size,
172 options: TransferOptions,
149 #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, 173 #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux,
150 #[cfg(dmamux)] dmamux_ch_num: u8, 174 #[cfg(dmamux)] dmamux_ch_num: u8,
151 ) { 175 ) {
@@ -180,6 +204,10 @@ mod low_level_api {
180 #[cfg(dma_v2)] 204 #[cfg(dma_v2)]
181 w.set_chsel(request); 205 w.set_chsel(request);
182 206
207 w.set_pburst(options.pburst.into());
208 w.set_mburst(options.mburst.into());
209 w.set_pfctrl(options.flow_ctrl.into());
210
183 w.set_en(true); 211 w.set_en(true);
184 }); 212 });
185 } 213 }
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index 4768a448c..8e9823772 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -46,6 +46,7 @@ pub(crate) mod sealed {
46 request: Request, 46 request: Request,
47 buf: *const [W], 47 buf: *const [W],
48 reg_addr: *mut W, 48 reg_addr: *mut W,
49 options: TransferOptions,
49 ); 50 );
50 51
51 /// Starts this channel for writing a word repeatedly. 52 /// Starts this channel for writing a word repeatedly.
@@ -58,6 +59,7 @@ pub(crate) mod sealed {
58 repeated: W, 59 repeated: W,
59 count: usize, 60 count: usize,
60 reg_addr: *mut W, 61 reg_addr: *mut W,
62 options: TransferOptions,
61 ); 63 );
62 64
63 /// Starts this channel for reading a stream of words. 65 /// Starts this channel for reading a stream of words.
@@ -71,6 +73,7 @@ pub(crate) mod sealed {
71 request: Request, 73 request: Request,
72 reg_addr: *const W, 74 reg_addr: *const W,
73 buf: *mut [W], 75 buf: *mut [W],
76 options: TransferOptions,
74 ); 77 );
75 78
76 /// Requests the channel to stop. 79 /// Requests the channel to stop.
@@ -126,6 +129,45 @@ impl Word for u32 {
126 } 129 }
127} 130}
128 131
132#[derive(Debug, PartialEq)]
133pub enum Burst {
134 /// Single transfer
135 Single,
136 /// Incremental burst of 4 beats
137 Incr4,
138 /// Incremental burst of 8 beats
139 Incr8,
140 /// Incremental burst of 16 beats
141 Incr16,
142}
143
144#[derive(Debug, PartialEq)]
145pub enum FlowControl {
146 /// Flow control by DMA
147 Dma,
148 /// Flow control by peripheral
149 Peripheral,
150}
151
152pub struct TransferOptions {
153 /// Peripheral burst transfer configuration
154 pub pburst: Burst,
155 /// Memory burst transfer configuration
156 pub mburst: Burst,
157 /// Flow control configuration
158 pub flow_ctrl: FlowControl,
159}
160
161impl Default for TransferOptions {
162 fn default() -> Self {
163 Self {
164 pburst: Burst::Single,
165 mburst: Burst::Single,
166 flow_ctrl: FlowControl::Dma,
167 }
168 }
169}
170
129mod transfers { 171mod transfers {
130 use super::*; 172 use super::*;
131 173
@@ -139,7 +181,7 @@ mod transfers {
139 assert!(buf.len() > 0 && buf.len() <= 0xFFFF); 181 assert!(buf.len() > 0 && buf.len() <= 0xFFFF);
140 unborrow!(channel); 182 unborrow!(channel);
141 183
142 unsafe { channel.start_read::<W>(request, reg_addr, buf) }; 184 unsafe { channel.start_read::<W>(request, reg_addr, buf, Default::default()) };
143 185
144 Transfer::new(channel) 186 Transfer::new(channel)
145 } 187 }
@@ -154,7 +196,7 @@ mod transfers {
154 assert!(buf.len() > 0 && buf.len() <= 0xFFFF); 196 assert!(buf.len() > 0 && buf.len() <= 0xFFFF);
155 unborrow!(channel); 197 unborrow!(channel);
156 198
157 unsafe { channel.start_write::<W>(request, buf, reg_addr) }; 199 unsafe { channel.start_write::<W>(request, buf, reg_addr, Default::default()) };
158 200
159 Transfer::new(channel) 201 Transfer::new(channel)
160 } 202 }
@@ -169,7 +211,15 @@ mod transfers {
169 ) -> impl Future<Output = ()> + 'a { 211 ) -> impl Future<Output = ()> + 'a {
170 unborrow!(channel); 212 unborrow!(channel);
171 213
172 unsafe { channel.start_write_repeated::<W>(request, repeated, count, reg_addr) }; 214 unsafe {
215 channel.start_write_repeated::<W>(
216 request,
217 repeated,
218 count,
219 reg_addr,
220 Default::default(),
221 )
222 };
173 223
174 Transfer::new(channel) 224 Transfer::new(channel)
175 } 225 }
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index 087cb4c40..f983c6759 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -1,7 +1,1554 @@
1#![macro_use] 1#![macro_use]
2 2
3#[cfg_attr(sdmmc_v1, path = "v1.rs")] 3use core::default::Default;
4#[cfg_attr(sdmmc_v2, path = "v2.rs")] 4use core::marker::PhantomData;
5mod _version; 5use core::task::Poll;
6 6
7pub use _version::*; 7use embassy::interrupt::InterruptExt;
8use embassy::util::Unborrow;
9use embassy::waitqueue::AtomicWaker;
10use embassy_hal_common::drop::OnDrop;
11use embassy_hal_common::unborrow;
12use futures::future::poll_fn;
13use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR};
14
15use crate::dma::NoDma;
16use crate::gpio::sealed::AFType;
17use crate::gpio::{Pull, Speed};
18use crate::interrupt::Interrupt;
19use crate::pac::sdmmc::Sdmmc as RegBlock;
20use crate::peripherals;
21use crate::rcc::RccPeripheral;
22use crate::time::Hertz;
23
24/// The signalling scheme used on the SDMMC bus
25#[non_exhaustive]
26#[derive(Debug, Copy, Clone, PartialEq, Eq)]
27#[cfg_attr(feature = "defmt", derive(defmt::Format))]
28pub enum Signalling {
29 SDR12,
30 SDR25,
31 SDR50,
32 SDR104,
33 DDR50,
34}
35
36impl Default for Signalling {
37 fn default() -> Self {
38 Signalling::SDR12
39 }
40}
41
42#[repr(align(4))]
43pub struct DataBlock([u8; 512]);
44
45/// Errors
46#[non_exhaustive]
47#[derive(Debug, Copy, Clone)]
48#[cfg_attr(feature = "defmt", derive(defmt::Format))]
49pub enum Error {
50 Timeout,
51 SoftwareTimeout,
52 UnsupportedCardVersion,
53 UnsupportedCardType,
54 Crc,
55 DataCrcFail,
56 RxOverFlow,
57 NoCard,
58 BadClock,
59 SignalingSwitchFailed,
60 PeripheralBusy,
61}
62
63/// A SD command
64struct Cmd {
65 cmd: u8,
66 arg: u32,
67 resp: Response,
68}
69
70#[derive(Clone, Copy, Debug, Default)]
71/// SD Card
72pub struct Card {
73 /// The type of this card
74 pub card_type: CardCapacity,
75 /// Operation Conditions Register
76 pub ocr: OCR,
77 /// Relative Card Address
78 pub rca: u32,
79 /// Card ID
80 pub cid: CID,
81 /// Card Specific Data
82 pub csd: CSD,
83 /// SD CARD Configuration Register
84 pub scr: SCR,
85 /// SD Status
86 pub status: SDStatus,
87}
88
89impl Card {
90 /// Size in bytes
91 pub fn size(&self) -> u64 {
92 // SDHC / SDXC / SDUC
93 u64::from(self.csd.block_count()) * 512
94 }
95}
96
97#[repr(u8)]
98enum PowerCtrl {
99 Off = 0b00,
100 On = 0b11,
101}
102
103#[repr(u32)]
104#[allow(dead_code)]
105#[allow(non_camel_case_types)]
106enum CmdAppOper {
107 VOLTAGE_WINDOW_SD = 0x8010_0000,
108 HIGH_CAPACITY = 0x4000_0000,
109 SDMMC_STD_CAPACITY = 0x0000_0000,
110 SDMMC_CHECK_PATTERN = 0x0000_01AA,
111 SD_SWITCH_1_8V_CAPACITY = 0x0100_0000,
112}
113
114#[derive(Eq, PartialEq, Copy, Clone)]
115enum Response {
116 None = 0,
117 Short = 1,
118 Long = 3,
119}
120
121cfg_if::cfg_if! {
122 if #[cfg(sdmmc_v1)] {
123 /// Calculate clock divisor. Returns a SDMMC_CK less than or equal to
124 /// `sdmmc_ck` in Hertz.
125 ///
126 /// Returns `(clk_div, clk_f)`, where `clk_div` is the divisor register
127 /// value and `clk_f` is the resulting new clock frequency.
128 fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(u8, Hertz), Error> {
129 let clk_div = match ker_ck.0 / sdmmc_ck {
130 0 | 1 => Ok(0),
131 x @ 2..=258 => {
132 Ok((x - 2) as u8)
133 }
134 _ => Err(Error::BadClock),
135 }?;
136
137 // SDIO_CK frequency = SDIOCLK / [CLKDIV + 2]
138 let clk_f = Hertz(ker_ck.0 / (clk_div as u32 + 2));
139 Ok((clk_div, clk_f))
140 }
141 } else if #[cfg(sdmmc_v2)] {
142 /// Calculate clock divisor. Returns a SDMMC_CK less than or equal to
143 /// `sdmmc_ck` in Hertz.
144 ///
145 /// Returns `(clk_div, clk_f)`, where `clk_div` is the divisor register
146 /// value and `clk_f` is the resulting new clock frequency.
147 fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(u16, Hertz), Error> {
148 match (ker_ck.0 + sdmmc_ck - 1) / sdmmc_ck {
149 0 | 1 => Ok((0, ker_ck)),
150 x @ 2..=2046 => {
151 let clk_div = ((x + 1) / 2) as u16;
152 let clk = Hertz(ker_ck.0 / (clk_div as u32 * 2));
153
154 Ok((clk_div, clk))
155 }
156 _ => Err(Error::BadClock),
157 }
158 }
159 }
160}
161
162/// SDMMC configuration
163///
164/// Default values:
165/// data_transfer_timeout: 5_000_000
166#[non_exhaustive]
167pub struct Config {
168 /// The timeout to be set for data transfers, in card bus clock periods
169 pub data_transfer_timeout: u32,
170}
171
172impl Default for Config {
173 fn default() -> Self {
174 Self {
175 data_transfer_timeout: 5_000_000,
176 }
177 }
178}
179
180/// Sdmmc device
181pub struct Sdmmc<'d, T: Instance, P: Pins<T>, Dma = NoDma> {
182 sdmmc: PhantomData<&'d mut T>,
183 pins: P,
184 irq: T::Interrupt,
185 config: Config,
186 dma: Dma,
187 /// Current clock to card
188 clock: Hertz,
189 /// Current signalling scheme to card
190 signalling: Signalling,
191 /// Card
192 card: Option<Card>,
193}
194
195#[cfg(sdmmc_v1)]
196impl<'d, T: Instance, P: Pins<T>, Dma: SdmmcDma<T>> Sdmmc<'d, T, P, Dma> {
197 pub fn new(
198 _peripheral: impl Unborrow<Target = T> + 'd,
199 pins: impl Unborrow<Target = P> + 'd,
200 irq: impl Unborrow<Target = T::Interrupt> + 'd,
201 config: Config,
202 dma: impl Unborrow<Target = Dma> + 'd,
203 ) -> Self {
204 unborrow!(irq, pins, dma);
205 pins.configure();
206
207 T::enable();
208 T::reset();
209
210 let inner = T::inner();
211 let clock = unsafe { inner.new_inner(T::frequency()) };
212
213 irq.set_handler(Self::on_interrupt);
214 irq.unpend();
215 irq.enable();
216
217 Self {
218 sdmmc: PhantomData,
219 pins,
220 irq,
221 config,
222 dma,
223 clock,
224 signalling: Default::default(),
225 card: None,
226 }
227 }
228}
229
230#[cfg(sdmmc_v2)]
231impl<'d, T: Instance, P: Pins<T>> Sdmmc<'d, T, P, NoDma> {
232 pub fn new(
233 _peripheral: impl Unborrow<Target = T> + 'd,
234 pins: impl Unborrow<Target = P> + 'd,
235 irq: impl Unborrow<Target = T::Interrupt> + 'd,
236 config: Config,
237 ) -> Self {
238 unborrow!(irq, pins);
239 pins.configure();
240
241 T::enable();
242 T::reset();
243
244 let inner = T::inner();
245 let clock = unsafe { inner.new_inner(T::frequency()) };
246
247 irq.set_handler(Self::on_interrupt);
248 irq.unpend();
249 irq.enable();
250
251 Self {
252 sdmmc: PhantomData,
253 pins,
254 irq,
255 config,
256 dma: NoDma,
257 clock,
258 signalling: Default::default(),
259 card: None,
260 }
261 }
262}
263
264impl<'d, T: Instance, P: Pins<T>, Dma: SdmmcDma<T>> Sdmmc<'d, T, P, Dma> {
265 #[inline(always)]
266 pub async fn init_card(&mut self, freq: impl Into<Hertz>) -> Result<(), Error> {
267 let inner = T::inner();
268 let freq = freq.into();
269
270 inner
271 .init_card(
272 freq,
273 P::BUSWIDTH,
274 &mut self.card,
275 &mut self.signalling,
276 T::frequency(),
277 &mut self.clock,
278 T::state(),
279 self.config.data_transfer_timeout,
280 &mut self.dma,
281 )
282 .await
283 }
284
285 #[inline(always)]
286 pub async fn read_block(
287 &mut self,
288 block_idx: u32,
289 buffer: &mut DataBlock,
290 ) -> Result<(), Error> {
291 let card_capacity = self.card()?.card_type;
292 let inner = T::inner();
293 let state = T::state();
294
295 // NOTE(unsafe) DataBlock uses align 4
296 let buf = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) };
297 inner
298 .read_block(
299 block_idx,
300 buf,
301 card_capacity,
302 state,
303 self.config.data_transfer_timeout,
304 &mut self.dma,
305 )
306 .await
307 }
308
309 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> {
310 let card = self.card.as_mut().ok_or(Error::NoCard)?;
311 let inner = T::inner();
312 let state = T::state();
313
314 // NOTE(unsafe) DataBlock uses align 4
315 let buf = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) };
316 inner
317 .write_block(
318 block_idx,
319 buf,
320 card,
321 state,
322 self.config.data_transfer_timeout,
323 &mut self.dma,
324 )
325 .await
326 }
327
328 /// Get a reference to the initialized card
329 ///
330 /// # Errors
331 ///
332 /// Returns Error::NoCard if [`init_card`](#method.init_card)
333 /// has not previously succeeded
334 #[inline(always)]
335 pub fn card(&self) -> Result<&Card, Error> {
336 self.card.as_ref().ok_or(Error::NoCard)
337 }
338
339 /// Get the current SDMMC bus clock
340 pub fn clock(&self) -> Hertz {
341 self.clock
342 }
343
344 #[inline(always)]
345 fn on_interrupt(_: *mut ()) {
346 let regs = T::inner();
347 let state = T::state();
348
349 regs.data_interrupts(false);
350 state.wake();
351 }
352}
353
354impl<'d, T: Instance, P: Pins<T>, Dma> Drop for Sdmmc<'d, T, P, Dma> {
355 fn drop(&mut self) {
356 self.irq.disable();
357 let inner = T::inner();
358 unsafe { inner.on_drop() };
359 self.pins.deconfigure();
360 }
361}
362
363pub struct SdmmcInner(pub(crate) RegBlock);
364
365impl SdmmcInner {
366 /// # Safety
367 ///
368 /// Access to `regs` registers should be exclusive
369 unsafe fn new_inner(&self, kernel_clk: Hertz) -> Hertz {
370 let regs = self.0;
371
372 // While the SD/SDIO card or eMMC is in identification mode,
373 // the SDMMC_CK frequency must be less than 400 kHz.
374 let (clkdiv, clock) = unwrap!(clk_div(kernel_clk, 400_000));
375
376 regs.clkcr().write(|w| {
377 w.set_widbus(0);
378 w.set_clkdiv(clkdiv);
379 w.set_pwrsav(false);
380 w.set_negedge(false);
381 w.set_hwfc_en(true);
382
383 #[cfg(sdmmc_v1)]
384 w.set_clken(true);
385 });
386
387 // Power off, writen 00: Clock to the card is stopped;
388 // D[7:0], CMD, and CK are driven high.
389 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8));
390
391 clock
392 }
393
394 /// Initializes card (if present) and sets the bus at the
395 /// specified frequency.
396 #[allow(clippy::too_many_arguments)]
397 async fn init_card<T: Instance, Dma: SdmmcDma<T>>(
398 &self,
399 freq: Hertz,
400 bus_width: BusWidth,
401 old_card: &mut Option<Card>,
402 signalling: &mut Signalling,
403 ker_ck: Hertz,
404 clock: &mut Hertz,
405 waker_reg: &AtomicWaker,
406 data_transfer_timeout: u32,
407 dma: &mut Dma,
408 ) -> Result<(), Error> {
409 let regs = self.0;
410
411 // NOTE(unsafe) We have exclusive access to the peripheral
412 unsafe {
413 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
414 self.cmd(Cmd::idle(), false)?;
415
416 // Check if cards supports CMD8 (with pattern)
417 self.cmd(Cmd::hs_send_ext_csd(0x1AA), false)?;
418 let r1 = regs.respr(0).read().cardstatus();
419
420 let mut card = if r1 == 0x1AA {
421 // Card echoed back the pattern. Must be at least v2
422 Card::default()
423 } else {
424 return Err(Error::UnsupportedCardVersion);
425 };
426
427 let ocr = loop {
428 // Signal that next command is a app command
429 self.cmd(Cmd::app_cmd(0), false)?; // CMD55
430
431 let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32
432 | CmdAppOper::HIGH_CAPACITY as u32
433 | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32;
434
435 // Initialize card
436 match self.cmd(Cmd::app_op_cmd(arg), false) {
437 // ACMD41
438 Ok(_) => (),
439 Err(Error::Crc) => (),
440 Err(err) => return Err(err),
441 }
442 let ocr: OCR = regs.respr(0).read().cardstatus().into();
443 if !ocr.is_busy() {
444 // Power up done
445 break ocr;
446 }
447 };
448
449 if ocr.high_capacity() {
450 // Card is SDHC or SDXC or SDUC
451 card.card_type = CardCapacity::SDHC;
452 } else {
453 card.card_type = CardCapacity::SDSC;
454 }
455 card.ocr = ocr;
456
457 self.cmd(Cmd::all_send_cid(), false)?; // CMD2
458 let cid0 = regs.respr(0).read().cardstatus() as u128;
459 let cid1 = regs.respr(1).read().cardstatus() as u128;
460 let cid2 = regs.respr(2).read().cardstatus() as u128;
461 let cid3 = regs.respr(3).read().cardstatus() as u128;
462 let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
463 card.cid = cid.into();
464
465 self.cmd(Cmd::send_rel_addr(), false)?;
466 card.rca = regs.respr(0).read().cardstatus() >> 16;
467
468 self.cmd(Cmd::send_csd(card.rca << 16), false)?;
469 let csd0 = regs.respr(0).read().cardstatus() as u128;
470 let csd1 = regs.respr(1).read().cardstatus() as u128;
471 let csd2 = regs.respr(2).read().cardstatus() as u128;
472 let csd3 = regs.respr(3).read().cardstatus() as u128;
473 let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
474 card.csd = csd.into();
475
476 self.select_card(Some(&card))?;
477
478 self.get_scr(&mut card, waker_reg, data_transfer_timeout, dma)
479 .await?;
480
481 // Set bus width
482 let (width, acmd_arg) = match bus_width {
483 BusWidth::Eight => unimplemented!(),
484 BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2),
485 _ => (BusWidth::One, 0),
486 };
487 self.cmd(Cmd::app_cmd(card.rca << 16), false)?;
488 self.cmd(Cmd::cmd6(acmd_arg), false)?;
489
490 // CPSMACT and DPSMACT must be 0 to set WIDBUS
491 self.wait_idle();
492
493 regs.clkcr().modify(|w| {
494 w.set_widbus(match width {
495 BusWidth::One => 0,
496 BusWidth::Four => 1,
497 BusWidth::Eight => 2,
498 _ => panic!("Invalid Bus Width"),
499 })
500 });
501
502 // Set Clock
503 if freq.0 <= 25_000_000 {
504 // Final clock frequency
505 self.clkcr_set_clkdiv(freq.0, width, ker_ck, clock)?;
506 } else {
507 // Switch to max clock for SDR12
508 self.clkcr_set_clkdiv(25_000_000, width, ker_ck, clock)?;
509 }
510
511 // Read status
512 self.read_sd_status(&mut card, waker_reg, data_transfer_timeout, dma)
513 .await?;
514
515 if freq.0 > 25_000_000 {
516 // Switch to SDR25
517 *signalling = self
518 .switch_signalling_mode(
519 Signalling::SDR25,
520 waker_reg,
521 data_transfer_timeout,
522 dma,
523 )
524 .await?;
525
526 if *signalling == Signalling::SDR25 {
527 // Set final clock frequency
528 self.clkcr_set_clkdiv(freq.0, width, ker_ck, clock)?;
529
530 if self.read_status(&card)?.state() != CurrentState::Transfer {
531 return Err(Error::SignalingSwitchFailed);
532 }
533 }
534 }
535 // Read status after signalling change
536 self.read_sd_status(&mut card, waker_reg, data_transfer_timeout, dma)
537 .await?;
538 old_card.replace(card);
539 }
540
541 Ok(())
542 }
543
544 async fn read_block<T: Instance, Dma: SdmmcDma<T>>(
545 &self,
546 block_idx: u32,
547 buffer: &mut [u32; 128],
548 capacity: CardCapacity,
549 waker_reg: &AtomicWaker,
550 data_transfer_timeout: u32,
551 dma: &mut Dma,
552 ) -> Result<(), Error> {
553 // Always read 1 block of 512 bytes
554 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
555 let address = match capacity {
556 CardCapacity::SDSC => block_idx * 512,
557 _ => block_idx,
558 };
559 self.cmd(Cmd::set_block_length(512), false)?; // CMD16
560
561 let regs = self.0;
562 let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
563
564 unsafe {
565 self.prepare_datapath_read(
566 buffer as *mut [u32; 128],
567 512,
568 9,
569 data_transfer_timeout,
570 dma,
571 );
572 self.data_interrupts(true);
573 }
574 self.cmd(Cmd::read_single_block(address), true)?;
575
576 let res = poll_fn(|cx| {
577 waker_reg.register(cx.waker());
578 let status = unsafe { regs.star().read() };
579
580 if status.dcrcfail() {
581 return Poll::Ready(Err(Error::Crc));
582 } else if status.dtimeout() {
583 return Poll::Ready(Err(Error::Timeout));
584 } else if status.dataend() {
585 return Poll::Ready(Ok(()));
586 }
587 Poll::Pending
588 })
589 .await;
590 self.clear_interrupt_flags();
591
592 if res.is_ok() {
593 on_drop.defuse();
594 self.stop_datapath();
595 }
596 res
597 }
598
599 async fn write_block<T: Instance, Dma: SdmmcDma<T>>(
600 &self,
601 block_idx: u32,
602 buffer: &[u32; 128],
603 card: &mut Card,
604 waker_reg: &AtomicWaker,
605 data_transfer_timeout: u32,
606 dma: &mut Dma,
607 ) -> Result<(), Error> {
608 // Always read 1 block of 512 bytes
609 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
610 let address = match card.card_type {
611 CardCapacity::SDSC => block_idx * 512,
612 _ => block_idx,
613 };
614 self.cmd(Cmd::set_block_length(512), false)?; // CMD16
615
616 let regs = self.0;
617 let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
618
619 unsafe {
620 self.prepare_datapath_write(
621 buffer as *const [u32; 128],
622 512,
623 9,
624 data_transfer_timeout,
625 dma,
626 );
627 self.data_interrupts(true);
628 }
629 self.cmd(Cmd::write_single_block(address), true)?;
630
631 let res = poll_fn(|cx| {
632 waker_reg.register(cx.waker());
633 let status = unsafe { regs.star().read() };
634
635 if status.dcrcfail() {
636 return Poll::Ready(Err(Error::Crc));
637 } else if status.dtimeout() {
638 return Poll::Ready(Err(Error::Timeout));
639 } else if status.dataend() {
640 return Poll::Ready(Ok(()));
641 }
642 Poll::Pending
643 })
644 .await;
645 self.clear_interrupt_flags();
646
647 match res {
648 Ok(_) => {
649 on_drop.defuse();
650 self.stop_datapath();
651
652 // TODO: Make this configurable
653 let mut timeout: u32 = 0x00FF_FFFF;
654
655 // Try to read card status (ACMD13)
656 while timeout > 0 {
657 match self
658 .read_sd_status(card, waker_reg, data_transfer_timeout, dma)
659 .await
660 {
661 Ok(_) => return Ok(()),
662 Err(Error::Timeout) => (), // Try again
663 Err(e) => return Err(e),
664 }
665 timeout -= 1;
666 }
667 Err(Error::SoftwareTimeout)
668 }
669 Err(e) => Err(e),
670 }
671 }
672
673 /// Data transfer is in progress
674 #[inline(always)]
675 fn data_active(&self) -> bool {
676 let regs = self.0;
677
678 // NOTE(unsafe) Atomic read with no side-effects
679 unsafe {
680 let status = regs.star().read();
681 cfg_if::cfg_if! {
682 if #[cfg(sdmmc_v1)] {
683 status.rxact() || status.txact()
684 } else if #[cfg(sdmmc_v2)] {
685 status.dpsmact()
686 }
687 }
688 }
689 }
690
691 /// Coammand transfer is in progress
692 #[inline(always)]
693 fn cmd_active(&self) -> bool {
694 let regs = self.0;
695
696 // NOTE(unsafe) Atomic read with no side-effects
697 unsafe {
698 let status = regs.star().read();
699 cfg_if::cfg_if! {
700 if #[cfg(sdmmc_v1)] {
701 status.cmdact()
702 } else if #[cfg(sdmmc_v2)] {
703 status.cpsmact()
704 }
705 }
706 }
707 }
708
709 /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2)
710 #[inline(always)]
711 fn wait_idle(&self) {
712 while self.data_active() || self.cmd_active() {}
713 }
714
715 /// # Safety
716 ///
717 /// `buffer` must be valid for the whole transfer and word aligned
718 unsafe fn prepare_datapath_read<T: Instance, Dma: SdmmcDma<T>>(
719 &self,
720 buffer: *mut [u32],
721 length_bytes: u32,
722 block_size: u8,
723 data_transfer_timeout: u32,
724 #[allow(unused_variables)] dma: &mut Dma,
725 ) {
726 assert!(block_size <= 14, "Block size up to 2^14 bytes");
727 let regs = self.0;
728
729 // Command AND Data state machines must be idle
730 self.wait_idle();
731 self.clear_interrupt_flags();
732
733 // NOTE(unsafe) We have exclusive access to the regisers
734
735 regs.dtimer()
736 .write(|w| w.set_datatime(data_transfer_timeout));
737 regs.dlenr().write(|w| w.set_datalength(length_bytes));
738
739 cfg_if::cfg_if! {
740 if #[cfg(sdmmc_v1)] {
741 let request = dma.request();
742 dma.start_read(request, regs.fifor().ptr() as *const u32, buffer, crate::dma::TransferOptions {
743 pburst: crate::dma::Burst::Incr4,
744 flow_ctrl: crate::dma::FlowControl::Peripheral,
745 ..Default::default()
746 });
747 } else if #[cfg(sdmmc_v2)] {
748 regs.idmabase0r().write(|w| w.set_idmabase0(buffer as *mut u32 as u32));
749 regs.idmactrlr().modify(|w| w.set_idmaen(true));
750 }
751 }
752
753 regs.dctrl().modify(|w| {
754 w.set_dblocksize(block_size);
755 w.set_dtdir(true);
756 #[cfg(sdmmc_v1)]
757 {
758 w.set_dmaen(true);
759 w.set_dten(true);
760 }
761 });
762 }
763
764 /// # Safety
765 ///
766 /// `buffer` must be valid for the whole transfer and word aligned
767 unsafe fn prepare_datapath_write<T: Instance, Dma: SdmmcDma<T>>(
768 &self,
769 buffer: *const [u32],
770 length_bytes: u32,
771 block_size: u8,
772 data_transfer_timeout: u32,
773 #[allow(unused_variables)] dma: &mut Dma,
774 ) {
775 assert!(block_size <= 14, "Block size up to 2^14 bytes");
776 let regs = self.0;
777
778 // Command AND Data state machines must be idle
779 self.wait_idle();
780 self.clear_interrupt_flags();
781
782 // NOTE(unsafe) We have exclusive access to the regisers
783
784 regs.dtimer()
785 .write(|w| w.set_datatime(data_transfer_timeout));
786 regs.dlenr().write(|w| w.set_datalength(length_bytes));
787
788 cfg_if::cfg_if! {
789 if #[cfg(sdmmc_v1)] {
790 let request = dma.request();
791 dma.start_write(request, buffer, regs.fifor().ptr() as *mut u32, crate::dma::TransferOptions {
792 pburst: crate::dma::Burst::Incr4,
793 flow_ctrl: crate::dma::FlowControl::Peripheral,
794 ..Default::default()
795 });
796 } else if #[cfg(sdmmc_v2)] {
797 regs.idmabase0r().write(|w| w.set_idmabase0(buffer as *const u32 as u32));
798 regs.idmactrlr().modify(|w| w.set_idmaen(true));
799 }
800 }
801
802 regs.dctrl().modify(|w| {
803 w.set_dblocksize(block_size);
804 w.set_dtdir(false);
805 });
806 }
807
808 /// Stops the DMA datapath
809 fn stop_datapath(&self) {
810 let regs = self.0;
811
812 unsafe {
813 cfg_if::cfg_if! {
814 if #[cfg(sdmmc_v1)] {
815 regs.dctrl().modify(|w| {
816 w.set_dmaen(false);
817 w.set_dten(false);
818 });
819 } else if #[cfg(sdmmc_v2)] {
820 regs.idmactrlr().modify(|w| w.set_idmaen(false));
821 }
822 }
823 }
824 }
825
826 /// Sets the CLKDIV field in CLKCR. Updates clock field in self
827 fn clkcr_set_clkdiv(
828 &self,
829 freq: u32,
830 width: BusWidth,
831 ker_ck: Hertz,
832 clock: &mut Hertz,
833 ) -> Result<(), Error> {
834 let regs = self.0;
835
836 let (clkdiv, new_clock) = clk_div(ker_ck, freq)?;
837 // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7
838 // Section 55.5.8
839 let sdmmc_bus_bandwidth = new_clock.0 * (width as u32);
840 assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32);
841 *clock = new_clock;
842
843 // NOTE(unsafe) We have exclusive access to the regblock
844 unsafe {
845 // CPSMACT and DPSMACT must be 0 to set CLKDIV
846 self.wait_idle();
847 regs.clkcr().modify(|w| w.set_clkdiv(clkdiv));
848 }
849
850 Ok(())
851 }
852
853 /// Switch mode using CMD6.
854 ///
855 /// Attempt to set a new signalling mode. The selected
856 /// signalling mode is returned. Expects the current clock
857 /// frequency to be > 12.5MHz.
858 async fn switch_signalling_mode<T: Instance, Dma: SdmmcDma<T>>(
859 &self,
860 signalling: Signalling,
861 waker_reg: &AtomicWaker,
862 data_transfer_timeout: u32,
863 dma: &mut Dma,
864 ) -> Result<Signalling, Error> {
865 // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not
866 // necessary"
867
868 let set_function = 0x8000_0000
869 | match signalling {
870 // See PLSS v7_10 Table 4-11
871 Signalling::DDR50 => 0xFF_FF04,
872 Signalling::SDR104 => 0xFF_1F03,
873 Signalling::SDR50 => 0xFF_1F02,
874 Signalling::SDR25 => 0xFF_FF01,
875 Signalling::SDR12 => 0xFF_FF00,
876 };
877
878 let mut status = [0u32; 16];
879
880 // Arm `OnDrop` after the buffer, so it will be dropped first
881 let regs = self.0;
882 let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
883
884 unsafe {
885 self.prepare_datapath_read(
886 &mut status as *mut [u32; 16],
887 64,
888 6,
889 data_transfer_timeout,
890 dma,
891 );
892 self.data_interrupts(true);
893 }
894 self.cmd(Cmd::cmd6(set_function), true)?; // CMD6
895
896 let res = poll_fn(|cx| {
897 waker_reg.register(cx.waker());
898 let status = unsafe { regs.star().read() };
899
900 if status.dcrcfail() {
901 return Poll::Ready(Err(Error::Crc));
902 } else if status.dtimeout() {
903 return Poll::Ready(Err(Error::Timeout));
904 } else if status.dataend() {
905 return Poll::Ready(Ok(()));
906 }
907 Poll::Pending
908 })
909 .await;
910 self.clear_interrupt_flags();
911
912 // Host is allowed to use the new functions at least 8
913 // clocks after the end of the switch command
914 // transaction. We know the current clock period is < 80ns,
915 // so a total delay of 640ns is required here
916 for _ in 0..300 {
917 cortex_m::asm::nop();
918 }
919
920 match res {
921 Ok(_) => {
922 on_drop.defuse();
923 self.stop_datapath();
924
925 // Function Selection of Function Group 1
926 let selection = (u32::from_be(status[4]) >> 24) & 0xF;
927
928 match selection {
929 0 => Ok(Signalling::SDR12),
930 1 => Ok(Signalling::SDR25),
931 2 => Ok(Signalling::SDR50),
932 3 => Ok(Signalling::SDR104),
933 4 => Ok(Signalling::DDR50),
934 _ => Err(Error::UnsupportedCardType),
935 }
936 }
937 Err(e) => Err(e),
938 }
939 }
940
941 /// Query the card status (CMD13, returns R1)
942 ///
943 fn read_status(&self, card: &Card) -> Result<CardStatus, Error> {
944 let regs = self.0;
945 let rca = card.rca;
946
947 self.cmd(Cmd::card_status(rca << 16), false)?; // CMD13
948
949 // NOTE(unsafe) Atomic read with no side-effects
950 let r1 = unsafe { regs.respr(0).read().cardstatus() };
951 Ok(r1.into())
952 }
953
954 /// Reads the SD Status (ACMD13)
955 async fn read_sd_status<T: Instance, Dma: SdmmcDma<T>>(
956 &self,
957 card: &mut Card,
958 waker_reg: &AtomicWaker,
959 data_transfer_timeout: u32,
960 dma: &mut Dma,
961 ) -> Result<(), Error> {
962 let rca = card.rca;
963 self.cmd(Cmd::set_block_length(64), false)?; // CMD16
964 self.cmd(Cmd::app_cmd(rca << 16), false)?; // APP
965
966 let mut status = [0u32; 16];
967
968 // Arm `OnDrop` after the buffer, so it will be dropped first
969 let regs = self.0;
970 let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
971
972 unsafe {
973 self.prepare_datapath_read(
974 &mut status as *mut [u32; 16],
975 64,
976 6,
977 data_transfer_timeout,
978 dma,
979 );
980 self.data_interrupts(true);
981 }
982 self.cmd(Cmd::card_status(0), true)?;
983
984 let res = poll_fn(|cx| {
985 waker_reg.register(cx.waker());
986 let status = unsafe { regs.star().read() };
987
988 if status.dcrcfail() {
989 return Poll::Ready(Err(Error::Crc));
990 } else if status.dtimeout() {
991 return Poll::Ready(Err(Error::Timeout));
992 } else if status.dataend() {
993 return Poll::Ready(Ok(()));
994 }
995 Poll::Pending
996 })
997 .await;
998 self.clear_interrupt_flags();
999
1000 if res.is_ok() {
1001 on_drop.defuse();
1002 self.stop_datapath();
1003
1004 for byte in status.iter_mut() {
1005 *byte = u32::from_be(*byte);
1006 }
1007 card.status = status.into();
1008 }
1009 res
1010 }
1011
1012 /// Select one card and place it into the _Tranfer State_
1013 ///
1014 /// If `None` is specifed for `card`, all cards are put back into
1015 /// _Stand-by State_
1016 fn select_card(&self, card: Option<&Card>) -> Result<(), Error> {
1017 // Determine Relative Card Address (RCA) of given card
1018 let rca = card.map(|c| c.rca << 16).unwrap_or(0);
1019
1020 let r = self.cmd(Cmd::sel_desel_card(rca), false);
1021 match (r, rca) {
1022 (Err(Error::Timeout), 0) => Ok(()),
1023 _ => r,
1024 }
1025 }
1026
1027 /// Clear flags in interrupt clear register
1028 #[inline(always)]
1029 fn clear_interrupt_flags(&self) {
1030 let regs = self.0;
1031 // NOTE(unsafe) Atomic write
1032 unsafe {
1033 regs.icr().write(|w| {
1034 w.set_ccrcfailc(true);
1035 w.set_dcrcfailc(true);
1036 w.set_ctimeoutc(true);
1037 w.set_dtimeoutc(true);
1038 w.set_txunderrc(true);
1039 w.set_rxoverrc(true);
1040 w.set_cmdrendc(true);
1041 w.set_cmdsentc(true);
1042 w.set_dataendc(true);
1043 w.set_dbckendc(true);
1044 w.set_sdioitc(true);
1045
1046 #[cfg(sdmmc_v2)]
1047 {
1048 w.set_dholdc(true);
1049 w.set_dabortc(true);
1050 w.set_busyd0endc(true);
1051 w.set_ackfailc(true);
1052 w.set_acktimeoutc(true);
1053 w.set_vswendc(true);
1054 w.set_ckstopc(true);
1055 w.set_idmatec(true);
1056 w.set_idmabtcc(true);
1057 }
1058 });
1059 }
1060 }
1061
1062 /// Enables the interrupts for data transfer
1063 #[inline(always)]
1064 fn data_interrupts(&self, enable: bool) {
1065 let regs = self.0;
1066 // NOTE(unsafe) Atomic write
1067 unsafe {
1068 regs.maskr().write(|w| {
1069 w.set_dcrcfailie(enable);
1070 w.set_dtimeoutie(enable);
1071 w.set_dataendie(enable);
1072
1073 #[cfg(sdmmc_v2)]
1074 w.set_dabortie(enable);
1075 });
1076 }
1077 }
1078
1079 async fn get_scr<T: Instance, Dma: SdmmcDma<T>>(
1080 &self,
1081 card: &mut Card,
1082 waker_reg: &AtomicWaker,
1083 data_transfer_timeout: u32,
1084 dma: &mut Dma,
1085 ) -> Result<(), Error> {
1086 // Read the the 64-bit SCR register
1087 self.cmd(Cmd::set_block_length(8), false)?; // CMD16
1088 self.cmd(Cmd::app_cmd(card.rca << 16), false)?;
1089
1090 let mut scr = [0u32; 2];
1091
1092 // Arm `OnDrop` after the buffer, so it will be dropped first
1093 let regs = self.0;
1094 let on_drop = OnDrop::new(move || unsafe { self.on_drop() });
1095
1096 unsafe {
1097 self.prepare_datapath_read(&mut scr as *mut [u32], 8, 3, data_transfer_timeout, dma);
1098 self.data_interrupts(true);
1099 }
1100 self.cmd(Cmd::cmd51(), true)?;
1101
1102 let res = poll_fn(|cx| {
1103 waker_reg.register(cx.waker());
1104 let status = unsafe { regs.star().read() };
1105
1106 if status.dcrcfail() {
1107 return Poll::Ready(Err(Error::Crc));
1108 } else if status.dtimeout() {
1109 return Poll::Ready(Err(Error::Timeout));
1110 } else if status.dataend() {
1111 return Poll::Ready(Ok(()));
1112 }
1113 Poll::Pending
1114 })
1115 .await;
1116 self.clear_interrupt_flags();
1117
1118 if res.is_ok() {
1119 on_drop.defuse();
1120 self.stop_datapath();
1121
1122 unsafe {
1123 let scr_bytes = &*(&scr as *const [u32; 2] as *const [u8; 8]);
1124 card.scr = SCR(u64::from_be_bytes(*scr_bytes));
1125 }
1126 }
1127 res
1128 }
1129
1130 /// Send command to card
1131 #[allow(unused_variables)]
1132 fn cmd(&self, cmd: Cmd, data: bool) -> Result<(), Error> {
1133 let regs = self.0;
1134
1135 self.clear_interrupt_flags();
1136 // NOTE(safety) Atomic operations
1137 unsafe {
1138 // CP state machine must be idle
1139 while self.cmd_active() {}
1140
1141 // Command arg
1142 regs.argr().write(|w| w.set_cmdarg(cmd.arg));
1143
1144 // Command index and start CP State Machine
1145 regs.cmdr().write(|w| {
1146 w.set_waitint(false);
1147 w.set_waitresp(cmd.resp as u8);
1148 w.set_cmdindex(cmd.cmd);
1149 w.set_cpsmen(true);
1150
1151 #[cfg(sdmmc_v2)]
1152 {
1153 // Special mode in CP State Machine
1154 // CMD12: Stop Transmission
1155 let cpsm_stop_transmission = cmd.cmd == 12;
1156 w.set_cmdstop(cpsm_stop_transmission);
1157 w.set_cmdtrans(data);
1158 }
1159 });
1160
1161 let mut status;
1162 if cmd.resp == Response::None {
1163 // Wait for CMDSENT or a timeout
1164 while {
1165 status = regs.star().read();
1166 !(status.ctimeout() || status.cmdsent())
1167 } {}
1168 } else {
1169 // Wait for CMDREND or CCRCFAIL or a timeout
1170 while {
1171 status = regs.star().read();
1172 !(status.ctimeout() || status.cmdrend() || status.ccrcfail())
1173 } {}
1174 }
1175
1176 if status.ctimeout() {
1177 return Err(Error::Timeout);
1178 } else if status.ccrcfail() {
1179 return Err(Error::Crc);
1180 }
1181 Ok(())
1182 }
1183 }
1184
1185 /// # Safety
1186 ///
1187 /// Ensure that `regs` has exclusive access to the regblocks
1188 unsafe fn on_drop(&self) {
1189 let regs = self.0;
1190 if self.data_active() {
1191 self.clear_interrupt_flags();
1192 // Send abort
1193 // CP state machine must be idle
1194 while self.cmd_active() {}
1195
1196 // Command arg
1197 regs.argr().write(|w| w.set_cmdarg(0));
1198
1199 // Command index and start CP State Machine
1200 regs.cmdr().write(|w| {
1201 w.set_waitint(false);
1202 w.set_waitresp(Response::Short as u8);
1203 w.set_cmdindex(12);
1204 w.set_cpsmen(true);
1205
1206 #[cfg(sdmmc_v2)]
1207 {
1208 w.set_cmdstop(true);
1209 w.set_cmdtrans(false);
1210 }
1211 });
1212
1213 // Wait for the abort
1214 while self.data_active() {}
1215 }
1216 self.data_interrupts(false);
1217 self.clear_interrupt_flags();
1218 self.stop_datapath();
1219 }
1220}
1221
1222/// SD card Commands
1223impl Cmd {
1224 const fn new(cmd: u8, arg: u32, resp: Response) -> Cmd {
1225 Cmd { cmd, arg, resp }
1226 }
1227
1228 /// CMD0: Idle
1229 const fn idle() -> Cmd {
1230 Cmd::new(0, 0, Response::None)
1231 }
1232
1233 /// CMD2: Send CID
1234 const fn all_send_cid() -> Cmd {
1235 Cmd::new(2, 0, Response::Long)
1236 }
1237
1238 /// CMD3: Send Relative Address
1239 const fn send_rel_addr() -> Cmd {
1240 Cmd::new(3, 0, Response::Short)
1241 }
1242
1243 /// CMD6: Switch Function Command
1244 /// ACMD6: Bus Width
1245 const fn cmd6(arg: u32) -> Cmd {
1246 Cmd::new(6, arg, Response::Short)
1247 }
1248
1249 /// CMD7: Select one card and put it into the _Tranfer State_
1250 const fn sel_desel_card(rca: u32) -> Cmd {
1251 Cmd::new(7, rca, Response::Short)
1252 }
1253
1254 /// CMD8:
1255 const fn hs_send_ext_csd(arg: u32) -> Cmd {
1256 Cmd::new(8, arg, Response::Short)
1257 }
1258
1259 /// CMD9:
1260 const fn send_csd(rca: u32) -> Cmd {
1261 Cmd::new(9, rca, Response::Long)
1262 }
1263
1264 /// CMD12:
1265 //const fn stop_transmission() -> Cmd {
1266 // Cmd::new(12, 0, Response::Short)
1267 //}
1268
1269 /// CMD13: Ask card to send status register
1270 /// ACMD13: SD Status
1271 const fn card_status(rca: u32) -> Cmd {
1272 Cmd::new(13, rca, Response::Short)
1273 }
1274
1275 /// CMD16:
1276 const fn set_block_length(blocklen: u32) -> Cmd {
1277 Cmd::new(16, blocklen, Response::Short)
1278 }
1279
1280 /// CMD17: Block Read
1281 const fn read_single_block(addr: u32) -> Cmd {
1282 Cmd::new(17, addr, Response::Short)
1283 }
1284
1285 /// CMD18: Multiple Block Read
1286 //const fn read_multiple_blocks(addr: u32) -> Cmd {
1287 // Cmd::new(18, addr, Response::Short)
1288 //}
1289
1290 /// CMD24: Block Write
1291 const fn write_single_block(addr: u32) -> Cmd {
1292 Cmd::new(24, addr, Response::Short)
1293 }
1294
1295 const fn app_op_cmd(arg: u32) -> Cmd {
1296 Cmd::new(41, arg, Response::Short)
1297 }
1298
1299 const fn cmd51() -> Cmd {
1300 Cmd::new(51, 0, Response::Short)
1301 }
1302
1303 /// App Command. Indicates that next command will be a app command
1304 const fn app_cmd(rca: u32) -> Cmd {
1305 Cmd::new(55, rca, Response::Short)
1306 }
1307}
1308
1309//////////////////////////////////////////////////////
1310
1311pub(crate) mod sealed {
1312 use super::*;
1313
1314 pub trait Instance {
1315 type Interrupt: Interrupt;
1316
1317 fn inner() -> SdmmcInner;
1318 fn state() -> &'static AtomicWaker;
1319 }
1320
1321 pub trait Pins<T: Instance> {}
1322}
1323
1324pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
1325pin_trait!(CkPin, Instance);
1326pin_trait!(CmdPin, Instance);
1327pin_trait!(D0Pin, Instance);
1328pin_trait!(D1Pin, Instance);
1329pin_trait!(D2Pin, Instance);
1330pin_trait!(D3Pin, Instance);
1331pin_trait!(D4Pin, Instance);
1332pin_trait!(D5Pin, Instance);
1333pin_trait!(D6Pin, Instance);
1334pin_trait!(D7Pin, Instance);
1335
1336cfg_if::cfg_if! {
1337 if #[cfg(sdmmc_v1)] {
1338 dma_trait!(SdmmcDma, Instance);
1339 } else if #[cfg(sdmmc_v2)] {
1340 // SDMMCv2 uses internal DMA
1341 pub trait SdmmcDma<T: Instance> {}
1342 impl<T: Instance> SdmmcDma<T> for NoDma {}
1343 }
1344}
1345
1346pub trait Pins<T: Instance>: sealed::Pins<T> + 'static {
1347 const BUSWIDTH: BusWidth;
1348
1349 fn configure(&mut self);
1350 fn deconfigure(&mut self);
1351}
1352
1353impl<T, CLK, CMD, D0, D1, D2, D3> sealed::Pins<T> for (CLK, CMD, D0, D1, D2, D3)
1354where
1355 T: Instance,
1356 CLK: CkPin<T>,
1357 CMD: CmdPin<T>,
1358 D0: D0Pin<T>,
1359 D1: D1Pin<T>,
1360 D2: D2Pin<T>,
1361 D3: D3Pin<T>,
1362{
1363}
1364
1365impl<T, CLK, CMD, D0> sealed::Pins<T> for (CLK, CMD, D0)
1366where
1367 T: Instance,
1368 CLK: CkPin<T>,
1369 CMD: CmdPin<T>,
1370 D0: D0Pin<T>,
1371{
1372}
1373
1374impl<T, CLK, CMD, D0, D1, D2, D3> Pins<T> for (CLK, CMD, D0, D1, D2, D3)
1375where
1376 T: Instance,
1377 CLK: CkPin<T>,
1378 CMD: CmdPin<T>,
1379 D0: D0Pin<T>,
1380 D1: D1Pin<T>,
1381 D2: D2Pin<T>,
1382 D3: D3Pin<T>,
1383{
1384 const BUSWIDTH: BusWidth = BusWidth::Four;
1385
1386 fn configure(&mut self) {
1387 let (clk_pin, cmd_pin, d0_pin, d1_pin, d2_pin, d3_pin) = self;
1388
1389 critical_section::with(|_| unsafe {
1390 clk_pin.set_as_af_pull(clk_pin.af_num(), AFType::OutputPushPull, Pull::None);
1391 cmd_pin.set_as_af_pull(cmd_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1392 d0_pin.set_as_af_pull(d0_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1393 d1_pin.set_as_af_pull(d1_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1394 d2_pin.set_as_af_pull(d2_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1395 d3_pin.set_as_af_pull(d3_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1396
1397 clk_pin.set_speed(Speed::VeryHigh);
1398 cmd_pin.set_speed(Speed::VeryHigh);
1399 d0_pin.set_speed(Speed::VeryHigh);
1400 d1_pin.set_speed(Speed::VeryHigh);
1401 d2_pin.set_speed(Speed::VeryHigh);
1402 d3_pin.set_speed(Speed::VeryHigh);
1403 });
1404 }
1405
1406 fn deconfigure(&mut self) {
1407 let (clk_pin, cmd_pin, d0_pin, d1_pin, d2_pin, d3_pin) = self;
1408
1409 critical_section::with(|_| unsafe {
1410 clk_pin.set_as_disconnected();
1411 cmd_pin.set_as_disconnected();
1412 d0_pin.set_as_disconnected();
1413 d1_pin.set_as_disconnected();
1414 d2_pin.set_as_disconnected();
1415 d3_pin.set_as_disconnected();
1416 });
1417 }
1418}
1419
1420impl<T, CLK, CMD, D0> Pins<T> for (CLK, CMD, D0)
1421where
1422 T: Instance,
1423 CLK: CkPin<T>,
1424 CMD: CmdPin<T>,
1425 D0: D0Pin<T>,
1426{
1427 const BUSWIDTH: BusWidth = BusWidth::One;
1428
1429 fn configure(&mut self) {
1430 let (clk_pin, cmd_pin, d0_pin) = self;
1431
1432 critical_section::with(|_| unsafe {
1433 clk_pin.set_as_af_pull(clk_pin.af_num(), AFType::OutputPushPull, Pull::None);
1434 cmd_pin.set_as_af_pull(cmd_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1435 d0_pin.set_as_af_pull(d0_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1436
1437 clk_pin.set_speed(Speed::VeryHigh);
1438 cmd_pin.set_speed(Speed::VeryHigh);
1439 d0_pin.set_speed(Speed::VeryHigh);
1440 });
1441 }
1442
1443 fn deconfigure(&mut self) {
1444 let (clk_pin, cmd_pin, d0_pin) = self;
1445
1446 critical_section::with(|_| unsafe {
1447 clk_pin.set_as_disconnected();
1448 cmd_pin.set_as_disconnected();
1449 d0_pin.set_as_disconnected();
1450 });
1451 }
1452}
1453
1454foreach_peripheral!(
1455 (sdmmc, $inst:ident) => {
1456 impl sealed::Instance for peripherals::$inst {
1457 type Interrupt = crate::interrupt::$inst;
1458
1459 fn inner() -> SdmmcInner {
1460 const INNER: SdmmcInner = SdmmcInner(crate::pac::$inst);
1461 INNER
1462 }
1463
1464 fn state() -> &'static ::embassy::waitqueue::AtomicWaker {
1465 static WAKER: ::embassy::waitqueue::AtomicWaker = ::embassy::waitqueue::AtomicWaker::new();
1466 &WAKER
1467 }
1468 }
1469
1470 impl Instance for peripherals::$inst {}
1471 };
1472);
1473
1474#[cfg(feature = "sdmmc-rs")]
1475mod sdmmc_rs {
1476 use super::*;
1477 use core::future::Future;
1478 use embedded_sdmmc::{Block, BlockCount, BlockDevice, BlockIdx};
1479
1480 impl<'d, T: Instance, P: Pins<T>> BlockDevice for Sdmmc<'d, T, P> {
1481 type Error = Error;
1482 type ReadFuture<'a>
1483 where
1484 Self: 'a,
1485 = impl Future<Output = Result<(), Self::Error>> + 'a;
1486 type WriteFuture<'a>
1487 where
1488 Self: 'a,
1489 = impl Future<Output = Result<(), Self::Error>> + 'a;
1490
1491 fn read<'a>(
1492 &'a mut self,
1493 blocks: &'a mut [Block],
1494 start_block_idx: BlockIdx,
1495 _reason: &str,
1496 ) -> Self::ReadFuture<'a> {
1497 async move {
1498 let card_capacity = self.card()?.card_type;
1499 let inner = T::inner();
1500 let state = T::state();
1501 let mut address = start_block_idx.0;
1502
1503 for block in blocks.iter_mut() {
1504 let block: &mut [u8; 512] = &mut block.contents;
1505
1506 // NOTE(unsafe) Block uses align(4)
1507 let buf = unsafe { &mut *(block as *mut [u8; 512] as *mut [u32; 128]) };
1508 inner
1509 .read_block(
1510 address,
1511 buf,
1512 card_capacity,
1513 state,
1514 self.config.data_transfer_timeout,
1515 )
1516 .await?;
1517 address += 1;
1518 }
1519 Ok(())
1520 }
1521 }
1522
1523 fn write<'a>(
1524 &'a mut self,
1525 blocks: &'a [Block],
1526 start_block_idx: BlockIdx,
1527 ) -> Self::WriteFuture<'a> {
1528 async move {
1529 let card = self.card.as_mut().ok_or(Error::NoCard)?;
1530 let inner = T::inner();
1531 let state = T::state();
1532 let mut address = start_block_idx.0;
1533
1534 for block in blocks.iter() {
1535 let block: &[u8; 512] = &block.contents;
1536
1537 // NOTE(unsafe) DataBlock uses align 4
1538 let buf = unsafe { &*(block as *const [u8; 512] as *const [u32; 128]) };
1539 inner
1540 .write_block(address, buf, card, state, self.config.data_transfer_timeout)
1541 .await?;
1542 address += 1;
1543 }
1544 Ok(())
1545 }
1546 }
1547
1548 fn num_blocks(&self) -> Result<BlockCount, Self::Error> {
1549 let card = self.card()?;
1550 let count = card.csd.block_count();
1551 Ok(BlockCount(count))
1552 }
1553 }
1554}
diff --git a/embassy-stm32/src/sdmmc/v1.rs b/embassy-stm32/src/sdmmc/v1.rs
deleted file mode 100644
index 8b1378917..000000000
--- a/embassy-stm32/src/sdmmc/v1.rs
+++ /dev/null
@@ -1 +0,0 @@
1
diff --git a/embassy-stm32/src/sdmmc/v2.rs b/embassy-stm32/src/sdmmc/v2.rs
deleted file mode 100644
index cb8fa5544..000000000
--- a/embassy-stm32/src/sdmmc/v2.rs
+++ /dev/null
@@ -1,1374 +0,0 @@
1#![macro_use]
2
3use core::default::Default;
4use core::marker::PhantomData;
5use core::task::Poll;
6
7use embassy::interrupt::InterruptExt;
8use embassy::util::Unborrow;
9use embassy::waitqueue::AtomicWaker;
10use embassy_hal_common::drop::OnDrop;
11use embassy_hal_common::unborrow;
12use futures::future::poll_fn;
13use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR};
14
15use crate::gpio::sealed::AFType;
16use crate::gpio::{Pull, Speed};
17use crate::interrupt::Interrupt;
18use crate::pac::sdmmc::Sdmmc as RegBlock;
19use crate::peripherals;
20use crate::time::Hertz;
21
22/// The signalling scheme used on the SDMMC bus
23#[non_exhaustive]
24#[derive(Debug, Copy, Clone, PartialEq, Eq)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub enum Signalling {
27 SDR12,
28 SDR25,
29 SDR50,
30 SDR104,
31 DDR50,
32}
33
34impl Default for Signalling {
35 fn default() -> Self {
36 Signalling::SDR12
37 }
38}
39
40#[repr(align(4))]
41pub struct DataBlock([u8; 512]);
42
43/// Errors
44#[non_exhaustive]
45#[derive(Debug, Copy, Clone)]
46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47pub enum Error {
48 Timeout,
49 SoftwareTimeout,
50 UnsupportedCardVersion,
51 UnsupportedCardType,
52 Crc,
53 DataCrcFail,
54 RxOverFlow,
55 NoCard,
56 BadClock,
57 SignalingSwitchFailed,
58 PeripheralBusy,
59}
60
61/// A SD command
62struct Cmd {
63 cmd: u8,
64 arg: u32,
65 resp: Response,
66}
67
68#[derive(Clone, Copy, Debug, Default)]
69/// SD Card
70pub struct Card {
71 /// The type of this card
72 pub card_type: CardCapacity,
73 /// Operation Conditions Register
74 pub ocr: OCR,
75 /// Relative Card Address
76 pub rca: u32,
77 /// Card ID
78 pub cid: CID,
79 /// Card Specific Data
80 pub csd: CSD,
81 /// SD CARD Configuration Register
82 pub scr: SCR,
83 /// SD Status
84 pub status: SDStatus,
85}
86impl Card {
87 /// Size in bytes
88 pub fn size(&self) -> u64 {
89 // SDHC / SDXC / SDUC
90 u64::from(self.csd.block_count()) * 512
91 }
92}
93
94/// Indicates transfer direction
95enum Dir {
96 CardToHost,
97 HostToCard,
98}
99
100#[repr(u8)]
101enum PowerCtrl {
102 Off = 0b00,
103 On = 0b11,
104}
105
106#[repr(u32)]
107#[allow(dead_code)]
108#[allow(non_camel_case_types)]
109enum CmdAppOper {
110 VOLTAGE_WINDOW_SD = 0x8010_0000,
111 HIGH_CAPACITY = 0x4000_0000,
112 SDMMC_STD_CAPACITY = 0x0000_0000,
113 SDMMC_CHECK_PATTERN = 0x0000_01AA,
114 SD_SWITCH_1_8V_CAPACITY = 0x0100_0000,
115}
116
117#[derive(Eq, PartialEq, Copy, Clone)]
118enum Response {
119 None = 0,
120 Short = 1,
121 Long = 3,
122}
123
124/// Calculate clock divisor. Returns a SDMMC_CK less than or equal to
125/// `sdmmc_ck` in Hertz.
126///
127/// Returns `(clk_div, clk_f)`, where `clk_div` is the divisor register
128/// value and `clk_f` is the resulting new clock frequency.
129fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(u16, Hertz), Error> {
130 match (ker_ck.0 + sdmmc_ck - 1) / sdmmc_ck {
131 0 | 1 => Ok((0, ker_ck)),
132 x @ 2..=2046 => {
133 let clk_div = ((x + 1) / 2) as u16;
134 let clk = Hertz(ker_ck.0 / (clk_div as u32 * 2));
135
136 Ok((clk_div, clk))
137 }
138 _ => Err(Error::BadClock),
139 }
140}
141
142/// SDMMC configuration
143///
144/// You should probably change the default clock values to match your configuration
145///
146/// Default values:
147/// hclk = 400_000_000 Hz
148/// kernel_clk: 100_000_000 Hz
149/// data_transfer_timeout: 5_000_000
150#[non_exhaustive]
151pub struct Config {
152 /// AHB clock
153 pub hclk: Hertz,
154 /// SDMMC kernel clock
155 pub kernel_clk: Hertz,
156 /// The timeout to be set for data transfers, in card bus clock periods
157 pub data_transfer_timeout: u32,
158}
159
160impl Default for Config {
161 fn default() -> Self {
162 Self {
163 hclk: Hertz(400_000_000),
164 kernel_clk: Hertz(100_000_000),
165 data_transfer_timeout: 5_000_000,
166 }
167 }
168}
169
170/// Sdmmc device
171pub struct Sdmmc<'d, T: Instance, P: Pins<T>> {
172 sdmmc: PhantomData<&'d mut T>,
173 pins: P,
174 irq: T::Interrupt,
175 config: Config,
176 /// Current clock to card
177 clock: Hertz,
178 /// Current signalling scheme to card
179 signalling: Signalling,
180 /// Card
181 card: Option<Card>,
182}
183
184impl<'d, T: Instance, P: Pins<T>> Sdmmc<'d, T, P> {
185 /// # Safety
186 ///
187 /// Futures that borrow this type can't be leaked
188 #[inline(always)]
189 pub unsafe fn new(
190 _peripheral: impl Unborrow<Target = T> + 'd,
191 pins: impl Unborrow<Target = P> + 'd,
192 irq: impl Unborrow<Target = T::Interrupt> + 'd,
193 config: Config,
194 ) -> Self {
195 unborrow!(irq, pins);
196 pins.configure();
197
198 let inner = T::inner();
199 let clock = inner.new_inner(config.kernel_clk);
200
201 irq.set_handler(Self::on_interrupt);
202 irq.unpend();
203 irq.enable();
204
205 Self {
206 sdmmc: PhantomData,
207 pins,
208 irq,
209 config,
210 clock,
211 signalling: Default::default(),
212 card: None,
213 }
214 }
215
216 #[inline(always)]
217 pub async fn init_card(&mut self, freq: impl Into<Hertz>) -> Result<(), Error> {
218 let inner = T::inner();
219 let freq = freq.into();
220
221 inner
222 .init_card(
223 freq,
224 P::BUSWIDTH,
225 &mut self.card,
226 &mut self.signalling,
227 self.config.hclk,
228 self.config.kernel_clk,
229 &mut self.clock,
230 T::state(),
231 self.config.data_transfer_timeout,
232 )
233 .await
234 }
235
236 #[inline(always)]
237 pub async fn read_block(
238 &mut self,
239 block_idx: u32,
240 buffer: &mut DataBlock,
241 ) -> Result<(), Error> {
242 let card_capacity = self.card()?.card_type;
243 let inner = T::inner();
244 let state = T::state();
245
246 // NOTE(unsafe) DataBlock uses align 4
247 let buf = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) };
248 inner
249 .read_block(
250 block_idx,
251 buf,
252 card_capacity,
253 state,
254 self.config.data_transfer_timeout,
255 )
256 .await
257 }
258
259 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> {
260 let card = self.card.as_mut().ok_or(Error::NoCard)?;
261 let inner = T::inner();
262 let state = T::state();
263
264 // NOTE(unsafe) DataBlock uses align 4
265 let buf = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) };
266 inner
267 .write_block(
268 block_idx,
269 buf,
270 card,
271 state,
272 self.config.data_transfer_timeout,
273 )
274 .await
275 }
276
277 /// Get a reference to the initialized card
278 ///
279 /// # Errors
280 ///
281 /// Returns Error::NoCard if [`init_card`](#method.init_card)
282 /// has not previously succeeded
283 #[inline(always)]
284 pub fn card(&self) -> Result<&Card, Error> {
285 self.card.as_ref().ok_or(Error::NoCard)
286 }
287
288 #[inline(always)]
289 fn on_interrupt(_: *mut ()) {
290 let regs = T::inner();
291 let state = T::state();
292
293 regs.data_interrupts(false);
294 state.wake();
295 }
296}
297
298impl<'d, T: Instance, P: Pins<T>> Drop for Sdmmc<'d, T, P> {
299 fn drop(&mut self) {
300 self.irq.disable();
301 let inner = T::inner();
302 unsafe { inner.on_drop() };
303 self.pins.deconfigure();
304 }
305}
306
307pub struct SdmmcInner(pub(crate) RegBlock);
308
309impl SdmmcInner {
310 /// # Safety
311 ///
312 /// Access to `regs` registers should be exclusive
313 unsafe fn new_inner(&self, kernel_clk: Hertz) -> Hertz {
314 let regs = self.0;
315
316 // While the SD/SDIO card or eMMC is in identification mode,
317 // the SDMMC_CK frequency must be less than 400 kHz.
318 let (clkdiv, clock) = unwrap!(clk_div(kernel_clk, 400_000));
319
320 regs.clkcr().write(|w| {
321 w.set_widbus(0);
322 w.set_clkdiv(clkdiv);
323 w.set_pwrsav(false);
324 w.set_negedge(false);
325 w.set_hwfc_en(true);
326 });
327
328 // Power off, writen 00: Clock to the card is stopped;
329 // D[7:0], CMD, and CK are driven high.
330 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8));
331
332 clock
333 }
334
335 /// Initializes card (if present) and sets the bus at the
336 /// specified frequency.
337 #[allow(clippy::too_many_arguments)]
338 async fn init_card(
339 &self,
340 freq: Hertz,
341 bus_width: BusWidth,
342 old_card: &mut Option<Card>,
343 signalling: &mut Signalling,
344 hclk: Hertz,
345 ker_ck: Hertz,
346 clock: &mut Hertz,
347 waker_reg: &AtomicWaker,
348 data_transfer_timeout: u32,
349 ) -> Result<(), Error> {
350 let regs = self.0;
351
352 // NOTE(unsafe) We have exclusive access to the peripheral
353 unsafe {
354 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
355 self.cmd(Cmd::idle(), false)?;
356
357 // Check if cards supports CMD8 (with pattern)
358 self.cmd(Cmd::hs_send_ext_csd(0x1AA), false)?;
359 let r1 = regs.respr(0).read().cardstatus1();
360
361 let mut card = if r1 == 0x1AA {
362 // Card echoed back the pattern. Must be at least v2
363 Card::default()
364 } else {
365 return Err(Error::UnsupportedCardVersion);
366 };
367
368 let ocr = loop {
369 // Signal that next command is a app command
370 self.cmd(Cmd::app_cmd(0), false)?; // CMD55
371
372 let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32
373 | CmdAppOper::HIGH_CAPACITY as u32
374 | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32;
375
376 // Initialize card
377 match self.cmd(Cmd::app_op_cmd(arg), false) {
378 // ACMD41
379 Ok(_) => (),
380 Err(Error::Crc) => (),
381 Err(err) => return Err(err),
382 }
383 let ocr: OCR = regs.respr(0).read().cardstatus1().into();
384 if !ocr.is_busy() {
385 // Power up done
386 break ocr;
387 }
388 };
389
390 if ocr.high_capacity() {
391 // Card is SDHC or SDXC or SDUC
392 card.card_type = CardCapacity::SDHC;
393 } else {
394 card.card_type = CardCapacity::SDSC;
395 }
396 card.ocr = ocr;
397
398 self.cmd(Cmd::all_send_cid(), false)?; // CMD2
399 let cid0 = regs.respr(0).read().cardstatus1() as u128;
400 let cid1 = regs.respr(1).read().cardstatus1() as u128;
401 let cid2 = regs.respr(2).read().cardstatus1() as u128;
402 let cid3 = regs.respr(3).read().cardstatus1() as u128;
403 let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
404 card.cid = cid.into();
405
406 self.cmd(Cmd::send_rel_addr(), false)?;
407 card.rca = regs.respr(0).read().cardstatus1() >> 16;
408
409 self.cmd(Cmd::send_csd(card.rca << 16), false)?;
410 let csd0 = regs.respr(0).read().cardstatus1() as u128;
411 let csd1 = regs.respr(1).read().cardstatus1() as u128;
412 let csd2 = regs.respr(2).read().cardstatus1() as u128;
413 let csd3 = regs.respr(3).read().cardstatus1() as u128;
414 let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
415 card.csd = csd.into();
416
417 self.select_card(Some(&card))?;
418 self.get_scr(&mut card, waker_reg, data_transfer_timeout)
419 .await?;
420
421 // Set bus width
422 let (width, acmd_arg) = match bus_width {
423 BusWidth::Eight => unimplemented!(),
424 BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2),
425 _ => (BusWidth::One, 0),
426 };
427 self.cmd(Cmd::app_cmd(card.rca << 16), false)?;
428 self.cmd(Cmd::cmd6(acmd_arg), false)?;
429
430 // CPSMACT and DPSMACT must be 0 to set WIDBUS
431 self.wait_idle();
432
433 regs.clkcr().modify(|w| {
434 w.set_widbus(match width {
435 BusWidth::One => 0,
436 BusWidth::Four => 1,
437 BusWidth::Eight => 2,
438 _ => panic!("Invalid Bus Width"),
439 })
440 });
441
442 // Set Clock
443 if freq.0 <= 25_000_000 {
444 // Final clock frequency
445 self.clkcr_set_clkdiv(freq.0, width, hclk, ker_ck, clock)?;
446 } else {
447 // Switch to max clock for SDR12
448 self.clkcr_set_clkdiv(25_000_000, width, hclk, ker_ck, clock)?;
449 }
450
451 // Read status
452 self.read_sd_status(&mut card, waker_reg, data_transfer_timeout)
453 .await?;
454
455 if freq.0 > 25_000_000 {
456 // Switch to SDR25
457 *signalling = self
458 .switch_signalling_mode(Signalling::SDR25, waker_reg, data_transfer_timeout)
459 .await?;
460
461 if *signalling == Signalling::SDR25 {
462 // Set final clock frequency
463 self.clkcr_set_clkdiv(freq.0, width, hclk, ker_ck, clock)?;
464
465 if self.read_status(&card)?.state() != CurrentState::Transfer {
466 return Err(Error::SignalingSwitchFailed);
467 }
468 }
469 }
470 // Read status after signalling change
471 self.read_sd_status(&mut card, waker_reg, data_transfer_timeout)
472 .await?;
473 old_card.replace(card);
474 }
475
476 Ok(())
477 }
478
479 async fn read_block(
480 &self,
481 block_idx: u32,
482 buffer: &mut [u32; 128],
483 capacity: CardCapacity,
484 waker_reg: &AtomicWaker,
485 data_transfer_timeout: u32,
486 ) -> Result<(), Error> {
487 // Always read 1 block of 512 bytes
488 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
489 let address = match capacity {
490 CardCapacity::SDSC => block_idx * 512,
491 _ => block_idx,
492 };
493 self.cmd(Cmd::set_block_length(512), false)?; // CMD16
494
495 let regs = self.0;
496 let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
497
498 let buf_addr = buffer as *mut [u32; 128] as u32;
499 unsafe {
500 self.prepare_datapath_transfer(
501 buf_addr,
502 512,
503 9,
504 Dir::CardToHost,
505 data_transfer_timeout,
506 );
507 self.data_interrupts(true);
508 }
509 self.cmd(Cmd::read_single_block(address), true)?;
510
511 let res = poll_fn(|cx| {
512 waker_reg.register(cx.waker());
513 let status = unsafe { regs.star().read() };
514
515 if status.dcrcfail() {
516 return Poll::Ready(Err(Error::Crc));
517 } else if status.dtimeout() {
518 return Poll::Ready(Err(Error::Timeout));
519 } else if status.dataend() {
520 return Poll::Ready(Ok(()));
521 }
522 Poll::Pending
523 })
524 .await;
525 self.clear_interrupt_flags();
526
527 if res.is_ok() {
528 on_drop.defuse();
529 unsafe {
530 regs.idmactrlr().modify(|w| w.set_idmaen(false));
531 }
532 }
533 res
534 }
535
536 async fn write_block(
537 &self,
538 block_idx: u32,
539 buffer: &[u32; 128],
540 card: &mut Card,
541 waker_reg: &AtomicWaker,
542 data_transfer_timeout: u32,
543 ) -> Result<(), Error> {
544 // Always read 1 block of 512 bytes
545 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
546 let address = match card.card_type {
547 CardCapacity::SDSC => block_idx * 512,
548 _ => block_idx,
549 };
550 self.cmd(Cmd::set_block_length(512), false)?; // CMD16
551
552 let regs = self.0;
553 let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
554
555 let buf_addr = buffer as *const [u32; 128] as u32;
556 unsafe {
557 self.prepare_datapath_transfer(
558 buf_addr,
559 512,
560 9,
561 Dir::HostToCard,
562 data_transfer_timeout,
563 );
564 self.data_interrupts(true);
565 }
566 self.cmd(Cmd::write_single_block(address), true)?;
567
568 let res = poll_fn(|cx| {
569 waker_reg.register(cx.waker());
570 let status = unsafe { regs.star().read() };
571
572 if status.dcrcfail() {
573 return Poll::Ready(Err(Error::Crc));
574 } else if status.dtimeout() {
575 return Poll::Ready(Err(Error::Timeout));
576 } else if status.dataend() {
577 return Poll::Ready(Ok(()));
578 }
579 Poll::Pending
580 })
581 .await;
582 self.clear_interrupt_flags();
583
584 match res {
585 Ok(_) => {
586 on_drop.defuse();
587 unsafe {
588 regs.idmactrlr().modify(|w| w.set_idmaen(false));
589 }
590 // TODO: Make this configurable
591 let mut timeout: u32 = 0x00FF_FFFF;
592
593 // Try to read card status (ACMD13)
594 while timeout > 0 {
595 match self
596 .read_sd_status(card, waker_reg, data_transfer_timeout)
597 .await
598 {
599 Ok(_) => return Ok(()),
600 Err(Error::Timeout) => (), // Try again
601 Err(e) => return Err(e),
602 }
603 timeout -= 1;
604 }
605 Err(Error::SoftwareTimeout)
606 }
607 Err(e) => Err(e),
608 }
609 }
610
611 /// Get the current SDMMC bus clock
612 //pub fn clock(&self) -> Hertz {
613 // self.clock
614 //}
615
616 /// Wait idle on DOSNACT and CPSMACT
617 #[inline(always)]
618 fn wait_idle(&self) {
619 let regs = self.0;
620
621 // NOTE(unsafe) Atomic read with no side-effects
622 unsafe {
623 while {
624 let status = regs.star().read();
625 status.dpsmact() || status.cpsmact()
626 } {}
627 }
628 }
629
630 /// # Safety
631 ///
632 /// `buffer_addr` must be valid for the whole transfer and word aligned
633 unsafe fn prepare_datapath_transfer(
634 &self,
635 buffer_addr: u32,
636 length_bytes: u32,
637 block_size: u8,
638 direction: Dir,
639 data_transfer_timeout: u32,
640 ) {
641 assert!(block_size <= 14, "Block size up to 2^14 bytes");
642 let regs = self.0;
643
644 let dtdir = match direction {
645 Dir::CardToHost => true,
646 Dir::HostToCard => false,
647 };
648
649 // Command AND Data state machines must be idle
650 self.wait_idle();
651 self.clear_interrupt_flags();
652
653 // NOTE(unsafe) We have exclusive access to the regisers
654
655 regs.dtimer()
656 .write(|w| w.set_datatime(data_transfer_timeout));
657 regs.dlenr().write(|w| w.set_datalength(length_bytes));
658
659 regs.idmabase0r().write(|w| w.set_idmabase0(buffer_addr));
660 regs.idmactrlr().modify(|w| w.set_idmaen(true));
661 regs.dctrl().modify(|w| {
662 w.set_dblocksize(block_size);
663 w.set_dtdir(dtdir);
664 });
665 }
666
667 /// Sets the CLKDIV field in CLKCR. Updates clock field in self
668 fn clkcr_set_clkdiv(
669 &self,
670 freq: u32,
671 width: BusWidth,
672 hclk: Hertz,
673 ker_ck: Hertz,
674 clock: &mut Hertz,
675 ) -> Result<(), Error> {
676 let regs = self.0;
677
678 let (clkdiv, new_clock) = clk_div(ker_ck, freq)?;
679 // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7
680 // Section 55.5.8
681 let sdmmc_bus_bandwidth = new_clock.0 * (width as u32);
682 assert!(hclk.0 > 3 * sdmmc_bus_bandwidth / 32);
683 *clock = new_clock;
684
685 // NOTE(unsafe) We have exclusive access to the regblock
686 unsafe {
687 // CPSMACT and DPSMACT must be 0 to set CLKDIV
688 self.wait_idle();
689 regs.clkcr().modify(|w| w.set_clkdiv(clkdiv));
690 }
691
692 Ok(())
693 }
694
695 /// Switch mode using CMD6.
696 ///
697 /// Attempt to set a new signalling mode. The selected
698 /// signalling mode is returned. Expects the current clock
699 /// frequency to be > 12.5MHz.
700 async fn switch_signalling_mode(
701 &self,
702 signalling: Signalling,
703 waker_reg: &AtomicWaker,
704 data_transfer_timeout: u32,
705 ) -> Result<Signalling, Error> {
706 // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not
707 // necessary"
708
709 let set_function = 0x8000_0000
710 | match signalling {
711 // See PLSS v7_10 Table 4-11
712 Signalling::DDR50 => 0xFF_FF04,
713 Signalling::SDR104 => 0xFF_1F03,
714 Signalling::SDR50 => 0xFF_1F02,
715 Signalling::SDR25 => 0xFF_FF01,
716 Signalling::SDR12 => 0xFF_FF00,
717 };
718
719 let mut status = [0u32; 16];
720 let status_addr = &mut status as *mut [u32; 16] as u32;
721
722 // Arm `OnDrop` after the buffer, so it will be dropped first
723 let regs = self.0;
724 let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
725
726 unsafe {
727 self.prepare_datapath_transfer(
728 status_addr,
729 64,
730 6,
731 Dir::CardToHost,
732 data_transfer_timeout,
733 );
734 self.data_interrupts(true);
735 }
736 self.cmd(Cmd::cmd6(set_function), true)?; // CMD6
737
738 let res = poll_fn(|cx| {
739 waker_reg.register(cx.waker());
740 let status = unsafe { regs.star().read() };
741
742 if status.dcrcfail() {
743 return Poll::Ready(Err(Error::Crc));
744 } else if status.dtimeout() {
745 return Poll::Ready(Err(Error::Timeout));
746 } else if status.dataend() {
747 return Poll::Ready(Ok(()));
748 }
749 Poll::Pending
750 })
751 .await;
752 self.clear_interrupt_flags();
753
754 // Host is allowed to use the new functions at least 8
755 // clocks after the end of the switch command
756 // transaction. We know the current clock period is < 80ns,
757 // so a total delay of 640ns is required here
758 for _ in 0..300 {
759 cortex_m::asm::nop();
760 }
761
762 match res {
763 Ok(_) => {
764 on_drop.defuse();
765 unsafe {
766 regs.idmactrlr().modify(|w| w.set_idmaen(false));
767 }
768 // Function Selection of Function Group 1
769 let selection = (u32::from_be(status[4]) >> 24) & 0xF;
770
771 match selection {
772 0 => Ok(Signalling::SDR12),
773 1 => Ok(Signalling::SDR25),
774 2 => Ok(Signalling::SDR50),
775 3 => Ok(Signalling::SDR104),
776 4 => Ok(Signalling::DDR50),
777 _ => Err(Error::UnsupportedCardType),
778 }
779 }
780 Err(e) => Err(e),
781 }
782 }
783
784 /// Query the card status (CMD13, returns R1)
785 ///
786 fn read_status(&self, card: &Card) -> Result<CardStatus, Error> {
787 let regs = self.0;
788 let rca = card.rca;
789
790 self.cmd(Cmd::card_status(rca << 16), false)?; // CMD13
791
792 // NOTE(unsafe) Atomic read with no side-effects
793 let r1 = unsafe { regs.respr(0).read().cardstatus1() };
794 Ok(r1.into())
795 }
796
797 /// Reads the SD Status (ACMD13)
798 async fn read_sd_status(
799 &self,
800 card: &mut Card,
801 waker_reg: &AtomicWaker,
802 data_transfer_timeout: u32,
803 ) -> Result<(), Error> {
804 let rca = card.rca;
805 self.cmd(Cmd::set_block_length(64), false)?; // CMD16
806 self.cmd(Cmd::app_cmd(rca << 16), false)?; // APP
807
808 let mut status = [0u32; 16];
809 let status_addr = &mut status as *mut [u32; 16] as u32;
810
811 // Arm `OnDrop` after the buffer, so it will be dropped first
812 let regs = self.0;
813 let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
814
815 unsafe {
816 self.prepare_datapath_transfer(
817 status_addr,
818 64,
819 6,
820 Dir::CardToHost,
821 data_transfer_timeout,
822 );
823 self.data_interrupts(true);
824 }
825 self.cmd(Cmd::card_status(0), true)?;
826
827 let res = poll_fn(|cx| {
828 waker_reg.register(cx.waker());
829 let status = unsafe { regs.star().read() };
830
831 if status.dcrcfail() {
832 return Poll::Ready(Err(Error::Crc));
833 } else if status.dtimeout() {
834 return Poll::Ready(Err(Error::Timeout));
835 } else if status.dataend() {
836 return Poll::Ready(Ok(()));
837 }
838 Poll::Pending
839 })
840 .await;
841 self.clear_interrupt_flags();
842
843 if res.is_ok() {
844 on_drop.defuse();
845 unsafe {
846 regs.idmactrlr().modify(|w| w.set_idmaen(false));
847 }
848 for byte in status.iter_mut() {
849 *byte = u32::from_be(*byte);
850 }
851 card.status = status.into();
852 }
853 res
854 }
855
856 /// Select one card and place it into the _Tranfer State_
857 ///
858 /// If `None` is specifed for `card`, all cards are put back into
859 /// _Stand-by State_
860 fn select_card(&self, card: Option<&Card>) -> Result<(), Error> {
861 // Determine Relative Card Address (RCA) of given card
862 let rca = card.map(|c| c.rca << 16).unwrap_or(0);
863
864 let r = self.cmd(Cmd::sel_desel_card(rca), false);
865 match (r, rca) {
866 (Err(Error::Timeout), 0) => Ok(()),
867 _ => r,
868 }
869 }
870
871 /// Clear flags in interrupt clear register
872 #[inline(always)]
873 fn clear_interrupt_flags(&self) {
874 let regs = self.0;
875 // NOTE(unsafe) Atomic write
876 unsafe {
877 regs.icr().write(|w| {
878 w.set_ccrcfailc(true);
879 w.set_dcrcfailc(true);
880 w.set_ctimeoutc(true);
881 w.set_dtimeoutc(true);
882 w.set_txunderrc(true);
883 w.set_rxoverrc(true);
884 w.set_cmdrendc(true);
885 w.set_cmdsentc(true);
886 w.set_dataendc(true);
887 w.set_dholdc(true);
888 w.set_dbckendc(true);
889 w.set_dabortc(true);
890 w.set_busyd0endc(true);
891 w.set_sdioitc(true);
892 w.set_ackfailc(true);
893 w.set_acktimeoutc(true);
894 w.set_vswendc(true);
895 w.set_ckstopc(true);
896 w.set_idmatec(true);
897 w.set_idmabtcc(true);
898 });
899 }
900 }
901
902 /// Enables the interrupts for data transfer
903 #[inline(always)]
904 fn data_interrupts(&self, enable: bool) {
905 let regs = self.0;
906 // NOTE(unsafe) Atomic write
907 unsafe {
908 regs.maskr().write(|w| {
909 w.set_dcrcfailie(enable);
910 w.set_dtimeoutie(enable);
911 w.set_dataendie(enable);
912 w.set_dabortie(enable);
913 });
914 }
915 }
916
917 async fn get_scr(
918 &self,
919 card: &mut Card,
920 waker_reg: &AtomicWaker,
921 data_transfer_timeout: u32,
922 ) -> Result<(), Error> {
923 // Read the the 64-bit SCR register
924 self.cmd(Cmd::set_block_length(8), false)?; // CMD16
925 self.cmd(Cmd::app_cmd(card.rca << 16), false)?;
926
927 let mut scr = [0u32; 2];
928 let scr_addr = &mut scr as *mut u32 as u32;
929
930 // Arm `OnDrop` after the buffer, so it will be dropped first
931 let regs = self.0;
932 let on_drop = OnDrop::new(move || unsafe { self.on_drop() });
933
934 unsafe {
935 self.prepare_datapath_transfer(scr_addr, 8, 3, Dir::CardToHost, data_transfer_timeout);
936 self.data_interrupts(true);
937 }
938 self.cmd(Cmd::cmd51(), true)?;
939
940 let res = poll_fn(|cx| {
941 waker_reg.register(cx.waker());
942 let status = unsafe { regs.star().read() };
943
944 if status.dcrcfail() {
945 return Poll::Ready(Err(Error::Crc));
946 } else if status.dtimeout() {
947 return Poll::Ready(Err(Error::Timeout));
948 } else if status.dataend() {
949 return Poll::Ready(Ok(()));
950 }
951 Poll::Pending
952 })
953 .await;
954 self.clear_interrupt_flags();
955
956 if res.is_ok() {
957 on_drop.defuse();
958
959 unsafe {
960 regs.idmactrlr().modify(|w| w.set_idmaen(false));
961 let scr_bytes = &*(&scr as *const [u32; 2] as *const [u8; 8]);
962 card.scr = SCR(u64::from_be_bytes(*scr_bytes));
963 }
964 }
965 res
966 }
967
968 /// Send command to card
969 fn cmd(&self, cmd: Cmd, data: bool) -> Result<(), Error> {
970 let regs = self.0;
971
972 self.clear_interrupt_flags();
973 // NOTE(safety) Atomic operations
974 unsafe {
975 // CP state machine must be idle
976 while regs.star().read().cpsmact() {}
977
978 // Command arg
979 regs.argr().write(|w| w.set_cmdarg(cmd.arg));
980
981 // Special mode in CP State Machine
982 // CMD12: Stop Transmission
983 let cpsm_stop_transmission = cmd.cmd == 12;
984
985 // Command index and start CP State Machine
986 regs.cmdr().write(|w| {
987 w.set_waitint(false);
988 w.set_waitresp(cmd.resp as u8);
989 w.set_cmdstop(cpsm_stop_transmission);
990 w.set_cmdindex(cmd.cmd);
991 w.set_cpsmen(true);
992 w.set_cmdtrans(data);
993 });
994
995 let mut status;
996 if cmd.resp == Response::None {
997 // Wait for CMDSENT or a timeout
998 while {
999 status = regs.star().read();
1000 !(status.ctimeout() || status.cmdsent())
1001 } {}
1002 } else {
1003 // Wait for CMDREND or CCRCFAIL or a timeout
1004 while {
1005 status = regs.star().read();
1006 !(status.ctimeout() || status.cmdrend() || status.ccrcfail())
1007 } {}
1008 }
1009
1010 if status.ctimeout() {
1011 return Err(Error::Timeout);
1012 } else if status.ccrcfail() {
1013 return Err(Error::Crc);
1014 }
1015 Ok(())
1016 }
1017 }
1018
1019 /// # Safety
1020 ///
1021 /// Ensure that `regs` has exclusive access to the regblocks
1022 unsafe fn on_drop(&self) {
1023 let regs = self.0;
1024 if regs.star().read().dpsmact() {
1025 self.clear_interrupt_flags();
1026 // Send abort
1027 // CP state machine must be idle
1028 while regs.star().read().cpsmact() {}
1029
1030 // Command arg
1031 regs.argr().write(|w| w.set_cmdarg(0));
1032
1033 // Command index and start CP State Machine
1034 regs.cmdr().write(|w| {
1035 w.set_waitint(false);
1036 w.set_waitresp(Response::Short as u8);
1037 w.set_cmdstop(true);
1038 w.set_cmdindex(12);
1039 w.set_cpsmen(true);
1040 w.set_cmdtrans(false);
1041 });
1042
1043 // Wait for the abort
1044 while regs.star().read().dpsmact() {}
1045 }
1046 self.data_interrupts(false);
1047 self.clear_interrupt_flags();
1048 regs.idmactrlr().modify(|w| w.set_idmaen(false));
1049 }
1050}
1051
1052/// SD card Commands
1053impl Cmd {
1054 const fn new(cmd: u8, arg: u32, resp: Response) -> Cmd {
1055 Cmd { cmd, arg, resp }
1056 }
1057
1058 /// CMD0: Idle
1059 const fn idle() -> Cmd {
1060 Cmd::new(0, 0, Response::None)
1061 }
1062
1063 /// CMD2: Send CID
1064 const fn all_send_cid() -> Cmd {
1065 Cmd::new(2, 0, Response::Long)
1066 }
1067
1068 /// CMD3: Send Relative Address
1069 const fn send_rel_addr() -> Cmd {
1070 Cmd::new(3, 0, Response::Short)
1071 }
1072
1073 /// CMD6: Switch Function Command
1074 /// ACMD6: Bus Width
1075 const fn cmd6(arg: u32) -> Cmd {
1076 Cmd::new(6, arg, Response::Short)
1077 }
1078
1079 /// CMD7: Select one card and put it into the _Tranfer State_
1080 const fn sel_desel_card(rca: u32) -> Cmd {
1081 Cmd::new(7, rca, Response::Short)
1082 }
1083
1084 /// CMD8:
1085 const fn hs_send_ext_csd(arg: u32) -> Cmd {
1086 Cmd::new(8, arg, Response::Short)
1087 }
1088
1089 /// CMD9:
1090 const fn send_csd(rca: u32) -> Cmd {
1091 Cmd::new(9, rca, Response::Long)
1092 }
1093
1094 /// CMD12:
1095 //const fn stop_transmission() -> Cmd {
1096 // Cmd::new(12, 0, Response::Short)
1097 //}
1098
1099 /// CMD13: Ask card to send status register
1100 /// ACMD13: SD Status
1101 const fn card_status(rca: u32) -> Cmd {
1102 Cmd::new(13, rca, Response::Short)
1103 }
1104
1105 /// CMD16:
1106 const fn set_block_length(blocklen: u32) -> Cmd {
1107 Cmd::new(16, blocklen, Response::Short)
1108 }
1109
1110 /// CMD17: Block Read
1111 const fn read_single_block(addr: u32) -> Cmd {
1112 Cmd::new(17, addr, Response::Short)
1113 }
1114
1115 /// CMD18: Multiple Block Read
1116 //const fn read_multiple_blocks(addr: u32) -> Cmd {
1117 // Cmd::new(18, addr, Response::Short)
1118 //}
1119
1120 /// CMD24: Block Write
1121 const fn write_single_block(addr: u32) -> Cmd {
1122 Cmd::new(24, addr, Response::Short)
1123 }
1124
1125 const fn app_op_cmd(arg: u32) -> Cmd {
1126 Cmd::new(41, arg, Response::Short)
1127 }
1128
1129 const fn cmd51() -> Cmd {
1130 Cmd::new(51, 0, Response::Short)
1131 }
1132
1133 /// App Command. Indicates that next command will be a app command
1134 const fn app_cmd(rca: u32) -> Cmd {
1135 Cmd::new(55, rca, Response::Short)
1136 }
1137}
1138
1139//////////////////////////////////////////////////////
1140
1141pub(crate) mod sealed {
1142 use super::*;
1143
1144 pub trait Instance {
1145 type Interrupt: Interrupt;
1146
1147 fn inner() -> SdmmcInner;
1148 fn state() -> &'static AtomicWaker;
1149 }
1150
1151 pub trait Pins<T: Instance> {}
1152}
1153
1154pub trait Instance: sealed::Instance + 'static {}
1155pin_trait!(CkPin, Instance);
1156pin_trait!(CmdPin, Instance);
1157pin_trait!(D0Pin, Instance);
1158pin_trait!(D1Pin, Instance);
1159pin_trait!(D2Pin, Instance);
1160pin_trait!(D3Pin, Instance);
1161pin_trait!(D4Pin, Instance);
1162pin_trait!(D5Pin, Instance);
1163pin_trait!(D6Pin, Instance);
1164pin_trait!(D7Pin, Instance);
1165
1166pub trait Pins<T: Instance>: sealed::Pins<T> + 'static {
1167 const BUSWIDTH: BusWidth;
1168
1169 fn configure(&mut self);
1170 fn deconfigure(&mut self);
1171}
1172
1173impl<T, CLK, CMD, D0, D1, D2, D3> sealed::Pins<T> for (CLK, CMD, D0, D1, D2, D3)
1174where
1175 T: Instance,
1176 CLK: CkPin<T>,
1177 CMD: CmdPin<T>,
1178 D0: D0Pin<T>,
1179 D1: D1Pin<T>,
1180 D2: D2Pin<T>,
1181 D3: D3Pin<T>,
1182{
1183}
1184
1185impl<T, CLK, CMD, D0> sealed::Pins<T> for (CLK, CMD, D0)
1186where
1187 T: Instance,
1188 CLK: CkPin<T>,
1189 CMD: CmdPin<T>,
1190 D0: D0Pin<T>,
1191{
1192}
1193
1194impl<T, CLK, CMD, D0, D1, D2, D3> Pins<T> for (CLK, CMD, D0, D1, D2, D3)
1195where
1196 T: Instance,
1197 CLK: CkPin<T>,
1198 CMD: CmdPin<T>,
1199 D0: D0Pin<T>,
1200 D1: D1Pin<T>,
1201 D2: D2Pin<T>,
1202 D3: D3Pin<T>,
1203{
1204 const BUSWIDTH: BusWidth = BusWidth::Four;
1205
1206 fn configure(&mut self) {
1207 let (clk_pin, cmd_pin, d0_pin, d1_pin, d2_pin, d3_pin) = self;
1208
1209 critical_section::with(|_| unsafe {
1210 clk_pin.set_as_af_pull(clk_pin.af_num(), AFType::OutputPushPull, Pull::None);
1211 cmd_pin.set_as_af_pull(cmd_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1212 d0_pin.set_as_af_pull(d0_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1213 d1_pin.set_as_af_pull(d1_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1214 d2_pin.set_as_af_pull(d2_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1215 d3_pin.set_as_af_pull(d3_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1216
1217 clk_pin.set_speed(Speed::VeryHigh);
1218 cmd_pin.set_speed(Speed::VeryHigh);
1219 d0_pin.set_speed(Speed::VeryHigh);
1220 d1_pin.set_speed(Speed::VeryHigh);
1221 d2_pin.set_speed(Speed::VeryHigh);
1222 d3_pin.set_speed(Speed::VeryHigh);
1223 });
1224 }
1225
1226 fn deconfigure(&mut self) {
1227 let (clk_pin, cmd_pin, d0_pin, d1_pin, d2_pin, d3_pin) = self;
1228
1229 critical_section::with(|_| unsafe {
1230 clk_pin.set_as_disconnected();
1231 cmd_pin.set_as_disconnected();
1232 d0_pin.set_as_disconnected();
1233 d1_pin.set_as_disconnected();
1234 d2_pin.set_as_disconnected();
1235 d3_pin.set_as_disconnected();
1236 });
1237 }
1238}
1239
1240impl<T, CLK, CMD, D0> Pins<T> for (CLK, CMD, D0)
1241where
1242 T: Instance,
1243 CLK: CkPin<T>,
1244 CMD: CmdPin<T>,
1245 D0: D0Pin<T>,
1246{
1247 const BUSWIDTH: BusWidth = BusWidth::One;
1248
1249 fn configure(&mut self) {
1250 let (clk_pin, cmd_pin, d0_pin) = self;
1251
1252 critical_section::with(|_| unsafe {
1253 clk_pin.set_as_af_pull(clk_pin.af_num(), AFType::OutputPushPull, Pull::None);
1254 cmd_pin.set_as_af_pull(cmd_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1255 d0_pin.set_as_af_pull(d0_pin.af_num(), AFType::OutputPushPull, Pull::Up);
1256
1257 clk_pin.set_speed(Speed::VeryHigh);
1258 cmd_pin.set_speed(Speed::VeryHigh);
1259 d0_pin.set_speed(Speed::VeryHigh);
1260 });
1261 }
1262
1263 fn deconfigure(&mut self) {
1264 let (clk_pin, cmd_pin, d0_pin) = self;
1265
1266 critical_section::with(|_| unsafe {
1267 clk_pin.set_as_disconnected();
1268 cmd_pin.set_as_disconnected();
1269 d0_pin.set_as_disconnected();
1270 });
1271 }
1272}
1273
1274foreach_peripheral!(
1275 (sdmmc, $inst:ident) => {
1276 impl sealed::Instance for peripherals::$inst {
1277 type Interrupt = crate::interrupt::$inst;
1278
1279 fn inner() -> SdmmcInner {
1280 const INNER: SdmmcInner = SdmmcInner(crate::pac::$inst);
1281 INNER
1282 }
1283
1284 fn state() -> &'static ::embassy::waitqueue::AtomicWaker {
1285 static WAKER: ::embassy::waitqueue::AtomicWaker = ::embassy::waitqueue::AtomicWaker::new();
1286 &WAKER
1287 }
1288 }
1289
1290 impl Instance for peripherals::$inst {}
1291 };
1292);
1293
1294#[cfg(feature = "sdmmc-rs")]
1295mod sdmmc_rs {
1296 use super::*;
1297 use core::future::Future;
1298 use embedded_sdmmc::{Block, BlockCount, BlockDevice, BlockIdx};
1299
1300 impl<'d, T: Instance, P: Pins<T>> BlockDevice for Sdmmc<'d, T, P> {
1301 type Error = Error;
1302 type ReadFuture<'a>
1303 where
1304 Self: 'a,
1305 = impl Future<Output = Result<(), Self::Error>> + 'a;
1306 type WriteFuture<'a>
1307 where
1308 Self: 'a,
1309 = impl Future<Output = Result<(), Self::Error>> + 'a;
1310
1311 fn read<'a>(
1312 &'a mut self,
1313 blocks: &'a mut [Block],
1314 start_block_idx: BlockIdx,
1315 _reason: &str,
1316 ) -> Self::ReadFuture<'a> {
1317 async move {
1318 let card_capacity = self.card()?.card_type;
1319 let inner = T::inner();
1320 let state = T::state();
1321 let mut address = start_block_idx.0;
1322
1323 for block in blocks.iter_mut() {
1324 let block: &mut [u8; 512] = &mut block.contents;
1325
1326 // NOTE(unsafe) Block uses align(4)
1327 let buf = unsafe { &mut *(block as *mut [u8; 512] as *mut [u32; 128]) };
1328 inner
1329 .read_block(
1330 address,
1331 buf,
1332 card_capacity,
1333 state,
1334 self.config.data_transfer_timeout,
1335 )
1336 .await?;
1337 address += 1;
1338 }
1339 Ok(())
1340 }
1341 }
1342
1343 fn write<'a>(
1344 &'a mut self,
1345 blocks: &'a [Block],
1346 start_block_idx: BlockIdx,
1347 ) -> Self::WriteFuture<'a> {
1348 async move {
1349 let card = self.card.as_mut().ok_or(Error::NoCard)?;
1350 let inner = T::inner();
1351 let state = T::state();
1352 let mut address = start_block_idx.0;
1353
1354 for block in blocks.iter() {
1355 let block: &[u8; 512] = &block.contents;
1356
1357 // NOTE(unsafe) DataBlock uses align 4
1358 let buf = unsafe { &*(block as *const [u8; 512] as *const [u32; 128]) };
1359 inner
1360 .write_block(address, buf, card, state, self.config.data_transfer_timeout)
1361 .await?;
1362 address += 1;
1363 }
1364 Ok(())
1365 }
1366 }
1367
1368 fn num_blocks(&self) -> Result<BlockCount, Self::Error> {
1369 let card = self.card()?;
1370 let count = card.csd.block_count();
1371 Ok(BlockCount(count))
1372 }
1373 }
1374}
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 764a967ca..ea0c496db 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -424,7 +424,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
424 424
425 let tx_request = self.txdma.request(); 425 let tx_request = self.txdma.request();
426 let tx_dst = T::REGS.tx_ptr(); 426 let tx_dst = T::REGS.tx_ptr();
427 unsafe { self.txdma.start_write(tx_request, data, tx_dst) } 427 unsafe {
428 self.txdma
429 .start_write(tx_request, data, tx_dst, Default::default())
430 }
428 let tx_f = Transfer::new(&mut self.txdma); 431 let tx_f = Transfer::new(&mut self.txdma);
429 432
430 unsafe { 433 unsafe {
@@ -470,7 +473,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
470 473
471 let rx_request = self.rxdma.request(); 474 let rx_request = self.rxdma.request();
472 let rx_src = T::REGS.rx_ptr(); 475 let rx_src = T::REGS.rx_ptr();
473 unsafe { self.rxdma.start_read(rx_request, rx_src, data) }; 476 unsafe {
477 self.rxdma
478 .start_read(rx_request, rx_src, data, Default::default())
479 };
474 let rx_f = Transfer::new(&mut self.rxdma); 480 let rx_f = Transfer::new(&mut self.rxdma);
475 481
476 let tx_request = self.txdma.request(); 482 let tx_request = self.txdma.request();
@@ -532,12 +538,18 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
532 538
533 let rx_request = self.rxdma.request(); 539 let rx_request = self.rxdma.request();
534 let rx_src = T::REGS.rx_ptr(); 540 let rx_src = T::REGS.rx_ptr();
535 unsafe { self.rxdma.start_read(rx_request, rx_src, read) }; 541 unsafe {
542 self.rxdma
543 .start_read(rx_request, rx_src, read, Default::default())
544 };
536 let rx_f = Transfer::new(&mut self.rxdma); 545 let rx_f = Transfer::new(&mut self.rxdma);
537 546
538 let tx_request = self.txdma.request(); 547 let tx_request = self.txdma.request();
539 let tx_dst = T::REGS.tx_ptr(); 548 let tx_dst = T::REGS.tx_ptr();
540 unsafe { self.txdma.start_write(tx_request, write, tx_dst) } 549 unsafe {
550 self.txdma
551 .start_write(tx_request, write, tx_dst, Default::default())
552 }
541 let tx_f = Transfer::new(&mut self.txdma); 553 let tx_f = Transfer::new(&mut self.txdma);
542 554
543 unsafe { 555 unsafe {
diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs
new file mode 100644
index 000000000..2ef367397
--- /dev/null
+++ b/examples/stm32f4/src/bin/sdmmc.rs
@@ -0,0 +1,44 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5#[path = "../example_common.rs"]
6mod example_common;
7
8use embassy::executor::Spawner;
9use embassy_stm32::sdmmc::Sdmmc;
10use embassy_stm32::time::U32Ext;
11use embassy_stm32::{interrupt, Config, Peripherals};
12use example_common::*;
13
14fn config() -> Config {
15 let mut config = Config::default();
16 config.rcc.sys_ck = Some(48.mhz().into());
17 config
18}
19
20#[embassy::main(config = "config()")]
21async fn main(_spawner: Spawner, p: Peripherals) -> ! {
22 info!("Hello World!");
23
24 let irq = interrupt::take!(SDIO);
25
26 let mut sdmmc = Sdmmc::new(
27 p.SDIO,
28 (p.PC12, p.PD2, p.PC8, p.PC9, p.PC10, p.PC11),
29 irq,
30 Default::default(),
31 p.DMA2_CH3,
32 );
33
34 // Should print 400kHz for initialization
35 info!("Configured clock: {}", sdmmc.clock().0);
36
37 unwrap!(sdmmc.init_card(25.mhz()).await);
38
39 let card = unwrap!(sdmmc.card());
40
41 info!("Card: {:#?}", Debug2Format(card));
42
43 loop {}
44}
diff --git a/examples/stm32f7/src/bin/sdmmc.rs b/examples/stm32f7/src/bin/sdmmc.rs
new file mode 100644
index 000000000..57b913db9
--- /dev/null
+++ b/examples/stm32f7/src/bin/sdmmc.rs
@@ -0,0 +1,44 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5#[path = "../example_common.rs"]
6mod example_common;
7
8use embassy::executor::Spawner;
9use embassy_stm32::sdmmc::Sdmmc;
10use embassy_stm32::time::U32Ext;
11use embassy_stm32::{interrupt, Config, Peripherals};
12use example_common::*;
13
14fn config() -> Config {
15 let mut config = Config::default();
16 config.rcc.sys_ck = Some(200.mhz().into());
17 config
18}
19
20#[embassy::main(config = "config()")]
21async fn main(_spawner: Spawner, p: Peripherals) -> ! {
22 info!("Hello World!");
23
24 let irq = interrupt::take!(SDMMC1);
25
26 let mut sdmmc = Sdmmc::new(
27 p.SDMMC1,
28 (p.PC12, p.PD2, p.PC8, p.PC9, p.PC10, p.PC11),
29 irq,
30 Default::default(),
31 p.DMA2_CH3,
32 );
33
34 // Should print 400kHz for initialization
35 info!("Configured clock: {}", sdmmc.clock().0);
36
37 unwrap!(sdmmc.init_card(25.mhz()).await);
38
39 let card = unwrap!(sdmmc.card());
40
41 info!("Card: {:#?}", Debug2Format(card));
42
43 loop {}
44}
diff --git a/examples/stm32h7/src/bin/sdmmc.rs b/examples/stm32h7/src/bin/sdmmc.rs
new file mode 100644
index 000000000..19c4deed1
--- /dev/null
+++ b/examples/stm32h7/src/bin/sdmmc.rs
@@ -0,0 +1,43 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5#[path = "../example_common.rs"]
6mod example_common;
7
8use embassy::executor::Spawner;
9use embassy_stm32::sdmmc::Sdmmc;
10use embassy_stm32::time::U32Ext;
11use embassy_stm32::{interrupt, Config, Peripherals};
12use example_common::*;
13
14fn config() -> Config {
15 let mut config = Config::default();
16 config.rcc.sys_ck = Some(200.mhz().into());
17 config
18}
19
20#[embassy::main(config = "config()")]
21async fn main(_spawner: Spawner, p: Peripherals) -> ! {
22 info!("Hello World!");
23
24 let irq = interrupt::take!(SDMMC1);
25
26 let mut sdmmc = Sdmmc::new(
27 p.SDMMC1,
28 (p.PC12, p.PD2, p.PC8, p.PC9, p.PC10, p.PC11),
29 irq,
30 Default::default(),
31 );
32
33 // Should print 400kHz for initialization
34 info!("Configured clock: {}", sdmmc.clock().0);
35
36 unwrap!(sdmmc.init_card(25.mhz()).await);
37
38 let card = unwrap!(sdmmc.card());
39
40 info!("Card: {:#?}", Debug2Format(card));
41
42 loop {}
43}
diff --git a/stm32-data b/stm32-data
Subproject d3e8a2fe63eeb403102559f3f9917d9fcf27e1a Subproject 938770167164faa46970af4f6096ec7c8b19591