aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-12-19 16:18:24 +0100
committerDario Nieuwenhuis <[email protected]>2023-12-19 16:21:51 +0100
commit1ea87ec6e752dca60e13731863e11d0e0f5c0492 (patch)
treebc9a76e2ae6c97025404f67bde9c90a89f1751d9
parentc995732b0e08b3157aa8886da2e5ce4a36af6e93 (diff)
stm32: document hrtim, qspi, sdmmc, spi.
-rw-r--r--embassy-stm32/src/hrtim/mod.rs59
-rw-r--r--embassy-stm32/src/hrtim/traits.rs6
-rw-r--r--embassy-stm32/src/lib.rs24
-rw-r--r--embassy-stm32/src/qspi/enums.rs2
-rw-r--r--embassy-stm32/src/qspi/mod.rs11
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs39
-rw-r--r--embassy-stm32/src/spi/mod.rs46
-rw-r--r--embassy-stm32/src/time.rs3
8 files changed, 132 insertions, 58 deletions
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs
index 6539326b4..1e6626a58 100644
--- a/embassy-stm32/src/hrtim/mod.rs
+++ b/embassy-stm32/src/hrtim/mod.rs
@@ -15,38 +15,42 @@ use crate::rcc::get_freqs;
15use crate::time::Hertz; 15use crate::time::Hertz;
16use crate::Peripheral; 16use crate::Peripheral;
17 17
18pub enum Source { 18/// HRTIM burst controller instance.
19 Master,
20 ChA,
21 ChB,
22 ChC,
23 ChD,
24 ChE,
25 #[cfg(hrtim_v2)]
26 ChF,
27}
28
29pub struct BurstController<T: Instance> { 19pub struct BurstController<T: Instance> {
30 phantom: PhantomData<T>, 20 phantom: PhantomData<T>,
31} 21}
22
23/// HRTIM master instance.
32pub struct Master<T: Instance> { 24pub struct Master<T: Instance> {
33 phantom: PhantomData<T>, 25 phantom: PhantomData<T>,
34} 26}
27
28/// HRTIM channel A instance.
35pub struct ChA<T: Instance> { 29pub struct ChA<T: Instance> {
36 phantom: PhantomData<T>, 30 phantom: PhantomData<T>,
37} 31}
32
33/// HRTIM channel B instance.
38pub struct ChB<T: Instance> { 34pub struct ChB<T: Instance> {
39 phantom: PhantomData<T>, 35 phantom: PhantomData<T>,
40} 36}
37
38/// HRTIM channel C instance.
41pub struct ChC<T: Instance> { 39pub struct ChC<T: Instance> {
42 phantom: PhantomData<T>, 40 phantom: PhantomData<T>,
43} 41}
42
43/// HRTIM channel D instance.
44pub struct ChD<T: Instance> { 44pub struct ChD<T: Instance> {
45 phantom: PhantomData<T>, 45 phantom: PhantomData<T>,
46} 46}
47
48/// HRTIM channel E instance.
47pub struct ChE<T: Instance> { 49pub struct ChE<T: Instance> {
48 phantom: PhantomData<T>, 50 phantom: PhantomData<T>,
49} 51}
52
53/// HRTIM channel F instance.
50#[cfg(hrtim_v2)] 54#[cfg(hrtim_v2)]
51pub struct ChF<T: Instance> { 55pub struct ChF<T: Instance> {
52 phantom: PhantomData<T>, 56 phantom: PhantomData<T>,
@@ -60,13 +64,16 @@ mod sealed {
60 } 64 }
61} 65}
62 66
67/// Advanced channel instance trait.
63pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {} 68pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {}
64 69
70/// HRTIM PWM pin.
65pub struct PwmPin<'d, Perip, Channel> { 71pub struct PwmPin<'d, Perip, Channel> {
66 _pin: PeripheralRef<'d, AnyPin>, 72 _pin: PeripheralRef<'d, AnyPin>,
67 phantom: PhantomData<(Perip, Channel)>, 73 phantom: PhantomData<(Perip, Channel)>,
68} 74}
69 75
76/// HRTIM complementary PWM pin.
70pub struct ComplementaryPwmPin<'d, Perip, Channel> { 77pub struct ComplementaryPwmPin<'d, Perip, Channel> {
71 _pin: PeripheralRef<'d, AnyPin>, 78 _pin: PeripheralRef<'d, AnyPin>,
72 phantom: PhantomData<(Perip, Channel)>, 79 phantom: PhantomData<(Perip, Channel)>,
@@ -75,6 +82,7 @@ pub struct ComplementaryPwmPin<'d, Perip, Channel> {
75macro_rules! advanced_channel_impl { 82macro_rules! advanced_channel_impl {
76 ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { 83 ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => {
77 impl<'d, Perip: Instance> PwmPin<'d, Perip, $channel<Perip>> { 84 impl<'d, Perip: Instance> PwmPin<'d, Perip, $channel<Perip>> {
85 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
78 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self { 86 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self {
79 into_ref!(pin); 87 into_ref!(pin);
80 critical_section::with(|_| { 88 critical_section::with(|_| {
@@ -91,6 +99,7 @@ macro_rules! advanced_channel_impl {
91 } 99 }
92 100
93 impl<'d, Perip: Instance> ComplementaryPwmPin<'d, Perip, $channel<Perip>> { 101 impl<'d, Perip: Instance> ComplementaryPwmPin<'d, Perip, $channel<Perip>> {
102 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")]
94 pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self { 103 pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self {
95 into_ref!(pin); 104 into_ref!(pin);
96 critical_section::with(|_| { 105 critical_section::with(|_| {
@@ -126,18 +135,29 @@ advanced_channel_impl!(new_chf, ChF, 5, ChannelFPin, ChannelFComplementaryPin);
126/// Struct used to divide a high resolution timer into multiple channels 135/// Struct used to divide a high resolution timer into multiple channels
127pub struct AdvancedPwm<'d, T: Instance> { 136pub struct AdvancedPwm<'d, T: Instance> {
128 _inner: PeripheralRef<'d, T>, 137 _inner: PeripheralRef<'d, T>,
138 /// Master instance.
129 pub master: Master<T>, 139 pub master: Master<T>,
140 /// Burst controller.
130 pub burst_controller: BurstController<T>, 141 pub burst_controller: BurstController<T>,
142 /// Channel A.
131 pub ch_a: ChA<T>, 143 pub ch_a: ChA<T>,
144 /// Channel B.
132 pub ch_b: ChB<T>, 145 pub ch_b: ChB<T>,
146 /// Channel C.
133 pub ch_c: ChC<T>, 147 pub ch_c: ChC<T>,
148 /// Channel D.
134 pub ch_d: ChD<T>, 149 pub ch_d: ChD<T>,
150 /// Channel E.
135 pub ch_e: ChE<T>, 151 pub ch_e: ChE<T>,
152 /// Channel F.
136 #[cfg(hrtim_v2)] 153 #[cfg(hrtim_v2)]
137 pub ch_f: ChF<T>, 154 pub ch_f: ChF<T>,
138} 155}
139 156
140impl<'d, T: Instance> AdvancedPwm<'d, T> { 157impl<'d, T: Instance> AdvancedPwm<'d, T> {
158 /// Create a new HRTIM driver.
159 ///
160 /// This splits the HRTIM into its constituent parts, which you can then use individually.
141 pub fn new( 161 pub fn new(
142 tim: impl Peripheral<P = T> + 'd, 162 tim: impl Peripheral<P = T> + 'd,
143 _cha: Option<PwmPin<'d, T, ChA<T>>>, 163 _cha: Option<PwmPin<'d, T, ChA<T>>>,
@@ -200,13 +220,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> {
200 } 220 }
201} 221}
202 222
203impl<T: Instance> BurstController<T> { 223/// Fixed-frequency bridge converter driver.
204 pub fn set_source(&mut self, _source: Source) {
205 todo!("burst mode control registers not implemented")
206 }
207}
208
209/// Represents a fixed-frequency bridge converter
210/// 224///
211/// Our implementation of the bridge converter uses a single channel and three compare registers, 225/// Our implementation of the bridge converter uses a single channel and three compare registers,
212/// allowing implementation of a synchronous buck or boost converter in continuous or discontinuous 226/// allowing implementation of a synchronous buck or boost converter in continuous or discontinuous
@@ -225,6 +239,7 @@ pub struct BridgeConverter<T: Instance, C: AdvancedChannel<T>> {
225} 239}
226 240
227impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> { 241impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
242 /// Create a new HRTIM bridge converter driver.
228 pub fn new(_channel: C, frequency: Hertz) -> Self { 243 pub fn new(_channel: C, frequency: Hertz) -> Self {
229 use crate::pac::hrtim::vals::{Activeeffect, Inactiveeffect}; 244 use crate::pac::hrtim::vals::{Activeeffect, Inactiveeffect};
230 245
@@ -281,14 +296,17 @@ impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
281 } 296 }
282 } 297 }
283 298
299 /// Start HRTIM.
284 pub fn start(&mut self) { 300 pub fn start(&mut self) {
285 T::regs().mcr().modify(|w| w.set_tcen(C::raw(), true)); 301 T::regs().mcr().modify(|w| w.set_tcen(C::raw(), true));
286 } 302 }
287 303
304 /// Stop HRTIM.
288 pub fn stop(&mut self) { 305 pub fn stop(&mut self) {
289 T::regs().mcr().modify(|w| w.set_tcen(C::raw(), false)); 306 T::regs().mcr().modify(|w| w.set_tcen(C::raw(), false));
290 } 307 }
291 308
309 /// Enable burst mode.
292 pub fn enable_burst_mode(&mut self) { 310 pub fn enable_burst_mode(&mut self) {
293 T::regs().tim(C::raw()).outr().modify(|w| { 311 T::regs().tim(C::raw()).outr().modify(|w| {
294 // Enable Burst Mode 312 // Enable Burst Mode
@@ -301,6 +319,7 @@ impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
301 }) 319 })
302 } 320 }
303 321
322 /// Disable burst mode.
304 pub fn disable_burst_mode(&mut self) { 323 pub fn disable_burst_mode(&mut self) {
305 T::regs().tim(C::raw()).outr().modify(|w| { 324 T::regs().tim(C::raw()).outr().modify(|w| {
306 // Disable Burst Mode 325 // Disable Burst Mode
@@ -357,7 +376,7 @@ impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
357 } 376 }
358} 377}
359 378
360/// Represents a variable-frequency resonant converter 379/// Variable-frequency resonant converter driver.
361/// 380///
362/// This implementation of a resonsant converter is appropriate for a half or full bridge, 381/// This implementation of a resonsant converter is appropriate for a half or full bridge,
363/// but does not include secondary rectification, which is appropriate for applications 382/// but does not include secondary rectification, which is appropriate for applications
@@ -370,6 +389,7 @@ pub struct ResonantConverter<T: Instance, C: AdvancedChannel<T>> {
370} 389}
371 390
372impl<T: Instance, C: AdvancedChannel<T>> ResonantConverter<T, C> { 391impl<T: Instance, C: AdvancedChannel<T>> ResonantConverter<T, C> {
392 /// Create a new variable-frequency resonant converter driver.
373 pub fn new(_channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self { 393 pub fn new(_channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self {
374 T::set_channel_frequency(C::raw(), min_frequency); 394 T::set_channel_frequency(C::raw(), min_frequency);
375 395
@@ -408,6 +428,7 @@ impl<T: Instance, C: AdvancedChannel<T>> ResonantConverter<T, C> {
408 T::set_channel_dead_time(C::raw(), value); 428 T::set_channel_dead_time(C::raw(), value);
409 } 429 }
410 430
431 /// Set the timer period.
411 pub fn set_period(&mut self, period: u16) { 432 pub fn set_period(&mut self, period: u16) {
412 assert!(period < self.max_period); 433 assert!(period < self.max_period);
413 assert!(period > self.min_period); 434 assert!(period > self.min_period);
diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs
index 34a363a1f..cfd31c47c 100644
--- a/embassy-stm32/src/hrtim/traits.rs
+++ b/embassy-stm32/src/hrtim/traits.rs
@@ -125,7 +125,6 @@ pub(crate) mod sealed {
125 } 125 }
126 126
127 /// Set the dead time as a proportion of max_duty 127 /// Set the dead time as a proportion of max_duty
128
129 fn set_channel_dead_time(channel: usize, dead_time: u16) { 128 fn set_channel_dead_time(channel: usize, dead_time: u16) {
130 let regs = Self::regs(); 129 let regs = Self::regs();
131 130
@@ -148,13 +147,10 @@ pub(crate) mod sealed {
148 w.set_dtr(dt_val as u16); 147 w.set_dtr(dt_val as u16);
149 }); 148 });
150 } 149 }
151
152 // fn enable_outputs(enable: bool);
153 //
154 // fn enable_channel(&mut self, channel: usize, enable: bool);
155 } 150 }
156} 151}
157 152
153/// HRTIM instance trait.
158pub trait Instance: sealed::Instance + 'static {} 154pub trait Instance: sealed::Instance + 'static {}
159 155
160foreach_interrupt! { 156foreach_interrupt! {
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index fd691a732..5d9b4e6a0 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -149,33 +149,15 @@ use crate::interrupt::Priority;
149pub use crate::pac::NVIC_PRIO_BITS; 149pub use crate::pac::NVIC_PRIO_BITS;
150use crate::rcc::sealed::RccPeripheral; 150use crate::rcc::sealed::RccPeripheral;
151 151
152/// `embassy-stm32` global configuration.
153#[non_exhaustive] 152#[non_exhaustive]
154pub struct Config { 153pub struct Config {
155 /// RCC config.
156 pub rcc: rcc::Config, 154 pub rcc: rcc::Config,
157
158 /// Enable debug during sleep.
159 ///
160 /// May incrase power consumption. Defaults to true.
161 #[cfg(dbgmcu)] 155 #[cfg(dbgmcu)]
162 pub enable_debug_during_sleep: bool, 156 pub enable_debug_during_sleep: bool,
163
164 /// BDMA interrupt priority.
165 ///
166 /// Defaults to P0 (highest).
167 #[cfg(bdma)] 157 #[cfg(bdma)]
168 pub bdma_interrupt_priority: Priority, 158 pub bdma_interrupt_priority: Priority,
169
170 /// DMA interrupt priority.
171 ///
172 /// Defaults to P0 (highest).
173 #[cfg(dma)] 159 #[cfg(dma)]
174 pub dma_interrupt_priority: Priority, 160 pub dma_interrupt_priority: Priority,
175
176 /// GPDMA interrupt priority.
177 ///
178 /// Defaults to P0 (highest).
179 #[cfg(gpdma)] 161 #[cfg(gpdma)]
180 pub gpdma_interrupt_priority: Priority, 162 pub gpdma_interrupt_priority: Priority,
181} 163}
@@ -196,11 +178,7 @@ impl Default for Config {
196 } 178 }
197} 179}
198 180
199/// Initialize the `embassy-stm32` HAL with the provided configuration. 181/// Initialize embassy.
200///
201/// This returns the peripheral singletons that can be used for creating drivers.
202///
203/// This should only be called once at startup, otherwise it panics.
204pub fn init(config: Config) -> Peripherals { 182pub fn init(config: Config) -> Peripherals {
205 critical_section::with(|cs| { 183 critical_section::with(|cs| {
206 let p = Peripherals::take_with_cs(cs); 184 let p = Peripherals::take_with_cs(cs);
diff --git a/embassy-stm32/src/qspi/enums.rs b/embassy-stm32/src/qspi/enums.rs
index e9e7fd482..ecade9b1a 100644
--- a/embassy-stm32/src/qspi/enums.rs
+++ b/embassy-stm32/src/qspi/enums.rs
@@ -1,3 +1,5 @@
1//! Enums used in QSPI configuration.
2
1#[allow(dead_code)] 3#[allow(dead_code)]
2#[derive(Copy, Clone)] 4#[derive(Copy, Clone)]
3pub(crate) enum QspiMode { 5pub(crate) enum QspiMode {
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
index 9ea0a726c..8a709a89e 100644
--- a/embassy-stm32/src/qspi/mod.rs
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -14,6 +14,7 @@ use crate::pac::quadspi::Quadspi as Regs;
14use crate::rcc::RccPeripheral; 14use crate::rcc::RccPeripheral;
15use crate::{peripherals, Peripheral}; 15use crate::{peripherals, Peripheral};
16 16
17/// QSPI transfer configuration.
17pub struct TransferConfig { 18pub struct TransferConfig {
18 /// Instraction width (IMODE) 19 /// Instraction width (IMODE)
19 pub iwidth: QspiWidth, 20 pub iwidth: QspiWidth,
@@ -45,6 +46,7 @@ impl Default for TransferConfig {
45 } 46 }
46} 47}
47 48
49/// QSPI driver configuration.
48pub struct Config { 50pub struct Config {
49 /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen. 51 /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen.
50 /// If you need other value the whose predefined use `Other` variant. 52 /// If you need other value the whose predefined use `Other` variant.
@@ -71,6 +73,7 @@ impl Default for Config {
71 } 73 }
72} 74}
73 75
76/// QSPI driver.
74#[allow(dead_code)] 77#[allow(dead_code)]
75pub struct Qspi<'d, T: Instance, Dma> { 78pub struct Qspi<'d, T: Instance, Dma> {
76 _peri: PeripheralRef<'d, T>, 79 _peri: PeripheralRef<'d, T>,
@@ -85,6 +88,7 @@ pub struct Qspi<'d, T: Instance, Dma> {
85} 88}
86 89
87impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { 90impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
91 /// Create a new QSPI driver for bank 1.
88 pub fn new_bk1( 92 pub fn new_bk1(
89 peri: impl Peripheral<P = T> + 'd, 93 peri: impl Peripheral<P = T> + 'd,
90 d0: impl Peripheral<P = impl BK1D0Pin<T>> + 'd, 94 d0: impl Peripheral<P = impl BK1D0Pin<T>> + 'd,
@@ -125,6 +129,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
125 ) 129 )
126 } 130 }
127 131
132 /// Create a new QSPI driver for bank 2.
128 pub fn new_bk2( 133 pub fn new_bk2(
129 peri: impl Peripheral<P = T> + 'd, 134 peri: impl Peripheral<P = T> + 'd,
130 d0: impl Peripheral<P = impl BK2D0Pin<T>> + 'd, 135 d0: impl Peripheral<P = impl BK2D0Pin<T>> + 'd,
@@ -223,6 +228,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
223 } 228 }
224 } 229 }
225 230
231 /// Do a QSPI command.
226 pub fn command(&mut self, transaction: TransferConfig) { 232 pub fn command(&mut self, transaction: TransferConfig) {
227 #[cfg(not(stm32h7))] 233 #[cfg(not(stm32h7))]
228 T::REGS.cr().modify(|v| v.set_dmaen(false)); 234 T::REGS.cr().modify(|v| v.set_dmaen(false));
@@ -232,6 +238,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
232 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 238 T::REGS.fcr().modify(|v| v.set_ctcf(true));
233 } 239 }
234 240
241 /// Blocking read data.
235 pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { 242 pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
236 #[cfg(not(stm32h7))] 243 #[cfg(not(stm32h7))]
237 T::REGS.cr().modify(|v| v.set_dmaen(false)); 244 T::REGS.cr().modify(|v| v.set_dmaen(false));
@@ -256,6 +263,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
256 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 263 T::REGS.fcr().modify(|v| v.set_ctcf(true));
257 } 264 }
258 265
266 /// Blocking write data.
259 pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) { 267 pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
260 // STM32H7 does not have dmaen 268 // STM32H7 does not have dmaen
261 #[cfg(not(stm32h7))] 269 #[cfg(not(stm32h7))]
@@ -278,6 +286,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
278 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 286 T::REGS.fcr().modify(|v| v.set_ctcf(true));
279 } 287 }
280 288
289 /// Blocking read data, using DMA.
281 pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) 290 pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig)
282 where 291 where
283 Dma: QuadDma<T>, 292 Dma: QuadDma<T>,
@@ -310,6 +319,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
310 transfer.blocking_wait(); 319 transfer.blocking_wait();
311 } 320 }
312 321
322 /// Blocking write data, using DMA.
313 pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) 323 pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig)
314 where 324 where
315 Dma: QuadDma<T>, 325 Dma: QuadDma<T>,
@@ -379,6 +389,7 @@ pub(crate) mod sealed {
379 } 389 }
380} 390}
381 391
392/// QSPI instance trait.
382pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} 393pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
383 394
384pin_trait!(SckPin, Instance); 395pin_trait!(SckPin, Instance);
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index 6099b9f43..ab142053a 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -54,6 +54,7 @@ const SD_INIT_FREQ: Hertz = Hertz(400_000);
54 54
55/// The signalling scheme used on the SDMMC bus 55/// The signalling scheme used on the SDMMC bus
56#[non_exhaustive] 56#[non_exhaustive]
57#[allow(missing_docs)]
57#[derive(Debug, Copy, Clone, PartialEq, Eq)] 58#[derive(Debug, Copy, Clone, PartialEq, Eq)]
58#[cfg_attr(feature = "defmt", derive(defmt::Format))] 59#[cfg_attr(feature = "defmt", derive(defmt::Format))]
59pub enum Signalling { 60pub enum Signalling {
@@ -70,6 +71,9 @@ impl Default for Signalling {
70 } 71 }
71} 72}
72 73
74/// Aligned data block for SDMMC transfers.
75///
76/// This is a 512-byte array, aligned to 4 bytes to satisfy DMA requirements.
73#[repr(align(4))] 77#[repr(align(4))]
74#[derive(Debug, Clone, PartialEq, Eq)] 78#[derive(Debug, Clone, PartialEq, Eq)]
75#[cfg_attr(feature = "defmt", derive(defmt::Format))] 79#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -94,17 +98,23 @@ impl DerefMut for DataBlock {
94#[derive(Debug, Copy, Clone, PartialEq, Eq)] 98#[derive(Debug, Copy, Clone, PartialEq, Eq)]
95#[cfg_attr(feature = "defmt", derive(defmt::Format))] 99#[cfg_attr(feature = "defmt", derive(defmt::Format))]
96pub enum Error { 100pub enum Error {
101 /// Timeout reported by the hardware
97 Timeout, 102 Timeout,
103 /// Timeout reported by the software driver.
98 SoftwareTimeout, 104 SoftwareTimeout,
105 /// Unsupported card version.
99 UnsupportedCardVersion, 106 UnsupportedCardVersion,
107 /// Unsupported card type.
100 UnsupportedCardType, 108 UnsupportedCardType,
109 /// CRC error.
101 Crc, 110 Crc,
102 DataCrcFail, 111 /// No card inserted.
103 RxOverFlow,
104 NoCard, 112 NoCard,
113 /// Bad clock supplied to the SDMMC peripheral.
105 BadClock, 114 BadClock,
115 /// Signaling switch failed.
106 SignalingSwitchFailed, 116 SignalingSwitchFailed,
107 PeripheralBusy, 117 /// ST bit error.
108 #[cfg(sdmmc_v1)] 118 #[cfg(sdmmc_v1)]
109 StBitErr, 119 StBitErr,
110} 120}
@@ -363,6 +373,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
363 373
364#[cfg(sdmmc_v2)] 374#[cfg(sdmmc_v2)]
365impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { 375impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
376 /// Create a new SDMMC driver, with 1 data lane.
366 pub fn new_1bit( 377 pub fn new_1bit(
367 sdmmc: impl Peripheral<P = T> + 'd, 378 sdmmc: impl Peripheral<P = T> + 'd,
368 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 379 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -396,6 +407,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
396 ) 407 )
397 } 408 }
398 409
410 /// Create a new SDMMC driver, with 4 data lanes.
399 pub fn new_4bit( 411 pub fn new_4bit(
400 sdmmc: impl Peripheral<P = T> + 'd, 412 sdmmc: impl Peripheral<P = T> + 'd,
401 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 413 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -497,7 +509,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
497 } 509 }
498 510
499 /// Data transfer is in progress 511 /// Data transfer is in progress
500 #[inline(always)] 512 #[inline]
501 fn data_active() -> bool { 513 fn data_active() -> bool {
502 let regs = T::regs(); 514 let regs = T::regs();
503 515
@@ -509,7 +521,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
509 } 521 }
510 522
511 /// Coammand transfer is in progress 523 /// Coammand transfer is in progress
512 #[inline(always)] 524 #[inline]
513 fn cmd_active() -> bool { 525 fn cmd_active() -> bool {
514 let regs = T::regs(); 526 let regs = T::regs();
515 527
@@ -521,7 +533,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
521 } 533 }
522 534
523 /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) 535 /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2)
524 #[inline(always)] 536 #[inline]
525 fn wait_idle() { 537 fn wait_idle() {
526 while Self::data_active() || Self::cmd_active() {} 538 while Self::data_active() || Self::cmd_active() {}
527 } 539 }
@@ -837,7 +849,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
837 } 849 }
838 850
839 /// Clear flags in interrupt clear register 851 /// Clear flags in interrupt clear register
840 #[inline(always)] 852 #[inline]
841 fn clear_interrupt_flags() { 853 fn clear_interrupt_flags() {
842 let regs = T::regs(); 854 let regs = T::regs();
843 regs.icr().write(|w| { 855 regs.icr().write(|w| {
@@ -1152,7 +1164,8 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1152 Ok(()) 1164 Ok(())
1153 } 1165 }
1154 1166
1155 #[inline(always)] 1167 /// Read a data block.
1168 #[inline]
1156 pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { 1169 pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> {
1157 let card_capacity = self.card()?.card_type; 1170 let card_capacity = self.card()?.card_type;
1158 1171
@@ -1204,6 +1217,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1204 res 1217 res
1205 } 1218 }
1206 1219
1220 /// Write a data block.
1207 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { 1221 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> {
1208 let card = self.card.as_mut().ok_or(Error::NoCard)?; 1222 let card = self.card.as_mut().ok_or(Error::NoCard)?;
1209 1223
@@ -1283,7 +1297,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1283 /// 1297 ///
1284 /// Returns Error::NoCard if [`init_card`](#method.init_card) 1298 /// Returns Error::NoCard if [`init_card`](#method.init_card)
1285 /// has not previously succeeded 1299 /// has not previously succeeded
1286 #[inline(always)] 1300 #[inline]
1287 pub fn card(&self) -> Result<&Card, Error> { 1301 pub fn card(&self) -> Result<&Card, Error> {
1288 self.card.as_ref().ok_or(Error::NoCard) 1302 self.card.as_ref().ok_or(Error::NoCard)
1289 } 1303 }
@@ -1419,7 +1433,9 @@ pub(crate) mod sealed {
1419 pub trait Pins<T: Instance> {} 1433 pub trait Pins<T: Instance> {}
1420} 1434}
1421 1435
1436/// SDMMC instance trait.
1422pub trait Instance: sealed::Instance + RccPeripheral + 'static {} 1437pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
1438
1423pin_trait!(CkPin, Instance); 1439pin_trait!(CkPin, Instance);
1424pin_trait!(CmdPin, Instance); 1440pin_trait!(CmdPin, Instance);
1425pin_trait!(D0Pin, Instance); 1441pin_trait!(D0Pin, Instance);
@@ -1434,7 +1450,10 @@ pin_trait!(D7Pin, Instance);
1434#[cfg(sdmmc_v1)] 1450#[cfg(sdmmc_v1)]
1435dma_trait!(SdmmcDma, Instance); 1451dma_trait!(SdmmcDma, Instance);
1436 1452
1437// SDMMCv2 uses internal DMA 1453/// DMA instance trait.
1454///
1455/// This is only implemented for `NoDma`, since SDMMCv2 has DMA built-in, instead of
1456/// using ST's system-wide DMA peripheral.
1438#[cfg(sdmmc_v2)] 1457#[cfg(sdmmc_v2)]
1439pub trait SdmmcDma<T: Instance> {} 1458pub trait SdmmcDma<T: Instance> {}
1440#[cfg(sdmmc_v2)] 1459#[cfg(sdmmc_v2)]
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 5a1ad3e91..674a5d316 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -16,27 +16,38 @@ use crate::rcc::RccPeripheral;
16use crate::time::Hertz; 16use crate::time::Hertz;
17use crate::{peripherals, Peripheral}; 17use crate::{peripherals, Peripheral};
18 18
19/// SPI error.
19#[derive(Debug, PartialEq, Eq)] 20#[derive(Debug, PartialEq, Eq)]
20#[cfg_attr(feature = "defmt", derive(defmt::Format))] 21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21pub enum Error { 22pub enum Error {
23 /// Invalid framing.
22 Framing, 24 Framing,
25 /// CRC error (only if hardware CRC checking is enabled).
23 Crc, 26 Crc,
27 /// Mode fault
24 ModeFault, 28 ModeFault,
29 /// Overrun.
25 Overrun, 30 Overrun,
26} 31}
27 32
28// TODO move upwards in the tree 33/// SPI bit order
29#[derive(Copy, Clone)] 34#[derive(Copy, Clone)]
30pub enum BitOrder { 35pub enum BitOrder {
36 /// Least significant bit first.
31 LsbFirst, 37 LsbFirst,
38 /// Most significant bit first.
32 MsbFirst, 39 MsbFirst,
33} 40}
34 41
42/// SPI configuration.
35#[non_exhaustive] 43#[non_exhaustive]
36#[derive(Copy, Clone)] 44#[derive(Copy, Clone)]
37pub struct Config { 45pub struct Config {
46 /// SPI mode.
38 pub mode: Mode, 47 pub mode: Mode,
48 /// Bit order.
39 pub bit_order: BitOrder, 49 pub bit_order: BitOrder,
50 /// Clock frequency.
40 pub frequency: Hertz, 51 pub frequency: Hertz,
41} 52}
42 53
@@ -73,6 +84,7 @@ impl Config {
73 } 84 }
74} 85}
75 86
87/// SPI driver.
76pub struct Spi<'d, T: Instance, Tx, Rx> { 88pub struct Spi<'d, T: Instance, Tx, Rx> {
77 _peri: PeripheralRef<'d, T>, 89 _peri: PeripheralRef<'d, T>,
78 sck: Option<PeripheralRef<'d, AnyPin>>, 90 sck: Option<PeripheralRef<'d, AnyPin>>,
@@ -84,6 +96,7 @@ pub struct Spi<'d, T: Instance, Tx, Rx> {
84} 96}
85 97
86impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { 98impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
99 /// Create a new SPI driver.
87 pub fn new( 100 pub fn new(
88 peri: impl Peripheral<P = T> + 'd, 101 peri: impl Peripheral<P = T> + 'd,
89 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 102 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
@@ -118,6 +131,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
118 ) 131 )
119 } 132 }
120 133
134 /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI).
121 pub fn new_rxonly( 135 pub fn new_rxonly(
122 peri: impl Peripheral<P = T> + 'd, 136 peri: impl Peripheral<P = T> + 'd,
123 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 137 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
@@ -143,6 +157,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
143 ) 157 )
144 } 158 }
145 159
160 /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO).
146 pub fn new_txonly( 161 pub fn new_txonly(
147 peri: impl Peripheral<P = T> + 'd, 162 peri: impl Peripheral<P = T> + 'd,
148 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 163 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
@@ -168,6 +183,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
168 ) 183 )
169 } 184 }
170 185
186 /// Create a new SPI driver, in TX-only mode, without SCK pin.
187 ///
188 /// This can be useful for bit-banging non-SPI protocols.
171 pub fn new_txonly_nosck( 189 pub fn new_txonly_nosck(
172 peri: impl Peripheral<P = T> + 'd, 190 peri: impl Peripheral<P = T> + 'd,
173 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd, 191 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
@@ -355,6 +373,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
355 Ok(()) 373 Ok(())
356 } 374 }
357 375
376 /// Get current SPI configuration.
358 pub fn get_current_config(&self) -> Config { 377 pub fn get_current_config(&self) -> Config {
359 #[cfg(any(spi_v1, spi_f1, spi_v2))] 378 #[cfg(any(spi_v1, spi_f1, spi_v2))]
360 let cfg = T::REGS.cr1().read(); 379 let cfg = T::REGS.cr1().read();
@@ -444,6 +463,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
444 self.current_word_size = word_size; 463 self.current_word_size = word_size;
445 } 464 }
446 465
466 /// SPI write, using DMA.
447 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> 467 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error>
448 where 468 where
449 Tx: TxDma<T>, 469 Tx: TxDma<T>,
@@ -477,6 +497,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
477 Ok(()) 497 Ok(())
478 } 498 }
479 499
500 /// SPI read, using DMA.
480 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> 501 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error>
481 where 502 where
482 Tx: TxDma<T>, 503 Tx: TxDma<T>,
@@ -580,6 +601,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
580 Ok(()) 601 Ok(())
581 } 602 }
582 603
604 /// Bidirectional transfer, using DMA.
605 ///
606 /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`.
607 ///
608 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
609 /// If `write` is shorter it is padded with zero bytes.
583 pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> 610 pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error>
584 where 611 where
585 Tx: TxDma<T>, 612 Tx: TxDma<T>,
@@ -588,6 +615,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
588 self.transfer_inner(read, write).await 615 self.transfer_inner(read, write).await
589 } 616 }
590 617
618 /// In-place bidirectional transfer, using DMA.
619 ///
620 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
591 pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> 621 pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error>
592 where 622 where
593 Tx: TxDma<T>, 623 Tx: TxDma<T>,
@@ -596,6 +626,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
596 self.transfer_inner(data, data).await 626 self.transfer_inner(data, data).await
597 } 627 }
598 628
629 /// Blocking write.
599 pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { 630 pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
600 T::REGS.cr1().modify(|w| w.set_spe(true)); 631 T::REGS.cr1().modify(|w| w.set_spe(true));
601 flush_rx_fifo(T::REGS); 632 flush_rx_fifo(T::REGS);
@@ -606,6 +637,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
606 Ok(()) 637 Ok(())
607 } 638 }
608 639
640 /// Blocking read.
609 pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { 641 pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
610 T::REGS.cr1().modify(|w| w.set_spe(true)); 642 T::REGS.cr1().modify(|w| w.set_spe(true));
611 flush_rx_fifo(T::REGS); 643 flush_rx_fifo(T::REGS);
@@ -616,6 +648,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
616 Ok(()) 648 Ok(())
617 } 649 }
618 650
651 /// Blocking in-place bidirectional transfer.
652 ///
653 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
619 pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { 654 pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
620 T::REGS.cr1().modify(|w| w.set_spe(true)); 655 T::REGS.cr1().modify(|w| w.set_spe(true));
621 flush_rx_fifo(T::REGS); 656 flush_rx_fifo(T::REGS);
@@ -626,6 +661,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
626 Ok(()) 661 Ok(())
627 } 662 }
628 663
664 /// Blocking bidirectional transfer.
665 ///
666 /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`.
667 ///
668 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
669 /// If `write` is shorter it is padded with zero bytes.
629 pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { 670 pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
630 T::REGS.cr1().modify(|w| w.set_spe(true)); 671 T::REGS.cr1().modify(|w| w.set_spe(true));
631 flush_rx_fifo(T::REGS); 672 flush_rx_fifo(T::REGS);
@@ -946,6 +987,7 @@ pub(crate) mod sealed {
946 } 987 }
947} 988}
948 989
990/// Word sizes usable for SPI.
949pub trait Word: word::Word + sealed::Word {} 991pub trait Word: word::Word + sealed::Word {}
950 992
951macro_rules! impl_word { 993macro_rules! impl_word {
@@ -1025,7 +1067,9 @@ mod word_impl {
1025 impl_word!(u32, 32 - 1); 1067 impl_word!(u32, 32 - 1);
1026} 1068}
1027 1069
1070/// SPI instance trait.
1028pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} 1071pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
1072
1029pin_trait!(SckPin, Instance); 1073pin_trait!(SckPin, Instance);
1030pin_trait!(MosiPin, Instance); 1074pin_trait!(MosiPin, Instance);
1031pin_trait!(MisoPin, Instance); 1075pin_trait!(MisoPin, Instance);
diff --git a/embassy-stm32/src/time.rs b/embassy-stm32/src/time.rs
index a0bc33944..17690aefc 100644
--- a/embassy-stm32/src/time.rs
+++ b/embassy-stm32/src/time.rs
@@ -8,14 +8,17 @@ use core::ops::{Div, Mul};
8pub struct Hertz(pub u32); 8pub struct Hertz(pub u32);
9 9
10impl Hertz { 10impl Hertz {
11 /// Create a `Hertz` from the given hertz.
11 pub const fn hz(hertz: u32) -> Self { 12 pub const fn hz(hertz: u32) -> Self {
12 Self(hertz) 13 Self(hertz)
13 } 14 }
14 15
16 /// Create a `Hertz` from the given kilohertz.
15 pub const fn khz(kilohertz: u32) -> Self { 17 pub const fn khz(kilohertz: u32) -> Self {
16 Self(kilohertz * 1_000) 18 Self(kilohertz * 1_000)
17 } 19 }
18 20
21 /// Create a `Hertz` from the given megahertz.
19 pub const fn mhz(megahertz: u32) -> Self { 22 pub const fn mhz(megahertz: u32) -> Self {
20 Self(megahertz * 1_000_000) 23 Self(megahertz * 1_000_000)
21 } 24 }