diff options
| -rw-r--r-- | embassy-stm32/src/hrtim/mod.rs | 59 | ||||
| -rw-r--r-- | embassy-stm32/src/hrtim/traits.rs | 6 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 24 | ||||
| -rw-r--r-- | embassy-stm32/src/qspi/enums.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/qspi/mod.rs | 11 | ||||
| -rw-r--r-- | embassy-stm32/src/sdmmc/mod.rs | 39 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/mod.rs | 46 | ||||
| -rw-r--r-- | embassy-stm32/src/time.rs | 3 |
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; | |||
| 15 | use crate::time::Hertz; | 15 | use crate::time::Hertz; |
| 16 | use crate::Peripheral; | 16 | use crate::Peripheral; |
| 17 | 17 | ||
| 18 | pub 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 | |||
| 29 | pub struct BurstController<T: Instance> { | 19 | pub struct BurstController<T: Instance> { |
| 30 | phantom: PhantomData<T>, | 20 | phantom: PhantomData<T>, |
| 31 | } | 21 | } |
| 22 | |||
| 23 | /// HRTIM master instance. | ||
| 32 | pub struct Master<T: Instance> { | 24 | pub struct Master<T: Instance> { |
| 33 | phantom: PhantomData<T>, | 25 | phantom: PhantomData<T>, |
| 34 | } | 26 | } |
| 27 | |||
| 28 | /// HRTIM channel A instance. | ||
| 35 | pub struct ChA<T: Instance> { | 29 | pub struct ChA<T: Instance> { |
| 36 | phantom: PhantomData<T>, | 30 | phantom: PhantomData<T>, |
| 37 | } | 31 | } |
| 32 | |||
| 33 | /// HRTIM channel B instance. | ||
| 38 | pub struct ChB<T: Instance> { | 34 | pub struct ChB<T: Instance> { |
| 39 | phantom: PhantomData<T>, | 35 | phantom: PhantomData<T>, |
| 40 | } | 36 | } |
| 37 | |||
| 38 | /// HRTIM channel C instance. | ||
| 41 | pub struct ChC<T: Instance> { | 39 | pub struct ChC<T: Instance> { |
| 42 | phantom: PhantomData<T>, | 40 | phantom: PhantomData<T>, |
| 43 | } | 41 | } |
| 42 | |||
| 43 | /// HRTIM channel D instance. | ||
| 44 | pub struct ChD<T: Instance> { | 44 | pub struct ChD<T: Instance> { |
| 45 | phantom: PhantomData<T>, | 45 | phantom: PhantomData<T>, |
| 46 | } | 46 | } |
| 47 | |||
| 48 | /// HRTIM channel E instance. | ||
| 47 | pub struct ChE<T: Instance> { | 49 | pub 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)] |
| 51 | pub struct ChF<T: Instance> { | 55 | pub 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. | ||
| 63 | pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {} | 68 | pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {} |
| 64 | 69 | ||
| 70 | /// HRTIM PWM pin. | ||
| 65 | pub struct PwmPin<'d, Perip, Channel> { | 71 | pub 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. | ||
| 70 | pub struct ComplementaryPwmPin<'d, Perip, Channel> { | 77 | pub 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> { | |||
| 75 | macro_rules! advanced_channel_impl { | 82 | macro_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 |
| 127 | pub struct AdvancedPwm<'d, T: Instance> { | 136 | pub 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 | ||
| 140 | impl<'d, T: Instance> AdvancedPwm<'d, T> { | 157 | impl<'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 | ||
| 203 | impl<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 | ||
| 227 | impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> { | 241 | impl<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 | ||
| 372 | impl<T: Instance, C: AdvancedChannel<T>> ResonantConverter<T, C> { | 391 | impl<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. | ||
| 158 | pub trait Instance: sealed::Instance + 'static {} | 154 | pub trait Instance: sealed::Instance + 'static {} |
| 159 | 155 | ||
| 160 | foreach_interrupt! { | 156 | foreach_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; | |||
| 149 | pub use crate::pac::NVIC_PRIO_BITS; | 149 | pub use crate::pac::NVIC_PRIO_BITS; |
| 150 | use crate::rcc::sealed::RccPeripheral; | 150 | use crate::rcc::sealed::RccPeripheral; |
| 151 | 151 | ||
| 152 | /// `embassy-stm32` global configuration. | ||
| 153 | #[non_exhaustive] | 152 | #[non_exhaustive] |
| 154 | pub struct Config { | 153 | pub 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. | ||
| 204 | pub fn init(config: Config) -> Peripherals { | 182 | pub 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)] |
| 3 | pub(crate) enum QspiMode { | 5 | pub(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; | |||
| 14 | use crate::rcc::RccPeripheral; | 14 | use crate::rcc::RccPeripheral; |
| 15 | use crate::{peripherals, Peripheral}; | 15 | use crate::{peripherals, Peripheral}; |
| 16 | 16 | ||
| 17 | /// QSPI transfer configuration. | ||
| 17 | pub struct TransferConfig { | 18 | pub 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. | ||
| 48 | pub struct Config { | 50 | pub 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)] |
| 75 | pub struct Qspi<'d, T: Instance, Dma> { | 78 | pub 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 | ||
| 87 | impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { | 90 | impl<'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. | ||
| 382 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} | 393 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} |
| 383 | 394 | ||
| 384 | pin_trait!(SckPin, Instance); | 395 | pin_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))] |
| 59 | pub enum Signalling { | 60 | pub 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))] |
| 96 | pub enum Error { | 100 | pub 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)] |
| 365 | impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { | 375 | impl<'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. | ||
| 1422 | pub trait Instance: sealed::Instance + RccPeripheral + 'static {} | 1437 | pub trait Instance: sealed::Instance + RccPeripheral + 'static {} |
| 1438 | |||
| 1423 | pin_trait!(CkPin, Instance); | 1439 | pin_trait!(CkPin, Instance); |
| 1424 | pin_trait!(CmdPin, Instance); | 1440 | pin_trait!(CmdPin, Instance); |
| 1425 | pin_trait!(D0Pin, Instance); | 1441 | pin_trait!(D0Pin, Instance); |
| @@ -1434,7 +1450,10 @@ pin_trait!(D7Pin, Instance); | |||
| 1434 | #[cfg(sdmmc_v1)] | 1450 | #[cfg(sdmmc_v1)] |
| 1435 | dma_trait!(SdmmcDma, Instance); | 1451 | dma_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)] |
| 1439 | pub trait SdmmcDma<T: Instance> {} | 1458 | pub 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; | |||
| 16 | use crate::time::Hertz; | 16 | use crate::time::Hertz; |
| 17 | use crate::{peripherals, Peripheral}; | 17 | use 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))] |
| 21 | pub enum Error { | 22 | pub 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)] |
| 30 | pub enum BitOrder { | 35 | pub 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)] |
| 37 | pub struct Config { | 45 | pub 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. | ||
| 76 | pub struct Spi<'d, T: Instance, Tx, Rx> { | 88 | pub 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 | ||
| 86 | impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | 98 | impl<'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. | ||
| 949 | pub trait Word: word::Word + sealed::Word {} | 991 | pub trait Word: word::Word + sealed::Word {} |
| 950 | 992 | ||
| 951 | macro_rules! impl_word { | 993 | macro_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. | ||
| 1028 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} | 1071 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} |
| 1072 | |||
| 1029 | pin_trait!(SckPin, Instance); | 1073 | pin_trait!(SckPin, Instance); |
| 1030 | pin_trait!(MosiPin, Instance); | 1074 | pin_trait!(MosiPin, Instance); |
| 1031 | pin_trait!(MisoPin, Instance); | 1075 | pin_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}; | |||
| 8 | pub struct Hertz(pub u32); | 8 | pub struct Hertz(pub u32); |
| 9 | 9 | ||
| 10 | impl Hertz { | 10 | impl 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 | } |
