diff options
| -rw-r--r-- | embassy-stm32/src/dma/gpdma.rs | 18 | ||||
| -rw-r--r-- | embassy-stm32/src/hrtim/mod.rs | 16 | ||||
| -rw-r--r-- | embassy-stm32/src/ipcc.rs | 8 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 26 | ||||
| -rw-r--r-- | embassy-stm32/src/low_power.rs | 106 | ||||
| -rw-r--r-- | embassy-stm32/src/opamp.rs | 9 | ||||
| -rw-r--r-- | embassy-stm32/src/rng.rs | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/sdmmc/mod.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/complementary_pwm.rs | 31 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/mod.rs | 158 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/qei.rs | 23 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/simple_pwm.rs | 45 | ||||
| -rw-r--r-- | embassy-stm32/src/usb/mod.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/usb/usb.rs | 7 | ||||
| -rw-r--r-- | embassy-stm32/src/usb_otg/mod.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/usb_otg/usb.rs | 13 | ||||
| -rw-r--r-- | embassy-stm32/src/wdg/mod.rs | 4 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/ws2812_pwm_dma.rs | 2 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/low_level_timer_api.rs | 10 |
19 files changed, 375 insertions, 110 deletions
diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index b061415eb..34b2426b9 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs | |||
| @@ -16,6 +16,7 @@ use crate::interrupt::Priority; | |||
| 16 | use crate::pac; | 16 | use crate::pac; |
| 17 | use crate::pac::gpdma::vals; | 17 | use crate::pac::gpdma::vals; |
| 18 | 18 | ||
| 19 | /// GPDMA transfer options. | ||
| 19 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 20 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| 20 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 21 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 21 | #[non_exhaustive] | 22 | #[non_exhaustive] |
| @@ -113,10 +114,13 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::gpdma::Gpdma, channel_num: usize, in | |||
| 113 | } | 114 | } |
| 114 | } | 115 | } |
| 115 | 116 | ||
| 117 | /// DMA request type alias. (also known as DMA channel number in some chips) | ||
| 116 | pub type Request = u8; | 118 | pub type Request = u8; |
| 117 | 119 | ||
| 120 | /// DMA channel. | ||
| 118 | #[cfg(dmamux)] | 121 | #[cfg(dmamux)] |
| 119 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} | 122 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} |
| 123 | /// DMA channel. | ||
| 120 | #[cfg(not(dmamux))] | 124 | #[cfg(not(dmamux))] |
| 121 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} | 125 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} |
| 122 | 126 | ||
| @@ -131,12 +135,14 @@ pub(crate) mod sealed { | |||
| 131 | } | 135 | } |
| 132 | } | 136 | } |
| 133 | 137 | ||
| 138 | /// DMA transfer. | ||
| 134 | #[must_use = "futures do nothing unless you `.await` or poll them"] | 139 | #[must_use = "futures do nothing unless you `.await` or poll them"] |
| 135 | pub struct Transfer<'a, C: Channel> { | 140 | pub struct Transfer<'a, C: Channel> { |
| 136 | channel: PeripheralRef<'a, C>, | 141 | channel: PeripheralRef<'a, C>, |
| 137 | } | 142 | } |
| 138 | 143 | ||
| 139 | impl<'a, C: Channel> Transfer<'a, C> { | 144 | impl<'a, C: Channel> Transfer<'a, C> { |
| 145 | /// Create a new read DMA transfer (peripheral to memory). | ||
| 140 | pub unsafe fn new_read<W: Word>( | 146 | pub unsafe fn new_read<W: Word>( |
| 141 | channel: impl Peripheral<P = C> + 'a, | 147 | channel: impl Peripheral<P = C> + 'a, |
| 142 | request: Request, | 148 | request: Request, |
| @@ -147,6 +153,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 147 | Self::new_read_raw(channel, request, peri_addr, buf, options) | 153 | Self::new_read_raw(channel, request, peri_addr, buf, options) |
| 148 | } | 154 | } |
| 149 | 155 | ||
| 156 | /// Create a new read DMA transfer (peripheral to memory), using raw pointers. | ||
| 150 | pub unsafe fn new_read_raw<W: Word>( | 157 | pub unsafe fn new_read_raw<W: Word>( |
| 151 | channel: impl Peripheral<P = C> + 'a, | 158 | channel: impl Peripheral<P = C> + 'a, |
| 152 | request: Request, | 159 | request: Request, |
| @@ -172,6 +179,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 172 | ) | 179 | ) |
| 173 | } | 180 | } |
| 174 | 181 | ||
| 182 | /// Create a new write DMA transfer (memory to peripheral). | ||
| 175 | pub unsafe fn new_write<W: Word>( | 183 | pub unsafe fn new_write<W: Word>( |
| 176 | channel: impl Peripheral<P = C> + 'a, | 184 | channel: impl Peripheral<P = C> + 'a, |
| 177 | request: Request, | 185 | request: Request, |
| @@ -182,6 +190,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 182 | Self::new_write_raw(channel, request, buf, peri_addr, options) | 190 | Self::new_write_raw(channel, request, buf, peri_addr, options) |
| 183 | } | 191 | } |
| 184 | 192 | ||
| 193 | /// Create a new write DMA transfer (memory to peripheral), using raw pointers. | ||
| 185 | pub unsafe fn new_write_raw<W: Word>( | 194 | pub unsafe fn new_write_raw<W: Word>( |
| 186 | channel: impl Peripheral<P = C> + 'a, | 195 | channel: impl Peripheral<P = C> + 'a, |
| 187 | request: Request, | 196 | request: Request, |
| @@ -207,6 +216,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 207 | ) | 216 | ) |
| 208 | } | 217 | } |
| 209 | 218 | ||
| 219 | /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly. | ||
| 210 | pub unsafe fn new_write_repeated<W: Word>( | 220 | pub unsafe fn new_write_repeated<W: Word>( |
| 211 | channel: impl Peripheral<P = C> + 'a, | 221 | channel: impl Peripheral<P = C> + 'a, |
| 212 | request: Request, | 222 | request: Request, |
| @@ -297,6 +307,9 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 297 | this | 307 | this |
| 298 | } | 308 | } |
| 299 | 309 | ||
| 310 | /// Request the transfer to stop. | ||
| 311 | /// | ||
| 312 | /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. | ||
| 300 | pub fn request_stop(&mut self) { | 313 | pub fn request_stop(&mut self) { |
| 301 | let ch = self.channel.regs().ch(self.channel.num()); | 314 | let ch = self.channel.regs().ch(self.channel.num()); |
| 302 | ch.cr().modify(|w| { | 315 | ch.cr().modify(|w| { |
| @@ -304,6 +317,10 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 304 | }) | 317 | }) |
| 305 | } | 318 | } |
| 306 | 319 | ||
| 320 | /// Return whether this transfer is still running. | ||
| 321 | /// | ||
| 322 | /// If this returns `false`, it can be because either the transfer finished, or | ||
| 323 | /// it was requested to stop early with [`request_stop`](Self::request_stop). | ||
| 307 | pub fn is_running(&mut self) -> bool { | 324 | pub fn is_running(&mut self) -> bool { |
| 308 | let ch = self.channel.regs().ch(self.channel.num()); | 325 | let ch = self.channel.regs().ch(self.channel.num()); |
| 309 | let sr = ch.sr().read(); | 326 | let sr = ch.sr().read(); |
| @@ -317,6 +334,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 317 | ch.br1().read().bndt() | 334 | ch.br1().read().bndt() |
| 318 | } | 335 | } |
| 319 | 336 | ||
| 337 | /// Blocking wait until the transfer finishes. | ||
| 320 | pub fn blocking_wait(mut self) { | 338 | pub fn blocking_wait(mut self) { |
| 321 | while self.is_running() {} | 339 | while self.is_running() {} |
| 322 | 340 | ||
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index 1e6626a58..faefaabbc 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs | |||
| @@ -68,22 +68,22 @@ mod sealed { | |||
| 68 | pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {} | 68 | pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {} |
| 69 | 69 | ||
| 70 | /// HRTIM PWM pin. | 70 | /// HRTIM PWM pin. |
| 71 | pub struct PwmPin<'d, Perip, Channel> { | 71 | pub struct PwmPin<'d, T, C> { |
| 72 | _pin: PeripheralRef<'d, AnyPin>, | 72 | _pin: PeripheralRef<'d, AnyPin>, |
| 73 | phantom: PhantomData<(Perip, Channel)>, | 73 | phantom: PhantomData<(T, C)>, |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | /// HRTIM complementary PWM pin. | 76 | /// HRTIM complementary PWM pin. |
| 77 | pub struct ComplementaryPwmPin<'d, Perip, Channel> { | 77 | pub struct ComplementaryPwmPin<'d, T, C> { |
| 78 | _pin: PeripheralRef<'d, AnyPin>, | 78 | _pin: PeripheralRef<'d, AnyPin>, |
| 79 | phantom: PhantomData<(Perip, Channel)>, | 79 | phantom: PhantomData<(T, C)>, |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | macro_rules! advanced_channel_impl { | 82 | macro_rules! advanced_channel_impl { |
| 83 | ($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) => { |
| 84 | impl<'d, Perip: Instance> PwmPin<'d, Perip, $channel<Perip>> { | 84 | impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> { |
| 85 | #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] | 85 | #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] |
| 86 | 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<T>> + 'd) -> Self { |
| 87 | into_ref!(pin); | 87 | into_ref!(pin); |
| 88 | critical_section::with(|_| { | 88 | critical_section::with(|_| { |
| 89 | pin.set_low(); | 89 | pin.set_low(); |
| @@ -98,9 +98,9 @@ macro_rules! advanced_channel_impl { | |||
| 98 | } | 98 | } |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | impl<'d, Perip: Instance> ComplementaryPwmPin<'d, Perip, $channel<Perip>> { | 101 | impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> { |
| 102 | #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] | 102 | #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] |
| 103 | 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<T>> + 'd) -> Self { |
| 104 | into_ref!(pin); | 104 | into_ref!(pin); |
| 105 | critical_section::with(|_| { | 105 | critical_section::with(|_| { |
| 106 | pin.set_low(); | 106 | pin.set_low(); |
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs index 4006dee19..663a7f59d 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/ipcc.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | //! Inter-Process Communication Controller (IPCC) | ||
| 2 | |||
| 1 | use core::future::poll_fn; | 3 | use core::future::poll_fn; |
| 2 | use core::sync::atomic::{compiler_fence, Ordering}; | 4 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 3 | use core::task::Poll; | 5 | use core::task::Poll; |
| @@ -41,6 +43,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for Receive | |||
| 41 | } | 43 | } |
| 42 | } | 44 | } |
| 43 | 45 | ||
| 46 | /// TX interrupt handler. | ||
| 44 | pub struct TransmitInterruptHandler {} | 47 | pub struct TransmitInterruptHandler {} |
| 45 | 48 | ||
| 46 | impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler { | 49 | impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler { |
| @@ -72,6 +75,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for Transmi | |||
| 72 | } | 75 | } |
| 73 | } | 76 | } |
| 74 | 77 | ||
| 78 | /// IPCC config. | ||
| 75 | #[non_exhaustive] | 79 | #[non_exhaustive] |
| 76 | #[derive(Clone, Copy, Default)] | 80 | #[derive(Clone, Copy, Default)] |
| 77 | pub struct Config { | 81 | pub struct Config { |
| @@ -79,6 +83,8 @@ pub struct Config { | |||
| 79 | // reserved for future use | 83 | // reserved for future use |
| 80 | } | 84 | } |
| 81 | 85 | ||
| 86 | /// Channel. | ||
| 87 | #[allow(missing_docs)] | ||
| 82 | #[derive(Debug, Clone, Copy)] | 88 | #[derive(Debug, Clone, Copy)] |
| 83 | #[repr(C)] | 89 | #[repr(C)] |
| 84 | pub enum IpccChannel { | 90 | pub enum IpccChannel { |
| @@ -90,9 +96,11 @@ pub enum IpccChannel { | |||
| 90 | Channel6 = 5, | 96 | Channel6 = 5, |
| 91 | } | 97 | } |
| 92 | 98 | ||
| 99 | /// IPCC driver. | ||
| 93 | pub struct Ipcc; | 100 | pub struct Ipcc; |
| 94 | 101 | ||
| 95 | impl Ipcc { | 102 | impl Ipcc { |
| 103 | /// Enable IPCC. | ||
| 96 | pub fn enable(_config: Config) { | 104 | pub fn enable(_config: Config) { |
| 97 | IPCC::enable_and_reset(); | 105 | IPCC::enable_and_reset(); |
| 98 | IPCC::set_cpu2(true); | 106 | IPCC::set_cpu2(true); |
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 5d9b4e6a0..207f7ed8f 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | #![cfg_attr(not(test), no_std)] | 1 | #![cfg_attr(not(test), no_std)] |
| 2 | #![allow(async_fn_in_trait)] | 2 | #![allow(async_fn_in_trait)] |
| 3 | #![warn(missing_docs)] | ||
| 3 | 4 | ||
| 4 | //! ## Feature flags | 5 | //! ## Feature flags |
| 5 | #![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)] | 6 | #![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)] |
| @@ -79,6 +80,7 @@ pub(crate) mod _generated { | |||
| 79 | #![allow(dead_code)] | 80 | #![allow(dead_code)] |
| 80 | #![allow(unused_imports)] | 81 | #![allow(unused_imports)] |
| 81 | #![allow(non_snake_case)] | 82 | #![allow(non_snake_case)] |
| 83 | #![allow(missing_docs)] | ||
| 82 | 84 | ||
| 83 | include!(concat!(env!("OUT_DIR"), "/_generated.rs")); | 85 | include!(concat!(env!("OUT_DIR"), "/_generated.rs")); |
| 84 | } | 86 | } |
| @@ -149,15 +151,33 @@ use crate::interrupt::Priority; | |||
| 149 | pub use crate::pac::NVIC_PRIO_BITS; | 151 | pub use crate::pac::NVIC_PRIO_BITS; |
| 150 | use crate::rcc::sealed::RccPeripheral; | 152 | use crate::rcc::sealed::RccPeripheral; |
| 151 | 153 | ||
| 154 | /// `embassy-stm32` global configuration. | ||
| 152 | #[non_exhaustive] | 155 | #[non_exhaustive] |
| 153 | pub struct Config { | 156 | pub struct Config { |
| 157 | /// RCC config. | ||
| 154 | pub rcc: rcc::Config, | 158 | pub rcc: rcc::Config, |
| 159 | |||
| 160 | /// Enable debug during sleep. | ||
| 161 | /// | ||
| 162 | /// May incrase power consumption. Defaults to true. | ||
| 155 | #[cfg(dbgmcu)] | 163 | #[cfg(dbgmcu)] |
| 156 | pub enable_debug_during_sleep: bool, | 164 | pub enable_debug_during_sleep: bool, |
| 165 | |||
| 166 | /// BDMA interrupt priority. | ||
| 167 | /// | ||
| 168 | /// Defaults to P0 (highest). | ||
| 157 | #[cfg(bdma)] | 169 | #[cfg(bdma)] |
| 158 | pub bdma_interrupt_priority: Priority, | 170 | pub bdma_interrupt_priority: Priority, |
| 171 | |||
| 172 | /// DMA interrupt priority. | ||
| 173 | /// | ||
| 174 | /// Defaults to P0 (highest). | ||
| 159 | #[cfg(dma)] | 175 | #[cfg(dma)] |
| 160 | pub dma_interrupt_priority: Priority, | 176 | pub dma_interrupt_priority: Priority, |
| 177 | |||
| 178 | /// GPDMA interrupt priority. | ||
| 179 | /// | ||
| 180 | /// Defaults to P0 (highest). | ||
| 161 | #[cfg(gpdma)] | 181 | #[cfg(gpdma)] |
| 162 | pub gpdma_interrupt_priority: Priority, | 182 | pub gpdma_interrupt_priority: Priority, |
| 163 | } | 183 | } |
| @@ -178,7 +198,11 @@ impl Default for Config { | |||
| 178 | } | 198 | } |
| 179 | } | 199 | } |
| 180 | 200 | ||
| 181 | /// Initialize embassy. | 201 | /// Initialize the `embassy-stm32` HAL with the provided configuration. |
| 202 | /// | ||
| 203 | /// This returns the peripheral singletons that can be used for creating drivers. | ||
| 204 | /// | ||
| 205 | /// This should only be called once at startup, otherwise it panics. | ||
| 182 | pub fn init(config: Config) -> Peripherals { | 206 | pub fn init(config: Config) -> Peripherals { |
| 183 | critical_section::with(|cs| { | 207 | critical_section::with(|cs| { |
| 184 | let p = Peripherals::take_with_cs(cs); | 208 | let p = Peripherals::take_with_cs(cs); |
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 20d8f9045..a41c40eba 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs | |||
| @@ -1,50 +1,53 @@ | |||
| 1 | /// The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating | 1 | //! Low-power support. |
| 2 | /// to reduce power consumption. `embassy-stm32` provides a low-power executor, [`Executor`] which | 2 | //! |
| 3 | /// can use knowledge of which peripherals are currently blocked upon to transparently and safely | 3 | //! The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating |
| 4 | /// enter such low-power modes (currently, only `STOP2`) when idle. | 4 | //! to reduce power consumption. `embassy-stm32` provides a low-power executor, [`Executor`] which |
| 5 | /// | 5 | //! can use knowledge of which peripherals are currently blocked upon to transparently and safely |
| 6 | /// The executor determines which peripherals are active by their RCC state; consequently, | 6 | //! enter such low-power modes (currently, only `STOP2`) when idle. |
| 7 | /// low-power states can only be entered if all peripherals have been `drop`'d. There are a few | 7 | //! |
| 8 | /// exceptions to this rule: | 8 | //! The executor determines which peripherals are active by their RCC state; consequently, |
| 9 | /// | 9 | //! low-power states can only be entered if all peripherals have been `drop`'d. There are a few |
| 10 | /// * `GPIO` | 10 | //! exceptions to this rule: |
| 11 | /// * `RCC` | 11 | //! |
| 12 | /// | 12 | //! * `GPIO` |
| 13 | /// Since entering and leaving low-power modes typically incurs a significant latency, the | 13 | //! * `RCC` |
| 14 | /// low-power executor will only attempt to enter when the next timer event is at least | 14 | //! |
| 15 | /// [`time_driver::MIN_STOP_PAUSE`] in the future. | 15 | //! Since entering and leaving low-power modes typically incurs a significant latency, the |
| 16 | /// | 16 | //! low-power executor will only attempt to enter when the next timer event is at least |
| 17 | /// Currently there is no macro analogous to `embassy_executor::main` for this executor; | 17 | //! [`time_driver::MIN_STOP_PAUSE`] in the future. |
| 18 | /// consequently one must define their entrypoint manually. Moveover, you must relinquish control | 18 | //! |
| 19 | /// of the `RTC` peripheral to the executor. This will typically look like | 19 | //! Currently there is no macro analogous to `embassy_executor::main` for this executor; |
| 20 | /// | 20 | //! consequently one must define their entrypoint manually. Moveover, you must relinquish control |
| 21 | /// ```rust,no_run | 21 | //! of the `RTC` peripheral to the executor. This will typically look like |
| 22 | /// use embassy_executor::Spawner; | 22 | //! |
| 23 | /// use embassy_stm32::low_power::Executor; | 23 | //! ```rust,no_run |
| 24 | /// use embassy_stm32::rtc::{Rtc, RtcConfig}; | 24 | //! use embassy_executor::Spawner; |
| 25 | /// use static_cell::make_static; | 25 | //! use embassy_stm32::low_power::Executor; |
| 26 | /// | 26 | //! use embassy_stm32::rtc::{Rtc, RtcConfig}; |
| 27 | /// #[cortex_m_rt::entry] | 27 | //! use static_cell::make_static; |
| 28 | /// fn main() -> ! { | 28 | //! |
| 29 | /// Executor::take().run(|spawner| { | 29 | //! #[cortex_m_rt::entry] |
| 30 | /// unwrap!(spawner.spawn(async_main(spawner))); | 30 | //! fn main() -> ! { |
| 31 | /// }); | 31 | //! Executor::take().run(|spawner| { |
| 32 | /// } | 32 | //! unwrap!(spawner.spawn(async_main(spawner))); |
| 33 | /// | 33 | //! }); |
| 34 | /// #[embassy_executor::task] | 34 | //! } |
| 35 | /// async fn async_main(spawner: Spawner) { | 35 | //! |
| 36 | /// // initialize the platform... | 36 | //! #[embassy_executor::task] |
| 37 | /// let mut config = embassy_stm32::Config::default(); | 37 | //! async fn async_main(spawner: Spawner) { |
| 38 | /// let p = embassy_stm32::init(config); | 38 | //! // initialize the platform... |
| 39 | /// | 39 | //! let mut config = embassy_stm32::Config::default(); |
| 40 | /// // give the RTC to the executor... | 40 | //! let p = embassy_stm32::init(config); |
| 41 | /// let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); | 41 | //! |
| 42 | /// let rtc = make_static!(rtc); | 42 | //! // give the RTC to the executor... |
| 43 | /// embassy_stm32::low_power::stop_with_rtc(rtc); | 43 | //! let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); |
| 44 | /// | 44 | //! let rtc = make_static!(rtc); |
| 45 | /// // your application here... | 45 | //! embassy_stm32::low_power::stop_with_rtc(rtc); |
| 46 | /// } | 46 | //! |
| 47 | /// ``` | 47 | //! // your application here... |
| 48 | //! } | ||
| 49 | //! ``` | ||
| 50 | |||
| 48 | use core::arch::asm; | 51 | use core::arch::asm; |
| 49 | use core::marker::PhantomData; | 52 | use core::marker::PhantomData; |
| 50 | use core::sync::atomic::{compiler_fence, Ordering}; | 53 | use core::sync::atomic::{compiler_fence, Ordering}; |
| @@ -64,6 +67,7 @@ static mut EXECUTOR: Option<Executor> = None; | |||
| 64 | foreach_interrupt! { | 67 | foreach_interrupt! { |
| 65 | (RTC, rtc, $block:ident, WKUP, $irq:ident) => { | 68 | (RTC, rtc, $block:ident, WKUP, $irq:ident) => { |
| 66 | #[interrupt] | 69 | #[interrupt] |
| 70 | #[allow(non_snake_case)] | ||
| 67 | unsafe fn $irq() { | 71 | unsafe fn $irq() { |
| 68 | EXECUTOR.as_mut().unwrap().on_wakeup_irq(); | 72 | EXECUTOR.as_mut().unwrap().on_wakeup_irq(); |
| 69 | } | 73 | } |
| @@ -75,10 +79,15 @@ pub(crate) unsafe fn on_wakeup_irq() { | |||
| 75 | EXECUTOR.as_mut().unwrap().on_wakeup_irq(); | 79 | EXECUTOR.as_mut().unwrap().on_wakeup_irq(); |
| 76 | } | 80 | } |
| 77 | 81 | ||
| 82 | /// Configure STOP mode with RTC. | ||
| 78 | pub fn stop_with_rtc(rtc: &'static Rtc) { | 83 | pub fn stop_with_rtc(rtc: &'static Rtc) { |
| 79 | unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) | 84 | unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) |
| 80 | } | 85 | } |
| 81 | 86 | ||
| 87 | /// Get whether the core is ready to enter the given stop mode. | ||
| 88 | /// | ||
| 89 | /// This will return false if some peripheral driver is in use that | ||
| 90 | /// prevents entering the given stop mode. | ||
| 82 | pub fn stop_ready(stop_mode: StopMode) -> bool { | 91 | pub fn stop_ready(stop_mode: StopMode) -> bool { |
| 83 | match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() { | 92 | match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() { |
| 84 | Some(StopMode::Stop2) => true, | 93 | Some(StopMode::Stop2) => true, |
| @@ -87,10 +96,13 @@ pub fn stop_ready(stop_mode: StopMode) -> bool { | |||
| 87 | } | 96 | } |
| 88 | } | 97 | } |
| 89 | 98 | ||
| 99 | /// Available stop modes. | ||
| 90 | #[non_exhaustive] | 100 | #[non_exhaustive] |
| 91 | #[derive(PartialEq)] | 101 | #[derive(PartialEq)] |
| 92 | pub enum StopMode { | 102 | pub enum StopMode { |
| 103 | /// STOP 1 | ||
| 93 | Stop1, | 104 | Stop1, |
| 105 | /// STOP 2 | ||
| 94 | Stop2, | 106 | Stop2, |
| 95 | } | 107 | } |
| 96 | 108 | ||
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index e1eb031d1..df8a78bcc 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs | |||
| @@ -1,9 +1,12 @@ | |||
| 1 | //! Operational Amplifier (OPAMP) | ||
| 1 | #![macro_use] | 2 | #![macro_use] |
| 2 | 3 | ||
| 3 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 4 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 4 | 5 | ||
| 5 | use crate::Peripheral; | 6 | use crate::Peripheral; |
| 6 | 7 | ||
| 8 | /// Gain | ||
| 9 | #[allow(missing_docs)] | ||
| 7 | #[derive(Clone, Copy)] | 10 | #[derive(Clone, Copy)] |
| 8 | pub enum OpAmpGain { | 11 | pub enum OpAmpGain { |
| 9 | Mul1, | 12 | Mul1, |
| @@ -13,6 +16,8 @@ pub enum OpAmpGain { | |||
| 13 | Mul16, | 16 | Mul16, |
| 14 | } | 17 | } |
| 15 | 18 | ||
| 19 | /// Speed | ||
| 20 | #[allow(missing_docs)] | ||
| 16 | #[derive(Clone, Copy)] | 21 | #[derive(Clone, Copy)] |
| 17 | pub enum OpAmpSpeed { | 22 | pub enum OpAmpSpeed { |
| 18 | Normal, | 23 | Normal, |
| @@ -180,6 +185,7 @@ impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> { | |||
| 180 | } | 185 | } |
| 181 | } | 186 | } |
| 182 | 187 | ||
| 188 | /// Opamp instance trait. | ||
| 183 | pub trait Instance: sealed::Instance + 'static {} | 189 | pub trait Instance: sealed::Instance + 'static {} |
| 184 | 190 | ||
| 185 | pub(crate) mod sealed { | 191 | pub(crate) mod sealed { |
| @@ -198,8 +204,11 @@ pub(crate) mod sealed { | |||
| 198 | pub trait OutputPin<T: Instance> {} | 204 | pub trait OutputPin<T: Instance> {} |
| 199 | } | 205 | } |
| 200 | 206 | ||
| 207 | /// Non-inverting pin trait. | ||
| 201 | pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {} | 208 | pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {} |
| 209 | /// Inverting pin trait. | ||
| 202 | pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {} | 210 | pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {} |
| 211 | /// Output pin trait. | ||
| 203 | pub trait OutputPin<T: Instance>: sealed::OutputPin<T> {} | 212 | pub trait OutputPin<T: Instance>: sealed::OutputPin<T> {} |
| 204 | 213 | ||
| 205 | macro_rules! impl_opamp_external_output { | 214 | macro_rules! impl_opamp_external_output { |
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index 6ee89a922..ca641f352 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs | |||
| @@ -80,6 +80,7 @@ impl<'d, T: Instance> Rng<'d, T> { | |||
| 80 | let _ = self.next_u32(); | 80 | let _ = self.next_u32(); |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | /// Reset the RNG. | ||
| 83 | #[cfg(not(rng_v1))] | 84 | #[cfg(not(rng_v1))] |
| 84 | pub fn reset(&mut self) { | 85 | pub fn reset(&mut self) { |
| 85 | T::regs().cr().write(|reg| { | 86 | T::regs().cr().write(|reg| { |
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index ab142053a..10006baff 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs | |||
| @@ -293,6 +293,7 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> { | |||
| 293 | 293 | ||
| 294 | #[cfg(sdmmc_v1)] | 294 | #[cfg(sdmmc_v1)] |
| 295 | impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { | 295 | impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { |
| 296 | /// Create a new SDMMC driver, with 1 data lane. | ||
| 296 | pub fn new_1bit( | 297 | pub fn new_1bit( |
| 297 | sdmmc: impl Peripheral<P = T> + 'd, | 298 | sdmmc: impl Peripheral<P = T> + 'd, |
| 298 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 299 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| @@ -327,6 +328,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { | |||
| 327 | ) | 328 | ) |
| 328 | } | 329 | } |
| 329 | 330 | ||
| 331 | /// Create a new SDMMC driver, with 4 data lanes. | ||
| 330 | pub fn new_4bit( | 332 | pub fn new_4bit( |
| 331 | sdmmc: impl Peripheral<P = T> + 'd, | 333 | sdmmc: impl Peripheral<P = T> + 'd, |
| 332 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 334 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index e543a5b43..71d7110b5 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs | |||
| @@ -13,15 +13,19 @@ use crate::gpio::{AnyPin, OutputType}; | |||
| 13 | use crate::time::Hertz; | 13 | use crate::time::Hertz; |
| 14 | use crate::Peripheral; | 14 | use crate::Peripheral; |
| 15 | 15 | ||
| 16 | pub struct ComplementaryPwmPin<'d, Perip, Channel> { | 16 | /// Complementary PWM pin wrapper. |
| 17 | /// | ||
| 18 | /// This wraps a pin to make it usable with PWM. | ||
| 19 | pub struct ComplementaryPwmPin<'d, T, C> { | ||
| 17 | _pin: PeripheralRef<'d, AnyPin>, | 20 | _pin: PeripheralRef<'d, AnyPin>, |
| 18 | phantom: PhantomData<(Perip, Channel)>, | 21 | phantom: PhantomData<(T, C)>, |
| 19 | } | 22 | } |
| 20 | 23 | ||
| 21 | macro_rules! complementary_channel_impl { | 24 | macro_rules! complementary_channel_impl { |
| 22 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | 25 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { |
| 23 | impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { | 26 | impl<'d, T: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> { |
| 24 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd, output_type: OutputType) -> Self { | 27 | #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] |
| 28 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self { | ||
| 25 | into_ref!(pin); | 29 | into_ref!(pin); |
| 26 | critical_section::with(|_| { | 30 | critical_section::with(|_| { |
| 27 | pin.set_low(); | 31 | pin.set_low(); |
| @@ -43,11 +47,13 @@ complementary_channel_impl!(new_ch2, Ch2, Channel2ComplementaryPin); | |||
| 43 | complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin); | 47 | complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin); |
| 44 | complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); | 48 | complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); |
| 45 | 49 | ||
| 50 | /// PWM driver with support for standard and complementary outputs. | ||
| 46 | pub struct ComplementaryPwm<'d, T> { | 51 | pub struct ComplementaryPwm<'d, T> { |
| 47 | inner: PeripheralRef<'d, T>, | 52 | inner: PeripheralRef<'d, T>, |
| 48 | } | 53 | } |
| 49 | 54 | ||
| 50 | impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | 55 | impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { |
| 56 | /// Create a new complementary PWM driver. | ||
| 51 | pub fn new( | 57 | pub fn new( |
| 52 | tim: impl Peripheral<P = T> + 'd, | 58 | tim: impl Peripheral<P = T> + 'd, |
| 53 | _ch1: Option<PwmPin<'d, T, Ch1>>, | 59 | _ch1: Option<PwmPin<'d, T, Ch1>>, |
| @@ -72,7 +78,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | |||
| 72 | let mut this = Self { inner: tim }; | 78 | let mut this = Self { inner: tim }; |
| 73 | 79 | ||
| 74 | this.inner.set_counting_mode(counting_mode); | 80 | this.inner.set_counting_mode(counting_mode); |
| 75 | this.set_freq(freq); | 81 | this.set_frequency(freq); |
| 76 | this.inner.start(); | 82 | this.inner.start(); |
| 77 | 83 | ||
| 78 | this.inner.enable_outputs(); | 84 | this.inner.enable_outputs(); |
| @@ -88,17 +94,23 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | |||
| 88 | this | 94 | this |
| 89 | } | 95 | } |
| 90 | 96 | ||
| 97 | /// Enable the given channel. | ||
| 91 | pub fn enable(&mut self, channel: Channel) { | 98 | pub fn enable(&mut self, channel: Channel) { |
| 92 | self.inner.enable_channel(channel, true); | 99 | self.inner.enable_channel(channel, true); |
| 93 | self.inner.enable_complementary_channel(channel, true); | 100 | self.inner.enable_complementary_channel(channel, true); |
| 94 | } | 101 | } |
| 95 | 102 | ||
| 103 | /// Disable the given channel. | ||
| 96 | pub fn disable(&mut self, channel: Channel) { | 104 | pub fn disable(&mut self, channel: Channel) { |
| 97 | self.inner.enable_complementary_channel(channel, false); | 105 | self.inner.enable_complementary_channel(channel, false); |
| 98 | self.inner.enable_channel(channel, false); | 106 | self.inner.enable_channel(channel, false); |
| 99 | } | 107 | } |
| 100 | 108 | ||
| 101 | pub fn set_freq(&mut self, freq: Hertz) { | 109 | /// Set PWM frequency. |
| 110 | /// | ||
| 111 | /// Note: when you call this, the max duty value changes, so you will have to | ||
| 112 | /// call `set_duty` on all channels with the duty calculated based on the new max duty. | ||
| 113 | pub fn set_frequency(&mut self, freq: Hertz) { | ||
| 102 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { | 114 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { |
| 103 | 2u8 | 115 | 2u8 |
| 104 | } else { | 116 | } else { |
| @@ -107,15 +119,22 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | |||
| 107 | self.inner.set_frequency(freq * multiplier); | 119 | self.inner.set_frequency(freq * multiplier); |
| 108 | } | 120 | } |
| 109 | 121 | ||
| 122 | /// Get max duty value. | ||
| 123 | /// | ||
| 124 | /// This value depends on the configured frequency and the timer's clock rate from RCC. | ||
| 110 | pub fn get_max_duty(&self) -> u16 { | 125 | pub fn get_max_duty(&self) -> u16 { |
| 111 | self.inner.get_max_compare_value() + 1 | 126 | self.inner.get_max_compare_value() + 1 |
| 112 | } | 127 | } |
| 113 | 128 | ||
| 129 | /// Set the duty for a given channel. | ||
| 130 | /// | ||
| 131 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. | ||
| 114 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { | 132 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { |
| 115 | assert!(duty <= self.get_max_duty()); | 133 | assert!(duty <= self.get_max_duty()); |
| 116 | self.inner.set_compare_value(channel, duty) | 134 | self.inner.set_compare_value(channel, duty) |
| 117 | } | 135 | } |
| 118 | 136 | ||
| 137 | /// Set the output polarity for a given channel. | ||
| 119 | pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { | 138 | pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { |
| 120 | self.inner.set_output_polarity(channel, polarity); | 139 | self.inner.set_output_polarity(channel, polarity); |
| 121 | self.inner.set_complementary_output_polarity(channel, polarity); | 140 | self.inner.set_complementary_output_polarity(channel, polarity); |
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 42ef878f7..74120adad 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs | |||
| @@ -17,17 +17,27 @@ pub mod low_level { | |||
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | pub(crate) mod sealed { | 19 | pub(crate) mod sealed { |
| 20 | |||
| 21 | use super::*; | 20 | use super::*; |
| 21 | |||
| 22 | /// Basic 16-bit timer instance. | ||
| 22 | pub trait Basic16bitInstance: RccPeripheral { | 23 | pub trait Basic16bitInstance: RccPeripheral { |
| 24 | /// Interrupt for this timer. | ||
| 23 | type Interrupt: interrupt::typelevel::Interrupt; | 25 | type Interrupt: interrupt::typelevel::Interrupt; |
| 24 | 26 | ||
| 27 | /// Get access to the basic 16bit timer registers. | ||
| 28 | /// | ||
| 29 | /// Note: This works even if the timer is more capable, because registers | ||
| 30 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 31 | /// for a given set of capabilities, and having it transparently work with | ||
| 32 | /// more capable timers. | ||
| 25 | fn regs() -> crate::pac::timer::TimBasic; | 33 | fn regs() -> crate::pac::timer::TimBasic; |
| 26 | 34 | ||
| 35 | /// Start the timer. | ||
| 27 | fn start(&mut self) { | 36 | fn start(&mut self) { |
| 28 | Self::regs().cr1().modify(|r| r.set_cen(true)); | 37 | Self::regs().cr1().modify(|r| r.set_cen(true)); |
| 29 | } | 38 | } |
| 30 | 39 | ||
| 40 | /// Stop the timer. | ||
| 31 | fn stop(&mut self) { | 41 | fn stop(&mut self) { |
| 32 | Self::regs().cr1().modify(|r| r.set_cen(false)); | 42 | Self::regs().cr1().modify(|r| r.set_cen(false)); |
| 33 | } | 43 | } |
| @@ -63,6 +73,9 @@ pub(crate) mod sealed { | |||
| 63 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); | 73 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); |
| 64 | } | 74 | } |
| 65 | 75 | ||
| 76 | /// Clear update interrupt. | ||
| 77 | /// | ||
| 78 | /// Returns whether the update interrupt flag was set. | ||
| 66 | fn clear_update_interrupt(&mut self) -> bool { | 79 | fn clear_update_interrupt(&mut self) -> bool { |
| 67 | let regs = Self::regs(); | 80 | let regs = Self::regs(); |
| 68 | let sr = regs.sr().read(); | 81 | let sr = regs.sr().read(); |
| @@ -76,14 +89,17 @@ pub(crate) mod sealed { | |||
| 76 | } | 89 | } |
| 77 | } | 90 | } |
| 78 | 91 | ||
| 92 | /// Enable/disable the update interrupt. | ||
| 79 | fn enable_update_interrupt(&mut self, enable: bool) { | 93 | fn enable_update_interrupt(&mut self, enable: bool) { |
| 80 | Self::regs().dier().write(|r| r.set_uie(enable)); | 94 | Self::regs().dier().write(|r| r.set_uie(enable)); |
| 81 | } | 95 | } |
| 82 | 96 | ||
| 97 | /// Enable/disable autoreload preload. | ||
| 83 | fn set_autoreload_preload(&mut self, enable: bool) { | 98 | fn set_autoreload_preload(&mut self, enable: bool) { |
| 84 | Self::regs().cr1().modify(|r| r.set_arpe(enable)); | 99 | Self::regs().cr1().modify(|r| r.set_arpe(enable)); |
| 85 | } | 100 | } |
| 86 | 101 | ||
| 102 | /// Get the timer frequency. | ||
| 87 | fn get_frequency(&self) -> Hertz { | 103 | fn get_frequency(&self) -> Hertz { |
| 88 | let timer_f = Self::frequency(); | 104 | let timer_f = Self::frequency(); |
| 89 | 105 | ||
| @@ -95,9 +111,17 @@ pub(crate) mod sealed { | |||
| 95 | } | 111 | } |
| 96 | } | 112 | } |
| 97 | 113 | ||
| 114 | /// Gneral-purpose 16-bit timer instance. | ||
| 98 | pub trait GeneralPurpose16bitInstance: Basic16bitInstance { | 115 | pub trait GeneralPurpose16bitInstance: Basic16bitInstance { |
| 116 | /// Get access to the general purpose 16bit timer registers. | ||
| 117 | /// | ||
| 118 | /// Note: This works even if the timer is more capable, because registers | ||
| 119 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 120 | /// for a given set of capabilities, and having it transparently work with | ||
| 121 | /// more capable timers. | ||
| 99 | fn regs_gp16() -> crate::pac::timer::TimGp16; | 122 | fn regs_gp16() -> crate::pac::timer::TimGp16; |
| 100 | 123 | ||
| 124 | /// Set counting mode. | ||
| 101 | fn set_counting_mode(&mut self, mode: CountingMode) { | 125 | fn set_counting_mode(&mut self, mode: CountingMode) { |
| 102 | let (cms, dir) = mode.into(); | 126 | let (cms, dir) = mode.into(); |
| 103 | 127 | ||
| @@ -110,19 +134,29 @@ pub(crate) mod sealed { | |||
| 110 | Self::regs_gp16().cr1().modify(|r| r.set_cms(cms)) | 134 | Self::regs_gp16().cr1().modify(|r| r.set_cms(cms)) |
| 111 | } | 135 | } |
| 112 | 136 | ||
| 137 | /// Get counting mode. | ||
| 113 | fn get_counting_mode(&self) -> CountingMode { | 138 | fn get_counting_mode(&self) -> CountingMode { |
| 114 | let cr1 = Self::regs_gp16().cr1().read(); | 139 | let cr1 = Self::regs_gp16().cr1().read(); |
| 115 | (cr1.cms(), cr1.dir()).into() | 140 | (cr1.cms(), cr1.dir()).into() |
| 116 | } | 141 | } |
| 117 | 142 | ||
| 143 | /// Set clock divider. | ||
| 118 | fn set_clock_division(&mut self, ckd: vals::Ckd) { | 144 | fn set_clock_division(&mut self, ckd: vals::Ckd) { |
| 119 | Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); | 145 | Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); |
| 120 | } | 146 | } |
| 121 | } | 147 | } |
| 122 | 148 | ||
| 149 | /// Gneral-purpose 32-bit timer instance. | ||
| 123 | pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { | 150 | pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { |
| 151 | /// Get access to the general purpose 32bit timer registers. | ||
| 152 | /// | ||
| 153 | /// Note: This works even if the timer is more capable, because registers | ||
| 154 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 155 | /// for a given set of capabilities, and having it transparently work with | ||
| 156 | /// more capable timers. | ||
| 124 | fn regs_gp32() -> crate::pac::timer::TimGp32; | 157 | fn regs_gp32() -> crate::pac::timer::TimGp32; |
| 125 | 158 | ||
| 159 | /// Set timer frequency. | ||
| 126 | fn set_frequency(&mut self, frequency: Hertz) { | 160 | fn set_frequency(&mut self, frequency: Hertz) { |
| 127 | let f = frequency.0; | 161 | let f = frequency.0; |
| 128 | assert!(f > 0); | 162 | assert!(f > 0); |
| @@ -140,6 +174,7 @@ pub(crate) mod sealed { | |||
| 140 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); | 174 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); |
| 141 | } | 175 | } |
| 142 | 176 | ||
| 177 | /// Get timer frequency. | ||
| 143 | fn get_frequency(&self) -> Hertz { | 178 | fn get_frequency(&self) -> Hertz { |
| 144 | let timer_f = Self::frequency(); | 179 | let timer_f = Self::frequency(); |
| 145 | 180 | ||
| @@ -151,141 +186,177 @@ pub(crate) mod sealed { | |||
| 151 | } | 186 | } |
| 152 | } | 187 | } |
| 153 | 188 | ||
| 189 | /// Advanced control timer instance. | ||
| 154 | pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { | 190 | pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { |
| 191 | /// Get access to the advanced timer registers. | ||
| 155 | fn regs_advanced() -> crate::pac::timer::TimAdv; | 192 | fn regs_advanced() -> crate::pac::timer::TimAdv; |
| 156 | } | 193 | } |
| 157 | 194 | ||
| 195 | /// Capture/Compare 16-bit timer instance. | ||
| 158 | pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { | 196 | pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { |
| 197 | /// Set input capture filter. | ||
| 159 | fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { | 198 | fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { |
| 160 | let raw_channel = channel.raw(); | 199 | let raw_channel = channel.index(); |
| 161 | Self::regs_gp16() | 200 | Self::regs_gp16() |
| 162 | .ccmr_input(raw_channel / 2) | 201 | .ccmr_input(raw_channel / 2) |
| 163 | .modify(|r| r.set_icf(raw_channel % 2, icf)); | 202 | .modify(|r| r.set_icf(raw_channel % 2, icf)); |
| 164 | } | 203 | } |
| 165 | 204 | ||
| 205 | /// Clear input interrupt. | ||
| 166 | fn clear_input_interrupt(&mut self, channel: Channel) { | 206 | fn clear_input_interrupt(&mut self, channel: Channel) { |
| 167 | Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.raw(), false)); | 207 | Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false)); |
| 168 | } | 208 | } |
| 169 | 209 | ||
| 210 | /// Enable input interrupt. | ||
| 170 | fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { | 211 | fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { |
| 171 | Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.raw(), enable)); | 212 | Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable)); |
| 172 | } | 213 | } |
| 214 | |||
| 215 | /// Set input capture prescaler. | ||
| 173 | fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { | 216 | fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { |
| 174 | let raw_channel = channel.raw(); | 217 | let raw_channel = channel.index(); |
| 175 | Self::regs_gp16() | 218 | Self::regs_gp16() |
| 176 | .ccmr_input(raw_channel / 2) | 219 | .ccmr_input(raw_channel / 2) |
| 177 | .modify(|r| r.set_icpsc(raw_channel % 2, factor)); | 220 | .modify(|r| r.set_icpsc(raw_channel % 2, factor)); |
| 178 | } | 221 | } |
| 179 | 222 | ||
| 223 | /// Set input TI selection. | ||
| 180 | fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { | 224 | fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { |
| 181 | let raw_channel = channel.raw(); | 225 | let raw_channel = channel.index(); |
| 182 | Self::regs_gp16() | 226 | Self::regs_gp16() |
| 183 | .ccmr_input(raw_channel / 2) | 227 | .ccmr_input(raw_channel / 2) |
| 184 | .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); | 228 | .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); |
| 185 | } | 229 | } |
| 230 | |||
| 231 | /// Set input capture mode. | ||
| 186 | fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { | 232 | fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { |
| 187 | Self::regs_gp16().ccer().modify(|r| match mode { | 233 | Self::regs_gp16().ccer().modify(|r| match mode { |
| 188 | InputCaptureMode::Rising => { | 234 | InputCaptureMode::Rising => { |
| 189 | r.set_ccnp(channel.raw(), false); | 235 | r.set_ccnp(channel.index(), false); |
| 190 | r.set_ccp(channel.raw(), false); | 236 | r.set_ccp(channel.index(), false); |
| 191 | } | 237 | } |
| 192 | InputCaptureMode::Falling => { | 238 | InputCaptureMode::Falling => { |
| 193 | r.set_ccnp(channel.raw(), false); | 239 | r.set_ccnp(channel.index(), false); |
| 194 | r.set_ccp(channel.raw(), true); | 240 | r.set_ccp(channel.index(), true); |
| 195 | } | 241 | } |
| 196 | InputCaptureMode::BothEdges => { | 242 | InputCaptureMode::BothEdges => { |
| 197 | r.set_ccnp(channel.raw(), true); | 243 | r.set_ccnp(channel.index(), true); |
| 198 | r.set_ccp(channel.raw(), true); | 244 | r.set_ccp(channel.index(), true); |
| 199 | } | 245 | } |
| 200 | }); | 246 | }); |
| 201 | } | 247 | } |
| 248 | |||
| 249 | /// Enable timer outputs. | ||
| 202 | fn enable_outputs(&mut self); | 250 | fn enable_outputs(&mut self); |
| 203 | 251 | ||
| 252 | /// Set output compare mode. | ||
| 204 | fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { | 253 | fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { |
| 205 | let r = Self::regs_gp16(); | 254 | let r = Self::regs_gp16(); |
| 206 | let raw_channel: usize = channel.raw(); | 255 | let raw_channel: usize = channel.index(); |
| 207 | r.ccmr_output(raw_channel / 2) | 256 | r.ccmr_output(raw_channel / 2) |
| 208 | .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); | 257 | .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); |
| 209 | } | 258 | } |
| 210 | 259 | ||
| 260 | /// Set output polarity. | ||
| 211 | fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { | 261 | fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { |
| 212 | Self::regs_gp16() | 262 | Self::regs_gp16() |
| 213 | .ccer() | 263 | .ccer() |
| 214 | .modify(|w| w.set_ccp(channel.raw(), polarity.into())); | 264 | .modify(|w| w.set_ccp(channel.index(), polarity.into())); |
| 215 | } | 265 | } |
| 216 | 266 | ||
| 267 | /// Enable/disable a channel. | ||
| 217 | fn enable_channel(&mut self, channel: Channel, enable: bool) { | 268 | fn enable_channel(&mut self, channel: Channel, enable: bool) { |
| 218 | Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.raw(), enable)); | 269 | Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable)); |
| 219 | } | 270 | } |
| 220 | 271 | ||
| 272 | /// Set compare value for a channel. | ||
| 221 | fn set_compare_value(&mut self, channel: Channel, value: u16) { | 273 | fn set_compare_value(&mut self, channel: Channel, value: u16) { |
| 222 | Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value)); | 274 | Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); |
| 223 | } | 275 | } |
| 224 | 276 | ||
| 277 | /// Get capture value for a channel. | ||
| 225 | fn get_capture_value(&mut self, channel: Channel) -> u16 { | 278 | fn get_capture_value(&mut self, channel: Channel) -> u16 { |
| 226 | Self::regs_gp16().ccr(channel.raw()).read().ccr() | 279 | Self::regs_gp16().ccr(channel.index()).read().ccr() |
| 227 | } | 280 | } |
| 228 | 281 | ||
| 282 | /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. | ||
| 229 | fn get_max_compare_value(&self) -> u16 { | 283 | fn get_max_compare_value(&self) -> u16 { |
| 230 | Self::regs_gp16().arr().read().arr() | 284 | Self::regs_gp16().arr().read().arr() |
| 231 | } | 285 | } |
| 232 | 286 | ||
| 287 | /// Get compare value for a channel. | ||
| 233 | fn get_compare_value(&self, channel: Channel) -> u16 { | 288 | fn get_compare_value(&self, channel: Channel) -> u16 { |
| 234 | Self::regs_gp16().ccr(channel.raw()).read().ccr() | 289 | Self::regs_gp16().ccr(channel.index()).read().ccr() |
| 235 | } | 290 | } |
| 236 | } | 291 | } |
| 237 | 292 | ||
| 293 | /// Capture/Compare 16-bit timer instance with complementary pin support. | ||
| 238 | pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance { | 294 | pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance { |
| 295 | /// Set complementary output polarity. | ||
| 239 | fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { | 296 | fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { |
| 240 | Self::regs_advanced() | 297 | Self::regs_advanced() |
| 241 | .ccer() | 298 | .ccer() |
| 242 | .modify(|w| w.set_ccnp(channel.raw(), polarity.into())); | 299 | .modify(|w| w.set_ccnp(channel.index(), polarity.into())); |
| 243 | } | 300 | } |
| 244 | 301 | ||
| 302 | /// Set clock divider for the dead time. | ||
| 245 | fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { | 303 | fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { |
| 246 | Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); | 304 | Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); |
| 247 | } | 305 | } |
| 248 | 306 | ||
| 307 | /// Set dead time, as a fraction of the max duty value. | ||
| 249 | fn set_dead_time_value(&mut self, value: u8) { | 308 | fn set_dead_time_value(&mut self, value: u8) { |
| 250 | Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); | 309 | Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); |
| 251 | } | 310 | } |
| 252 | 311 | ||
| 312 | /// Enable/disable a complementary channel. | ||
| 253 | fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { | 313 | fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { |
| 254 | Self::regs_advanced() | 314 | Self::regs_advanced() |
| 255 | .ccer() | 315 | .ccer() |
| 256 | .modify(|w| w.set_ccne(channel.raw(), enable)); | 316 | .modify(|w| w.set_ccne(channel.index(), enable)); |
| 257 | } | 317 | } |
| 258 | } | 318 | } |
| 259 | 319 | ||
| 320 | /// Capture/Compare 32-bit timer instance. | ||
| 260 | pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance { | 321 | pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance { |
| 322 | /// Set comapre value for a channel. | ||
| 261 | fn set_compare_value(&mut self, channel: Channel, value: u32) { | 323 | fn set_compare_value(&mut self, channel: Channel, value: u32) { |
| 262 | Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value)); | 324 | Self::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(value)); |
| 263 | } | 325 | } |
| 264 | 326 | ||
| 327 | /// Get capture value for a channel. | ||
| 265 | fn get_capture_value(&mut self, channel: Channel) -> u32 { | 328 | fn get_capture_value(&mut self, channel: Channel) -> u32 { |
| 266 | Self::regs_gp32().ccr(channel.raw()).read().ccr() | 329 | Self::regs_gp32().ccr(channel.index()).read().ccr() |
| 267 | } | 330 | } |
| 268 | 331 | ||
| 332 | /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. | ||
| 269 | fn get_max_compare_value(&self) -> u32 { | 333 | fn get_max_compare_value(&self) -> u32 { |
| 270 | Self::regs_gp32().arr().read().arr() | 334 | Self::regs_gp32().arr().read().arr() |
| 271 | } | 335 | } |
| 272 | 336 | ||
| 337 | /// Get compare value for a channel. | ||
| 273 | fn get_compare_value(&self, channel: Channel) -> u32 { | 338 | fn get_compare_value(&self, channel: Channel) -> u32 { |
| 274 | Self::regs_gp32().ccr(channel.raw()).read().ccr() | 339 | Self::regs_gp32().ccr(channel.index()).read().ccr() |
| 275 | } | 340 | } |
| 276 | } | 341 | } |
| 277 | } | 342 | } |
| 278 | 343 | ||
| 344 | /// Timer channel. | ||
| 279 | #[derive(Clone, Copy)] | 345 | #[derive(Clone, Copy)] |
| 280 | pub enum Channel { | 346 | pub enum Channel { |
| 347 | /// Channel 1. | ||
| 281 | Ch1, | 348 | Ch1, |
| 349 | /// Channel 2. | ||
| 282 | Ch2, | 350 | Ch2, |
| 351 | /// Channel 3. | ||
| 283 | Ch3, | 352 | Ch3, |
| 353 | /// Channel 4. | ||
| 284 | Ch4, | 354 | Ch4, |
| 285 | } | 355 | } |
| 286 | 356 | ||
| 287 | impl Channel { | 357 | impl Channel { |
| 288 | pub fn raw(&self) -> usize { | 358 | /// Get the channel index (0..3) |
| 359 | pub fn index(&self) -> usize { | ||
| 289 | match self { | 360 | match self { |
| 290 | Channel::Ch1 => 0, | 361 | Channel::Ch1 => 0, |
| 291 | Channel::Ch2 => 1, | 362 | Channel::Ch2 => 1, |
| @@ -295,17 +366,25 @@ impl Channel { | |||
| 295 | } | 366 | } |
| 296 | } | 367 | } |
| 297 | 368 | ||
| 369 | /// Input capture mode. | ||
| 298 | #[derive(Clone, Copy)] | 370 | #[derive(Clone, Copy)] |
| 299 | pub enum InputCaptureMode { | 371 | pub enum InputCaptureMode { |
| 372 | /// Rising edge only. | ||
| 300 | Rising, | 373 | Rising, |
| 374 | /// Falling edge only. | ||
| 301 | Falling, | 375 | Falling, |
| 376 | /// Both rising or falling edges. | ||
| 302 | BothEdges, | 377 | BothEdges, |
| 303 | } | 378 | } |
| 304 | 379 | ||
| 380 | /// Input TI selection. | ||
| 305 | #[derive(Clone, Copy)] | 381 | #[derive(Clone, Copy)] |
| 306 | pub enum InputTISelection { | 382 | pub enum InputTISelection { |
| 383 | /// Normal | ||
| 307 | Normal, | 384 | Normal, |
| 385 | /// Alternate | ||
| 308 | Alternate, | 386 | Alternate, |
| 387 | /// TRC | ||
| 309 | TRC, | 388 | TRC, |
| 310 | } | 389 | } |
| 311 | 390 | ||
| @@ -319,6 +398,7 @@ impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs { | |||
| 319 | } | 398 | } |
| 320 | } | 399 | } |
| 321 | 400 | ||
| 401 | /// Timer counting mode. | ||
| 322 | #[repr(u8)] | 402 | #[repr(u8)] |
| 323 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] | 403 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] |
| 324 | pub enum CountingMode { | 404 | pub enum CountingMode { |
| @@ -345,6 +425,7 @@ pub enum CountingMode { | |||
| 345 | } | 425 | } |
| 346 | 426 | ||
| 347 | impl CountingMode { | 427 | impl CountingMode { |
| 428 | /// Return whether this mode is edge-aligned (up or down). | ||
| 348 | pub fn is_edge_aligned(&self) -> bool { | 429 | pub fn is_edge_aligned(&self) -> bool { |
| 349 | match self { | 430 | match self { |
| 350 | CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true, | 431 | CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true, |
| @@ -352,6 +433,7 @@ impl CountingMode { | |||
| 352 | } | 433 | } |
| 353 | } | 434 | } |
| 354 | 435 | ||
| 436 | /// Return whether this mode is center-aligned. | ||
| 355 | pub fn is_center_aligned(&self) -> bool { | 437 | pub fn is_center_aligned(&self) -> bool { |
| 356 | match self { | 438 | match self { |
| 357 | CountingMode::CenterAlignedDownInterrupts | 439 | CountingMode::CenterAlignedDownInterrupts |
| @@ -386,16 +468,34 @@ impl From<(vals::Cms, vals::Dir)> for CountingMode { | |||
| 386 | } | 468 | } |
| 387 | } | 469 | } |
| 388 | 470 | ||
| 471 | /// Output compare mode. | ||
| 389 | #[derive(Clone, Copy)] | 472 | #[derive(Clone, Copy)] |
| 390 | pub enum OutputCompareMode { | 473 | pub enum OutputCompareMode { |
| 474 | /// The comparison between the output compare register TIMx_CCRx and | ||
| 475 | /// the counter TIMx_CNT has no effect on the outputs. | ||
| 476 | /// (this mode is used to generate a timing base). | ||
| 391 | Frozen, | 477 | Frozen, |
| 478 | /// Set channel to active level on match. OCxREF signal is forced high when the | ||
| 479 | /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx). | ||
| 392 | ActiveOnMatch, | 480 | ActiveOnMatch, |
| 481 | /// Set channel to inactive level on match. OCxREF signal is forced low when the | ||
| 482 | /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx). | ||
| 393 | InactiveOnMatch, | 483 | InactiveOnMatch, |
| 484 | /// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx. | ||
| 394 | Toggle, | 485 | Toggle, |
| 486 | /// Force inactive level - OCxREF is forced low. | ||
| 395 | ForceInactive, | 487 | ForceInactive, |
| 488 | /// Force active level - OCxREF is forced high. | ||
| 396 | ForceActive, | 489 | ForceActive, |
| 490 | /// PWM mode 1 - In upcounting, channel is active as long as TIMx_CNT<TIMx_CCRx | ||
| 491 | /// else inactive. In downcounting, channel is inactive (OCxREF=0) as long as | ||
| 492 | /// TIMx_CNT>TIMx_CCRx else active (OCxREF=1). | ||
| 397 | PwmMode1, | 493 | PwmMode1, |
| 494 | /// PWM mode 2 - In upcounting, channel is inactive as long as | ||
| 495 | /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as | ||
| 496 | /// TIMx_CNT>TIMx_CCRx else inactive. | ||
| 398 | PwmMode2, | 497 | PwmMode2, |
| 498 | // TODO: there's more modes here depending on the chip family. | ||
| 399 | } | 499 | } |
| 400 | 500 | ||
| 401 | impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { | 501 | impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { |
| @@ -413,9 +513,12 @@ impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { | |||
| 413 | } | 513 | } |
| 414 | } | 514 | } |
| 415 | 515 | ||
| 516 | /// Timer output pin polarity. | ||
| 416 | #[derive(Clone, Copy)] | 517 | #[derive(Clone, Copy)] |
| 417 | pub enum OutputPolarity { | 518 | pub enum OutputPolarity { |
| 519 | /// Active high (higher duty value makes the pin spend more time high). | ||
| 418 | ActiveHigh, | 520 | ActiveHigh, |
| 521 | /// Active low (higher duty value makes the pin spend more time low). | ||
| 419 | ActiveLow, | 522 | ActiveLow, |
| 420 | } | 523 | } |
| 421 | 524 | ||
| @@ -428,24 +531,31 @@ impl From<OutputPolarity> for bool { | |||
| 428 | } | 531 | } |
| 429 | } | 532 | } |
| 430 | 533 | ||
| 534 | /// Basic 16-bit timer instance. | ||
| 431 | pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} | 535 | pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} |
| 432 | 536 | ||
| 537 | /// Gneral-purpose 16-bit timer instance. | ||
| 433 | pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} | 538 | pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} |
| 434 | 539 | ||
| 540 | /// Gneral-purpose 32-bit timer instance. | ||
| 435 | pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {} | 541 | pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {} |
| 436 | 542 | ||
| 543 | /// Advanced control timer instance. | ||
| 437 | pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {} | 544 | pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {} |
| 438 | 545 | ||
| 546 | /// Capture/Compare 16-bit timer instance. | ||
| 439 | pub trait CaptureCompare16bitInstance: | 547 | pub trait CaptureCompare16bitInstance: |
| 440 | sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static | 548 | sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static |
| 441 | { | 549 | { |
| 442 | } | 550 | } |
| 443 | 551 | ||
| 552 | /// Capture/Compare 16-bit timer instance with complementary pin support. | ||
| 444 | pub trait ComplementaryCaptureCompare16bitInstance: | 553 | pub trait ComplementaryCaptureCompare16bitInstance: |
| 445 | sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static | 554 | sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static |
| 446 | { | 555 | { |
| 447 | } | 556 | } |
| 448 | 557 | ||
| 558 | /// Capture/Compare 32-bit timer instance. | ||
| 449 | pub trait CaptureCompare32bitInstance: | 559 | pub trait CaptureCompare32bitInstance: |
| 450 | sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static | 560 | sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static |
| 451 | { | 561 | { |
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index 9f9379c20..59efb72ba 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs | |||
| @@ -9,23 +9,30 @@ use crate::gpio::sealed::AFType; | |||
| 9 | use crate::gpio::AnyPin; | 9 | use crate::gpio::AnyPin; |
| 10 | use crate::Peripheral; | 10 | use crate::Peripheral; |
| 11 | 11 | ||
| 12 | /// Counting direction | ||
| 12 | pub enum Direction { | 13 | pub enum Direction { |
| 14 | /// Counting up. | ||
| 13 | Upcounting, | 15 | Upcounting, |
| 16 | /// Counting down. | ||
| 14 | Downcounting, | 17 | Downcounting, |
| 15 | } | 18 | } |
| 16 | 19 | ||
| 17 | pub struct Ch1; | 20 | /// Channel 1 marker type. |
| 18 | pub struct Ch2; | 21 | pub enum Ch1 {} |
| 22 | /// Channel 2 marker type. | ||
| 23 | pub enum Ch2 {} | ||
| 19 | 24 | ||
| 20 | pub struct QeiPin<'d, Perip, Channel> { | 25 | /// Wrapper for using a pin with QEI. |
| 26 | pub struct QeiPin<'d, T, Channel> { | ||
| 21 | _pin: PeripheralRef<'d, AnyPin>, | 27 | _pin: PeripheralRef<'d, AnyPin>, |
| 22 | phantom: PhantomData<(Perip, Channel)>, | 28 | phantom: PhantomData<(T, Channel)>, |
| 23 | } | 29 | } |
| 24 | 30 | ||
| 25 | macro_rules! channel_impl { | 31 | macro_rules! channel_impl { |
| 26 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | 32 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { |
| 27 | impl<'d, Perip: CaptureCompare16bitInstance> QeiPin<'d, Perip, $channel> { | 33 | impl<'d, T: CaptureCompare16bitInstance> QeiPin<'d, T, $channel> { |
| 28 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self { | 34 | #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")] |
| 35 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self { | ||
| 29 | into_ref!(pin); | 36 | into_ref!(pin); |
| 30 | critical_section::with(|_| { | 37 | critical_section::with(|_| { |
| 31 | pin.set_low(); | 38 | pin.set_low(); |
| @@ -45,11 +52,13 @@ macro_rules! channel_impl { | |||
| 45 | channel_impl!(new_ch1, Ch1, Channel1Pin); | 52 | channel_impl!(new_ch1, Ch1, Channel1Pin); |
| 46 | channel_impl!(new_ch2, Ch2, Channel2Pin); | 53 | channel_impl!(new_ch2, Ch2, Channel2Pin); |
| 47 | 54 | ||
| 55 | /// Quadrature decoder driver. | ||
| 48 | pub struct Qei<'d, T> { | 56 | pub struct Qei<'d, T> { |
| 49 | _inner: PeripheralRef<'d, T>, | 57 | _inner: PeripheralRef<'d, T>, |
| 50 | } | 58 | } |
| 51 | 59 | ||
| 52 | impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { | 60 | impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { |
| 61 | /// Create a new quadrature decoder driver. | ||
| 53 | pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { | 62 | pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { |
| 54 | Self::new_inner(tim) | 63 | Self::new_inner(tim) |
| 55 | } | 64 | } |
| @@ -84,6 +93,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { | |||
| 84 | Self { _inner: tim } | 93 | Self { _inner: tim } |
| 85 | } | 94 | } |
| 86 | 95 | ||
| 96 | /// Get direction. | ||
| 87 | pub fn read_direction(&self) -> Direction { | 97 | pub fn read_direction(&self) -> Direction { |
| 88 | match T::regs_gp16().cr1().read().dir() { | 98 | match T::regs_gp16().cr1().read().dir() { |
| 89 | vals::Dir::DOWN => Direction::Downcounting, | 99 | vals::Dir::DOWN => Direction::Downcounting, |
| @@ -91,6 +101,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { | |||
| 91 | } | 101 | } |
| 92 | } | 102 | } |
| 93 | 103 | ||
| 104 | /// Get count. | ||
| 94 | pub fn count(&self) -> u16 { | 105 | pub fn count(&self) -> u16 { |
| 95 | T::regs_gp16().cnt().read().cnt() | 106 | T::regs_gp16().cnt().read().cnt() |
| 96 | } | 107 | } |
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 234bbaff0..e6072aa15 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs | |||
| @@ -11,20 +11,28 @@ use crate::gpio::{AnyPin, OutputType}; | |||
| 11 | use crate::time::Hertz; | 11 | use crate::time::Hertz; |
| 12 | use crate::Peripheral; | 12 | use crate::Peripheral; |
| 13 | 13 | ||
| 14 | pub struct Ch1; | 14 | /// Channel 1 marker type. |
| 15 | pub struct Ch2; | 15 | pub enum Ch1 {} |
| 16 | pub struct Ch3; | 16 | /// Channel 2 marker type. |
| 17 | pub struct Ch4; | 17 | pub enum Ch2 {} |
| 18 | 18 | /// Channel 3 marker type. | |
| 19 | pub struct PwmPin<'d, Perip, Channel> { | 19 | pub enum Ch3 {} |
| 20 | /// Channel 4 marker type. | ||
| 21 | pub enum Ch4 {} | ||
| 22 | |||
| 23 | /// PWM pin wrapper. | ||
| 24 | /// | ||
| 25 | /// This wraps a pin to make it usable with PWM. | ||
| 26 | pub struct PwmPin<'d, T, C> { | ||
| 20 | _pin: PeripheralRef<'d, AnyPin>, | 27 | _pin: PeripheralRef<'d, AnyPin>, |
| 21 | phantom: PhantomData<(Perip, Channel)>, | 28 | phantom: PhantomData<(T, C)>, |
| 22 | } | 29 | } |
| 23 | 30 | ||
| 24 | macro_rules! channel_impl { | 31 | macro_rules! channel_impl { |
| 25 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | 32 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { |
| 26 | impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { | 33 | impl<'d, T: CaptureCompare16bitInstance> PwmPin<'d, T, $channel> { |
| 27 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd, output_type: OutputType) -> Self { | 34 | #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] |
| 35 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self { | ||
| 28 | into_ref!(pin); | 36 | into_ref!(pin); |
| 29 | critical_section::with(|_| { | 37 | critical_section::with(|_| { |
| 30 | pin.set_low(); | 38 | pin.set_low(); |
| @@ -46,11 +54,13 @@ channel_impl!(new_ch2, Ch2, Channel2Pin); | |||
| 46 | channel_impl!(new_ch3, Ch3, Channel3Pin); | 54 | channel_impl!(new_ch3, Ch3, Channel3Pin); |
| 47 | channel_impl!(new_ch4, Ch4, Channel4Pin); | 55 | channel_impl!(new_ch4, Ch4, Channel4Pin); |
| 48 | 56 | ||
| 57 | /// Simple PWM driver. | ||
| 49 | pub struct SimplePwm<'d, T> { | 58 | pub struct SimplePwm<'d, T> { |
| 50 | inner: PeripheralRef<'d, T>, | 59 | inner: PeripheralRef<'d, T>, |
| 51 | } | 60 | } |
| 52 | 61 | ||
| 53 | impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | 62 | impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { |
| 63 | /// Create a new simple PWM driver. | ||
| 54 | pub fn new( | 64 | pub fn new( |
| 55 | tim: impl Peripheral<P = T> + 'd, | 65 | tim: impl Peripheral<P = T> + 'd, |
| 56 | _ch1: Option<PwmPin<'d, T, Ch1>>, | 66 | _ch1: Option<PwmPin<'d, T, Ch1>>, |
| @@ -71,7 +81,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 71 | let mut this = Self { inner: tim }; | 81 | let mut this = Self { inner: tim }; |
| 72 | 82 | ||
| 73 | this.inner.set_counting_mode(counting_mode); | 83 | this.inner.set_counting_mode(counting_mode); |
| 74 | this.set_freq(freq); | 84 | this.set_frequency(freq); |
| 75 | this.inner.start(); | 85 | this.inner.start(); |
| 76 | 86 | ||
| 77 | this.inner.enable_outputs(); | 87 | this.inner.enable_outputs(); |
| @@ -87,15 +97,21 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 87 | this | 97 | this |
| 88 | } | 98 | } |
| 89 | 99 | ||
| 100 | /// Enable the given channel. | ||
| 90 | pub fn enable(&mut self, channel: Channel) { | 101 | pub fn enable(&mut self, channel: Channel) { |
| 91 | self.inner.enable_channel(channel, true); | 102 | self.inner.enable_channel(channel, true); |
| 92 | } | 103 | } |
| 93 | 104 | ||
| 105 | /// Disable the given channel. | ||
| 94 | pub fn disable(&mut self, channel: Channel) { | 106 | pub fn disable(&mut self, channel: Channel) { |
| 95 | self.inner.enable_channel(channel, false); | 107 | self.inner.enable_channel(channel, false); |
| 96 | } | 108 | } |
| 97 | 109 | ||
| 98 | pub fn set_freq(&mut self, freq: Hertz) { | 110 | /// Set PWM frequency. |
| 111 | /// | ||
| 112 | /// Note: when you call this, the max duty value changes, so you will have to | ||
| 113 | /// call `set_duty` on all channels with the duty calculated based on the new max duty. | ||
| 114 | pub fn set_frequency(&mut self, freq: Hertz) { | ||
| 99 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { | 115 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { |
| 100 | 2u8 | 116 | 2u8 |
| 101 | } else { | 117 | } else { |
| @@ -104,15 +120,22 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 104 | self.inner.set_frequency(freq * multiplier); | 120 | self.inner.set_frequency(freq * multiplier); |
| 105 | } | 121 | } |
| 106 | 122 | ||
| 123 | /// Get max duty value. | ||
| 124 | /// | ||
| 125 | /// This value depends on the configured frequency and the timer's clock rate from RCC. | ||
| 107 | pub fn get_max_duty(&self) -> u16 { | 126 | pub fn get_max_duty(&self) -> u16 { |
| 108 | self.inner.get_max_compare_value() + 1 | 127 | self.inner.get_max_compare_value() + 1 |
| 109 | } | 128 | } |
| 110 | 129 | ||
| 130 | /// Set the duty for a given channel. | ||
| 131 | /// | ||
| 132 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. | ||
| 111 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { | 133 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { |
| 112 | assert!(duty <= self.get_max_duty()); | 134 | assert!(duty <= self.get_max_duty()); |
| 113 | self.inner.set_compare_value(channel, duty) | 135 | self.inner.set_compare_value(channel, duty) |
| 114 | } | 136 | } |
| 115 | 137 | ||
| 138 | /// Set the output polarity for a given channel. | ||
| 116 | pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { | 139 | pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { |
| 117 | self.inner.set_output_polarity(channel, polarity); | 140 | self.inner.set_output_polarity(channel, polarity); |
| 118 | } | 141 | } |
diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs index d0b289462..4debd4e54 100644 --- a/embassy-stm32/src/usb/mod.rs +++ b/embassy-stm32/src/usb/mod.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | //! Universal Serial Bus (USB) | ||
| 2 | |||
| 1 | use crate::interrupt; | 3 | use crate::interrupt; |
| 2 | use crate::rcc::RccPeripheral; | 4 | use crate::rcc::RccPeripheral; |
| 3 | 5 | ||
| @@ -10,7 +12,9 @@ pub(crate) mod sealed { | |||
| 10 | } | 12 | } |
| 11 | } | 13 | } |
| 12 | 14 | ||
| 15 | /// USB instance trait. | ||
| 13 | pub trait Instance: sealed::Instance + RccPeripheral + 'static { | 16 | pub trait Instance: sealed::Instance + RccPeripheral + 'static { |
| 17 | /// Interrupt for this USB instance. | ||
| 14 | type Interrupt: interrupt::typelevel::Interrupt; | 18 | type Interrupt: interrupt::typelevel::Interrupt; |
| 15 | } | 19 | } |
| 16 | 20 | ||
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 295dc9198..a8aebfe1f 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs | |||
| @@ -244,6 +244,7 @@ struct EndpointData { | |||
| 244 | used_out: bool, | 244 | used_out: bool, |
| 245 | } | 245 | } |
| 246 | 246 | ||
| 247 | /// USB driver. | ||
| 247 | pub struct Driver<'d, T: Instance> { | 248 | pub struct Driver<'d, T: Instance> { |
| 248 | phantom: PhantomData<&'d mut T>, | 249 | phantom: PhantomData<&'d mut T>, |
| 249 | alloc: [EndpointData; EP_COUNT], | 250 | alloc: [EndpointData; EP_COUNT], |
| @@ -251,6 +252,7 @@ pub struct Driver<'d, T: Instance> { | |||
| 251 | } | 252 | } |
| 252 | 253 | ||
| 253 | impl<'d, T: Instance> Driver<'d, T> { | 254 | impl<'d, T: Instance> Driver<'d, T> { |
| 255 | /// Create a new USB driver. | ||
| 254 | pub fn new( | 256 | pub fn new( |
| 255 | _usb: impl Peripheral<P = T> + 'd, | 257 | _usb: impl Peripheral<P = T> + 'd, |
| 256 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 258 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| @@ -465,6 +467,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { | |||
| 465 | } | 467 | } |
| 466 | } | 468 | } |
| 467 | 469 | ||
| 470 | /// USB bus. | ||
| 468 | pub struct Bus<'d, T: Instance> { | 471 | pub struct Bus<'d, T: Instance> { |
| 469 | phantom: PhantomData<&'d mut T>, | 472 | phantom: PhantomData<&'d mut T>, |
| 470 | ep_types: [EpType; EP_COUNT - 1], | 473 | ep_types: [EpType; EP_COUNT - 1], |
| @@ -640,6 +643,7 @@ trait Dir { | |||
| 640 | fn waker(i: usize) -> &'static AtomicWaker; | 643 | fn waker(i: usize) -> &'static AtomicWaker; |
| 641 | } | 644 | } |
| 642 | 645 | ||
| 646 | /// Marker type for the "IN" direction. | ||
| 643 | pub enum In {} | 647 | pub enum In {} |
| 644 | impl Dir for In { | 648 | impl Dir for In { |
| 645 | fn dir() -> Direction { | 649 | fn dir() -> Direction { |
| @@ -652,6 +656,7 @@ impl Dir for In { | |||
| 652 | } | 656 | } |
| 653 | } | 657 | } |
| 654 | 658 | ||
| 659 | /// Marker type for the "OUT" direction. | ||
| 655 | pub enum Out {} | 660 | pub enum Out {} |
| 656 | impl Dir for Out { | 661 | impl Dir for Out { |
| 657 | fn dir() -> Direction { | 662 | fn dir() -> Direction { |
| @@ -664,6 +669,7 @@ impl Dir for Out { | |||
| 664 | } | 669 | } |
| 665 | } | 670 | } |
| 666 | 671 | ||
| 672 | /// USB endpoint. | ||
| 667 | pub struct Endpoint<'d, T: Instance, D> { | 673 | pub struct Endpoint<'d, T: Instance, D> { |
| 668 | _phantom: PhantomData<(&'d mut T, D)>, | 674 | _phantom: PhantomData<(&'d mut T, D)>, |
| 669 | info: EndpointInfo, | 675 | info: EndpointInfo, |
| @@ -813,6 +819,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 813 | } | 819 | } |
| 814 | } | 820 | } |
| 815 | 821 | ||
| 822 | /// USB control pipe. | ||
| 816 | pub struct ControlPipe<'d, T: Instance> { | 823 | pub struct ControlPipe<'d, T: Instance> { |
| 817 | _phantom: PhantomData<&'d mut T>, | 824 | _phantom: PhantomData<&'d mut T>, |
| 818 | max_packet_size: u16, | 825 | max_packet_size: u16, |
diff --git a/embassy-stm32/src/usb_otg/mod.rs b/embassy-stm32/src/usb_otg/mod.rs index 1abd031dd..0649e684b 100644 --- a/embassy-stm32/src/usb_otg/mod.rs +++ b/embassy-stm32/src/usb_otg/mod.rs | |||
| @@ -20,7 +20,9 @@ pub(crate) mod sealed { | |||
| 20 | } | 20 | } |
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | /// USB OTG instance. | ||
| 23 | pub trait Instance: sealed::Instance + RccPeripheral { | 24 | pub trait Instance: sealed::Instance + RccPeripheral { |
| 25 | /// Interrupt for this USB OTG instance. | ||
| 24 | type Interrupt: interrupt::typelevel::Interrupt; | 26 | type Interrupt: interrupt::typelevel::Interrupt; |
| 25 | } | 27 | } |
| 26 | 28 | ||
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs index ba77bfb16..190fb274f 100644 --- a/embassy-stm32/src/usb_otg/usb.rs +++ b/embassy-stm32/src/usb_otg/usb.rs | |||
| @@ -204,6 +204,7 @@ pub enum PhyType { | |||
| 204 | } | 204 | } |
| 205 | 205 | ||
| 206 | impl PhyType { | 206 | impl PhyType { |
| 207 | /// Get whether this PHY is any of the internal types. | ||
| 207 | pub fn internal(&self) -> bool { | 208 | pub fn internal(&self) -> bool { |
| 208 | match self { | 209 | match self { |
| 209 | PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true, | 210 | PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true, |
| @@ -211,6 +212,7 @@ impl PhyType { | |||
| 211 | } | 212 | } |
| 212 | } | 213 | } |
| 213 | 214 | ||
| 215 | /// Get whether this PHY is any of the high-speed types. | ||
| 214 | pub fn high_speed(&self) -> bool { | 216 | pub fn high_speed(&self) -> bool { |
| 215 | match self { | 217 | match self { |
| 216 | PhyType::InternalFullSpeed => false, | 218 | PhyType::InternalFullSpeed => false, |
| @@ -218,7 +220,7 @@ impl PhyType { | |||
| 218 | } | 220 | } |
| 219 | } | 221 | } |
| 220 | 222 | ||
| 221 | pub fn to_dspd(&self) -> vals::Dspd { | 223 | fn to_dspd(&self) -> vals::Dspd { |
| 222 | match self { | 224 | match self { |
| 223 | PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL, | 225 | PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL, |
| 224 | PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED, | 226 | PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED, |
| @@ -230,6 +232,7 @@ impl PhyType { | |||
| 230 | /// Indicates that [State::ep_out_buffers] is empty. | 232 | /// Indicates that [State::ep_out_buffers] is empty. |
| 231 | const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX; | 233 | const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX; |
| 232 | 234 | ||
| 235 | /// USB OTG driver state. | ||
| 233 | pub struct State<const EP_COUNT: usize> { | 236 | pub struct State<const EP_COUNT: usize> { |
| 234 | /// Holds received SETUP packets. Available if [State::ep0_setup_ready] is true. | 237 | /// Holds received SETUP packets. Available if [State::ep0_setup_ready] is true. |
| 235 | ep0_setup_data: UnsafeCell<[u8; 8]>, | 238 | ep0_setup_data: UnsafeCell<[u8; 8]>, |
| @@ -247,6 +250,7 @@ unsafe impl<const EP_COUNT: usize> Send for State<EP_COUNT> {} | |||
| 247 | unsafe impl<const EP_COUNT: usize> Sync for State<EP_COUNT> {} | 250 | unsafe impl<const EP_COUNT: usize> Sync for State<EP_COUNT> {} |
| 248 | 251 | ||
| 249 | impl<const EP_COUNT: usize> State<EP_COUNT> { | 252 | impl<const EP_COUNT: usize> State<EP_COUNT> { |
| 253 | /// Create a new State. | ||
| 250 | pub const fn new() -> Self { | 254 | pub const fn new() -> Self { |
| 251 | const NEW_AW: AtomicWaker = AtomicWaker::new(); | 255 | const NEW_AW: AtomicWaker = AtomicWaker::new(); |
| 252 | const NEW_BUF: UnsafeCell<*mut u8> = UnsafeCell::new(0 as _); | 256 | const NEW_BUF: UnsafeCell<*mut u8> = UnsafeCell::new(0 as _); |
| @@ -271,6 +275,7 @@ struct EndpointData { | |||
| 271 | fifo_size_words: u16, | 275 | fifo_size_words: u16, |
| 272 | } | 276 | } |
| 273 | 277 | ||
| 278 | /// USB driver config. | ||
| 274 | #[non_exhaustive] | 279 | #[non_exhaustive] |
| 275 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 280 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| 276 | pub struct Config { | 281 | pub struct Config { |
| @@ -297,6 +302,7 @@ impl Default for Config { | |||
| 297 | } | 302 | } |
| 298 | } | 303 | } |
| 299 | 304 | ||
| 305 | /// USB driver. | ||
| 300 | pub struct Driver<'d, T: Instance> { | 306 | pub struct Driver<'d, T: Instance> { |
| 301 | config: Config, | 307 | config: Config, |
| 302 | phantom: PhantomData<&'d mut T>, | 308 | phantom: PhantomData<&'d mut T>, |
| @@ -527,6 +533,7 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> { | |||
| 527 | } | 533 | } |
| 528 | } | 534 | } |
| 529 | 535 | ||
| 536 | /// USB bus. | ||
| 530 | pub struct Bus<'d, T: Instance> { | 537 | pub struct Bus<'d, T: Instance> { |
| 531 | config: Config, | 538 | config: Config, |
| 532 | phantom: PhantomData<&'d mut T>, | 539 | phantom: PhantomData<&'d mut T>, |
| @@ -1092,6 +1099,7 @@ trait Dir { | |||
| 1092 | fn dir() -> Direction; | 1099 | fn dir() -> Direction; |
| 1093 | } | 1100 | } |
| 1094 | 1101 | ||
| 1102 | /// Marker type for the "IN" direction. | ||
| 1095 | pub enum In {} | 1103 | pub enum In {} |
| 1096 | impl Dir for In { | 1104 | impl Dir for In { |
| 1097 | fn dir() -> Direction { | 1105 | fn dir() -> Direction { |
| @@ -1099,6 +1107,7 @@ impl Dir for In { | |||
| 1099 | } | 1107 | } |
| 1100 | } | 1108 | } |
| 1101 | 1109 | ||
| 1110 | /// Marker type for the "OUT" direction. | ||
| 1102 | pub enum Out {} | 1111 | pub enum Out {} |
| 1103 | impl Dir for Out { | 1112 | impl Dir for Out { |
| 1104 | fn dir() -> Direction { | 1113 | fn dir() -> Direction { |
| @@ -1106,6 +1115,7 @@ impl Dir for Out { | |||
| 1106 | } | 1115 | } |
| 1107 | } | 1116 | } |
| 1108 | 1117 | ||
| 1118 | /// USB endpoint. | ||
| 1109 | pub struct Endpoint<'d, T: Instance, D> { | 1119 | pub struct Endpoint<'d, T: Instance, D> { |
| 1110 | _phantom: PhantomData<(&'d mut T, D)>, | 1120 | _phantom: PhantomData<(&'d mut T, D)>, |
| 1111 | info: EndpointInfo, | 1121 | info: EndpointInfo, |
| @@ -1299,6 +1309,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 1299 | } | 1309 | } |
| 1300 | } | 1310 | } |
| 1301 | 1311 | ||
| 1312 | /// USB control pipe. | ||
| 1302 | pub struct ControlPipe<'d, T: Instance> { | 1313 | pub struct ControlPipe<'d, T: Instance> { |
| 1303 | _phantom: PhantomData<&'d mut T>, | 1314 | _phantom: PhantomData<&'d mut T>, |
| 1304 | max_packet_size: u16, | 1315 | max_packet_size: u16, |
diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs index 5751a9ff3..dc701ef64 100644 --- a/embassy-stm32/src/wdg/mod.rs +++ b/embassy-stm32/src/wdg/mod.rs | |||
| @@ -6,6 +6,7 @@ use stm32_metapac::iwdg::vals::{Key, Pr}; | |||
| 6 | 6 | ||
| 7 | use crate::rcc::LSI_FREQ; | 7 | use crate::rcc::LSI_FREQ; |
| 8 | 8 | ||
| 9 | /// Independent watchdog (IWDG) driver. | ||
| 9 | pub struct IndependentWatchdog<'d, T: Instance> { | 10 | pub struct IndependentWatchdog<'d, T: Instance> { |
| 10 | wdg: PhantomData<&'d mut T>, | 11 | wdg: PhantomData<&'d mut T>, |
| 11 | } | 12 | } |
| @@ -64,10 +65,12 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> { | |||
| 64 | IndependentWatchdog { wdg: PhantomData } | 65 | IndependentWatchdog { wdg: PhantomData } |
| 65 | } | 66 | } |
| 66 | 67 | ||
| 68 | /// Unleash (start) the watchdog. | ||
| 67 | pub fn unleash(&mut self) { | 69 | pub fn unleash(&mut self) { |
| 68 | T::regs().kr().write(|w| w.set_key(Key::START)); | 70 | T::regs().kr().write(|w| w.set_key(Key::START)); |
| 69 | } | 71 | } |
| 70 | 72 | ||
| 73 | /// Pet (reload, refresh) the watchdog. | ||
| 71 | pub fn pet(&mut self) { | 74 | pub fn pet(&mut self) { |
| 72 | T::regs().kr().write(|w| w.set_key(Key::RESET)); | 75 | T::regs().kr().write(|w| w.set_key(Key::RESET)); |
| 73 | } | 76 | } |
| @@ -79,6 +82,7 @@ mod sealed { | |||
| 79 | } | 82 | } |
| 80 | } | 83 | } |
| 81 | 84 | ||
| 85 | /// IWDG instance trait. | ||
| 82 | pub trait Instance: sealed::Instance {} | 86 | pub trait Instance: sealed::Instance {} |
| 83 | 87 | ||
| 84 | foreach_peripheral!( | 88 | foreach_peripheral!( |
diff --git a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs index 52cc665c7..39f5d3421 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs | |||
| @@ -110,7 +110,7 @@ async fn main(_spawner: Spawner) { | |||
| 110 | &mut dp.DMA1_CH2, | 110 | &mut dp.DMA1_CH2, |
| 111 | 5, | 111 | 5, |
| 112 | color_list[color_list_index], | 112 | color_list[color_list_index], |
| 113 | pac::TIM3.ccr(pwm_channel.raw()).as_ptr() as *mut _, | 113 | pac::TIM3.ccr(pwm_channel.index()).as_ptr() as *mut _, |
| 114 | dma_transfer_option, | 114 | dma_transfer_option, |
| 115 | ) | 115 | ) |
| 116 | .await; | 116 | .await; |
diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index e0be495d1..394ed3281 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs | |||
| @@ -85,7 +85,7 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { | |||
| 85 | 85 | ||
| 86 | let mut this = Self { inner: tim }; | 86 | let mut this = Self { inner: tim }; |
| 87 | 87 | ||
| 88 | this.set_freq(freq); | 88 | this.set_frequency(freq); |
| 89 | this.inner.start(); | 89 | this.inner.start(); |
| 90 | 90 | ||
| 91 | let r = T::regs_gp32(); | 91 | let r = T::regs_gp32(); |
| @@ -102,14 +102,14 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { | |||
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | pub fn enable(&mut self, channel: Channel) { | 104 | pub fn enable(&mut self, channel: Channel) { |
| 105 | T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), true)); | 105 | T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), true)); |
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | pub fn disable(&mut self, channel: Channel) { | 108 | pub fn disable(&mut self, channel: Channel) { |
| 109 | T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), false)); | 109 | T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), false)); |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | pub fn set_freq(&mut self, freq: Hertz) { | 112 | pub fn set_frequency(&mut self, freq: Hertz) { |
| 113 | <T as embassy_stm32::timer::low_level::GeneralPurpose32bitInstance>::set_frequency(&mut self.inner, freq); | 113 | <T as embassy_stm32::timer::low_level::GeneralPurpose32bitInstance>::set_frequency(&mut self.inner, freq); |
| 114 | } | 114 | } |
| 115 | 115 | ||
| @@ -119,6 +119,6 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { | |||
| 119 | 119 | ||
| 120 | pub fn set_duty(&mut self, channel: Channel, duty: u32) { | 120 | pub fn set_duty(&mut self, channel: Channel, duty: u32) { |
| 121 | defmt::assert!(duty < self.get_max_duty()); | 121 | defmt::assert!(duty < self.get_max_duty()); |
| 122 | T::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(duty)) | 122 | T::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(duty)) |
| 123 | } | 123 | } |
| 124 | } | 124 | } |
