diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 33985a3f4..511eb6d37 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -1017,6 +1017,7 @@ fn main() {
(("hrtim", "CHF2"), quote!(crate::hrtim::ChannelFComplementaryPin)),
(("lptim", "CH1"), quote!(crate::lptim::Channel1Pin)),
(("lptim", "CH2"), quote!(crate::lptim::Channel1Pin)),
+ (("lptim", "OUT"), quote!(crate::lptim::OutputPin)),
(("sdmmc", "CK"), quote!(crate::sdmmc::CkPin)),
(("sdmmc", "CMD"), quote!(crate::sdmmc::CmdPin)),
(("sdmmc", "D0"), quote!(crate::sdmmc::D0Pin)),
diff --git a/embassy-stm32/src/lptim/channel.rs b/embassy-stm32/src/lptim/channel.rs
new file mode 100644
index 000000000..17fc2fb86
--- /dev/null
+++ b/embassy-stm32/src/lptim/channel.rs
@@ -0,0 +1,18 @@
+/// Timer channel.
+#[derive(Clone, Copy)]
+pub enum Channel {
+ /// Channel 1.
+ Ch1,
+ /// Channel 2.
+ Ch2,
+}
+
+impl Channel {
+ /// Get the channel index (0..1)
+ pub fn index(&self) -> usize {
+ match self {
+ Channel::Ch1 => 0,
+ Channel::Ch2 => 1,
+ }
+ }
+}
diff --git a/embassy-stm32/src/lptim/mod.rs b/embassy-stm32/src/lptim/mod.rs
index dc5f1d5bb..9c10efa43 100644
--- a/embassy-stm32/src/lptim/mod.rs
+++ b/embassy-stm32/src/lptim/mod.rs
@@ -6,24 +6,12 @@ pub mod timer;
use crate::rcc::RccPeripheral;
/// Timer channel.
-#[derive(Clone, Copy)]
-pub enum Channel {
- /// Channel 1.
- Ch1,
- /// Channel 2.
- Ch2,
-}
-
-impl Channel {
- /// Get the channel index (0..1)
- pub fn index(&self) -> usize {
- match self {
- Channel::Ch1 => 0,
- Channel::Ch2 => 1,
- }
- }
-}
+#[cfg(any(lptim_v2a, lptim_v2b))]
+mod channel;
+#[cfg(any(lptim_v2a, lptim_v2b))]
+pub use channel::Channel;
+pin_trait!(OutputPin, Instance);
pin_trait!(Channel1Pin, Instance);
pin_trait!(Channel2Pin, Instance);
diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs
index 24725f625..586148848 100644
--- a/embassy-stm32/src/lptim/pwm.rs
+++ b/embassy-stm32/src/lptim/pwm.rs
@@ -4,12 +4,18 @@ use core::marker::PhantomData;
use embassy_hal_internal::{into_ref, PeripheralRef};
-use super::timer::{ChannelDirection, Timer};
-use super::{Channel, Channel1Pin, Channel2Pin, Instance};
+use super::timer::Timer;
+use super::Instance;
+#[cfg(not(any(lptim_v2a, lptim_v2b)))]
+use super::OutputPin;
+#[cfg(any(lptim_v2a, lptim_v2b))]
+use super::{channel::Channel, timer::ChannelDirection, Channel1Pin, Channel2Pin};
use crate::gpio::{AfType, AnyPin, OutputType, Speed};
use crate::time::Hertz;
use crate::Peripheral;
+/// Output marker type.
+pub enum Output {}
/// Channel 1 marker type.
pub enum Ch1 {}
/// Channel 2 marker type.
@@ -45,14 +51,44 @@ macro_rules! channel_impl {
};
}
+#[cfg(not(any(lptim_v2a, lptim_v2b)))]
+channel_impl!(new, Output, OutputPin);
+#[cfg(any(lptim_v2a, lptim_v2b))]
channel_impl!(new_ch1, Ch1, Channel1Pin);
+#[cfg(any(lptim_v2a, lptim_v2b))]
channel_impl!(new_ch2, Ch2, Channel2Pin);
/// PWM driver.
pub struct Pwm<'d, T: Instance> {
- inner: Timer<'d, T>, // _inner: PeripheralRef<'d, T>,
+ inner: Timer<'d, T>,
}
+#[cfg(not(any(lptim_v2a, lptim_v2b)))]
+impl<'d, T: Instance> Pwm<'d, T> {
+ /// Create a new PWM driver.
+ pub fn new(tim: impl Peripheral
+ 'd, _output_pin: PwmPin<'d, T, Output>, freq: Hertz) -> Self {
+ Self::new_inner(tim, freq)
+ }
+
+ /// Set the duty.
+ ///
+ /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
+ pub fn set_duty(&mut self, duty: u16) {
+ assert!(duty <= self.get_max_duty());
+ self.inner.set_compare_value(duty)
+ }
+
+ /// Get the duty.
+ ///
+ /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
+ pub fn get_duty(&self) -> u16 {
+ self.inner.get_compare_value()
+ }
+
+ fn post_init(&mut self) {}
+}
+
+#[cfg(any(lptim_v2a, lptim_v2b))]
impl<'d, T: Instance> Pwm<'d, T> {
/// Create a new PWM driver.
pub fn new(
@@ -61,19 +97,7 @@ impl<'d, T: Instance> Pwm<'d, T> {
_ch2_pin: Option>,
freq: Hertz,
) -> Self {
- let mut this = Self { inner: Timer::new(tim) };
-
- this.inner.enable();
- this.set_frequency(freq);
-
- #[cfg(any(lptim_v2a, lptim_v2b))]
- [Channel::Ch1, Channel::Ch2].iter().for_each(|&channel| {
- this.inner.set_channel_direction(channel, ChannelDirection::OutputPwm);
- });
-
- this.inner.continuous_mode_start();
-
- this
+ Self::new_inner(tim, freq)
}
/// Enable the given channel.
@@ -91,21 +115,6 @@ impl<'d, T: Instance> Pwm<'d, T> {
self.inner.get_channel_enable_state(channel)
}
- /// Set PWM frequency.
- ///
- /// Note: when you call this, the max duty value changes, so you will have to
- /// call `set_duty` on all channels with the duty calculated based on the new max duty.
- pub fn set_frequency(&mut self, frequency: Hertz) {
- self.inner.set_frequency(frequency);
- }
-
- /// Get max duty value.
- ///
- /// This value depends on the configured frequency and the timer's clock rate from RCC.
- pub fn get_max_duty(&self) -> u16 {
- self.inner.get_max_compare_value() + 1
- }
-
/// Set the duty for a given channel.
///
/// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
@@ -120,4 +129,40 @@ impl<'d, T: Instance> Pwm<'d, T> {
pub fn get_duty(&self, channel: Channel) -> u16 {
self.inner.get_compare_value(channel)
}
+
+ fn post_init(&mut self) {
+ [Channel::Ch1, Channel::Ch2].iter().for_each(|&channel| {
+ self.inner.set_channel_direction(channel, ChannelDirection::OutputPwm);
+ });
+ }
+}
+
+impl<'d, T: Instance> Pwm<'d, T> {
+ fn new_inner(tim: impl Peripheral + 'd, freq: Hertz) -> Self {
+ let mut this = Self { inner: Timer::new(tim) };
+
+ this.inner.enable();
+ this.set_frequency(freq);
+
+ this.post_init();
+
+ this.inner.continuous_mode_start();
+
+ this
+ }
+
+ /// Set PWM frequency.
+ ///
+ /// Note: when you call this, the max duty value changes, so you will have to
+ /// call `set_duty` on all channels with the duty calculated based on the new max duty.
+ pub fn set_frequency(&mut self, frequency: Hertz) {
+ self.inner.set_frequency(frequency);
+ }
+
+ /// Get max duty value.
+ ///
+ /// This value depends on the configured frequency and the timer's clock rate from RCC.
+ pub fn get_max_duty(&self) -> u16 {
+ self.inner.get_max_compare_value() + 1
+ }
}
diff --git a/embassy-stm32/src/lptim/timer/channel_direction.rs b/embassy-stm32/src/lptim/timer/channel_direction.rs
new file mode 100644
index 000000000..a38df63cd
--- /dev/null
+++ b/embassy-stm32/src/lptim/timer/channel_direction.rs
@@ -0,0 +1,18 @@
+use crate::pac::lptim::vals;
+
+/// Direction of a low-power timer channel
+pub enum ChannelDirection {
+ /// Use channel as a PWM output
+ OutputPwm,
+ /// Use channel as an input capture
+ InputCapture,
+}
+
+impl From for vals::Ccsel {
+ fn from(direction: ChannelDirection) -> Self {
+ match direction {
+ ChannelDirection::OutputPwm => vals::Ccsel::OUTPUTCOMPARE,
+ ChannelDirection::InputCapture => vals::Ccsel::INPUTCAPTURE,
+ }
+ }
+}
diff --git a/embassy-stm32/src/lptim/timer.rs b/embassy-stm32/src/lptim/timer/mod.rs
similarity index 53%
rename from embassy-stm32/src/lptim/timer.rs
rename to embassy-stm32/src/lptim/timer/mod.rs
index b354c1f61..e62fcab49 100644
--- a/embassy-stm32/src/lptim/timer.rs
+++ b/embassy-stm32/src/lptim/timer/mod.rs
@@ -1,118 +1,20 @@
//! Low-level timer driver.
+mod prescaler;
use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
-use super::{Channel, Instance};
-use crate::pac::lptim::vals;
+#[cfg(any(lptim_v2a, lptim_v2b))]
+use super::channel::Channel;
+#[cfg(any(lptim_v2a, lptim_v2b))]
+mod channel_direction;
+#[cfg(any(lptim_v2a, lptim_v2b))]
+pub use channel_direction::ChannelDirection;
+use prescaler::Prescaler;
+
+use super::Instance;
use crate::rcc;
use crate::time::Hertz;
-/// Direction of a low-power timer channel
-#[cfg(any(lptim_v2a, lptim_v2b))]
-pub enum ChannelDirection {
- /// Use channel as a PWM output
- OutputPwm,
- /// Use channel as an input capture
- InputCapture,
-}
-
-#[cfg(any(lptim_v2a, lptim_v2b))]
-impl From for vals::Ccsel {
- fn from(direction: ChannelDirection) -> Self {
- match direction {
- ChannelDirection::OutputPwm => vals::Ccsel::OUTPUTCOMPARE,
- ChannelDirection::InputCapture => vals::Ccsel::INPUTCAPTURE,
- }
- }
-}
-
-enum Prescaler {
- Div1,
- Div2,
- Div4,
- Div8,
- Div16,
- Div32,
- Div64,
- Div128,
-}
-
-impl From<&Prescaler> for vals::Presc {
- fn from(prescaler: &Prescaler) -> Self {
- match prescaler {
- Prescaler::Div1 => vals::Presc::DIV1,
- Prescaler::Div2 => vals::Presc::DIV2,
- Prescaler::Div4 => vals::Presc::DIV4,
- Prescaler::Div8 => vals::Presc::DIV8,
- Prescaler::Div16 => vals::Presc::DIV16,
- Prescaler::Div32 => vals::Presc::DIV32,
- Prescaler::Div64 => vals::Presc::DIV64,
- Prescaler::Div128 => vals::Presc::DIV128,
- }
- }
-}
-
-impl From for Prescaler {
- fn from(prescaler: vals::Presc) -> Self {
- match prescaler {
- vals::Presc::DIV1 => Prescaler::Div1,
- vals::Presc::DIV2 => Prescaler::Div2,
- vals::Presc::DIV4 => Prescaler::Div4,
- vals::Presc::DIV8 => Prescaler::Div8,
- vals::Presc::DIV16 => Prescaler::Div16,
- vals::Presc::DIV32 => Prescaler::Div32,
- vals::Presc::DIV64 => Prescaler::Div64,
- vals::Presc::DIV128 => Prescaler::Div128,
- }
- }
-}
-
-impl From<&Prescaler> for u32 {
- fn from(prescaler: &Prescaler) -> Self {
- match prescaler {
- Prescaler::Div1 => 1,
- Prescaler::Div2 => 2,
- Prescaler::Div4 => 4,
- Prescaler::Div8 => 8,
- Prescaler::Div16 => 16,
- Prescaler::Div32 => 32,
- Prescaler::Div64 => 64,
- Prescaler::Div128 => 128,
- }
- }
-}
-
-impl From for Prescaler {
- fn from(prescaler: u32) -> Self {
- match prescaler {
- 1 => Prescaler::Div1,
- 2 => Prescaler::Div2,
- 4 => Prescaler::Div4,
- 8 => Prescaler::Div8,
- 16 => Prescaler::Div16,
- 32 => Prescaler::Div32,
- 64 => Prescaler::Div64,
- 128 => Prescaler::Div128,
- _ => unreachable!(),
- }
- }
-}
-
-impl Prescaler {
- pub fn from_ticks(ticks: u32) -> Self {
- // We need to scale down to a 16-bit range
- (ticks >> 16).next_power_of_two().into()
- }
-
- pub fn scale_down(&self, ticks: u32) -> u16 {
- (ticks / u32::from(self)).try_into().unwrap()
- }
-
- pub fn scale_up(&self, ticks: u16) -> u32 {
- u32::from(self) * ticks as u32
- }
-}
-
/// Low-level timer driver.
pub struct Timer<'d, T: Instance> {
_tim: PeripheralRef<'d, T>,
@@ -148,14 +50,6 @@ impl<'d, T: Instance> Timer<'d, T> {
T::regs().cr().modify(|w| w.set_cntstrt(true));
}
- /// Set channel direction.
- #[cfg(any(lptim_v2a, lptim_v2b))]
- pub fn set_channel_direction(&self, channel: Channel, direction: ChannelDirection) {
- T::regs()
- .ccmr(0)
- .modify(|w| w.set_ccsel(channel.index(), direction.into()));
- }
-
/// Set the frequency of how many times per second the timer counts up to the max value or down to 0.
pub fn set_frequency(&self, frequency: Hertz) {
let f = frequency.0;
@@ -186,6 +80,14 @@ impl<'d, T: Instance> Timer<'d, T> {
T::frequency()
}
+ /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
+ pub fn get_max_compare_value(&self) -> u16 {
+ T::regs().arr().read().arr()
+ }
+}
+
+#[cfg(any(lptim_v2a, lptim_v2b))]
+impl<'d, T: Instance> Timer<'d, T> {
/// Enable/disable a channel.
pub fn enable_channel(&self, channel: Channel, enable: bool) {
T::regs().ccmr(0).modify(|w| {
@@ -208,8 +110,24 @@ impl<'d, T: Instance> Timer<'d, T> {
T::regs().ccr(channel.index()).read().ccr()
}
- /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
- pub fn get_max_compare_value(&self) -> u16 {
- T::regs().arr().read().arr()
+ /// Set channel direction.
+ #[cfg(any(lptim_v2a, lptim_v2b))]
+ pub fn set_channel_direction(&self, channel: Channel, direction: ChannelDirection) {
+ T::regs()
+ .ccmr(0)
+ .modify(|w| w.set_ccsel(channel.index(), direction.into()));
+ }
+}
+
+#[cfg(not(any(lptim_v2a, lptim_v2b)))]
+impl<'d, T: Instance> Timer<'d, T> {
+ /// Set compare value for a channel.
+ pub fn set_compare_value(&self, value: u16) {
+ T::regs().cmp().modify(|w| w.set_cmp(value));
+ }
+
+ /// Get compare value for a channel.
+ pub fn get_compare_value(&self) -> u16 {
+ T::regs().cmp().read().cmp()
}
}
diff --git a/embassy-stm32/src/lptim/timer/prescaler.rs b/embassy-stm32/src/lptim/timer/prescaler.rs
new file mode 100644
index 000000000..5d2326faf
--- /dev/null
+++ b/embassy-stm32/src/lptim/timer/prescaler.rs
@@ -0,0 +1,90 @@
+//! Low-level timer driver.
+
+use crate::pac::lptim::vals;
+
+pub enum Prescaler {
+ Div1,
+ Div2,
+ Div4,
+ Div8,
+ Div16,
+ Div32,
+ Div64,
+ Div128,
+}
+
+impl From<&Prescaler> for vals::Presc {
+ fn from(prescaler: &Prescaler) -> Self {
+ match prescaler {
+ Prescaler::Div1 => vals::Presc::DIV1,
+ Prescaler::Div2 => vals::Presc::DIV2,
+ Prescaler::Div4 => vals::Presc::DIV4,
+ Prescaler::Div8 => vals::Presc::DIV8,
+ Prescaler::Div16 => vals::Presc::DIV16,
+ Prescaler::Div32 => vals::Presc::DIV32,
+ Prescaler::Div64 => vals::Presc::DIV64,
+ Prescaler::Div128 => vals::Presc::DIV128,
+ }
+ }
+}
+
+impl From for Prescaler {
+ fn from(prescaler: vals::Presc) -> Self {
+ match prescaler {
+ vals::Presc::DIV1 => Prescaler::Div1,
+ vals::Presc::DIV2 => Prescaler::Div2,
+ vals::Presc::DIV4 => Prescaler::Div4,
+ vals::Presc::DIV8 => Prescaler::Div8,
+ vals::Presc::DIV16 => Prescaler::Div16,
+ vals::Presc::DIV32 => Prescaler::Div32,
+ vals::Presc::DIV64 => Prescaler::Div64,
+ vals::Presc::DIV128 => Prescaler::Div128,
+ }
+ }
+}
+
+impl From<&Prescaler> for u32 {
+ fn from(prescaler: &Prescaler) -> Self {
+ match prescaler {
+ Prescaler::Div1 => 1,
+ Prescaler::Div2 => 2,
+ Prescaler::Div4 => 4,
+ Prescaler::Div8 => 8,
+ Prescaler::Div16 => 16,
+ Prescaler::Div32 => 32,
+ Prescaler::Div64 => 64,
+ Prescaler::Div128 => 128,
+ }
+ }
+}
+
+impl From for Prescaler {
+ fn from(prescaler: u32) -> Self {
+ match prescaler {
+ 1 => Prescaler::Div1,
+ 2 => Prescaler::Div2,
+ 4 => Prescaler::Div4,
+ 8 => Prescaler::Div8,
+ 16 => Prescaler::Div16,
+ 32 => Prescaler::Div32,
+ 64 => Prescaler::Div64,
+ 128 => Prescaler::Div128,
+ _ => unreachable!(),
+ }
+ }
+}
+
+impl Prescaler {
+ pub fn from_ticks(ticks: u32) -> Self {
+ // We need to scale down to a 16-bit range
+ (ticks >> 16).next_power_of_two().into()
+ }
+
+ pub fn scale_down(&self, ticks: u32) -> u16 {
+ (ticks / u32::from(self)).try_into().unwrap()
+ }
+
+ pub fn scale_up(&self, ticks: u16) -> u32 {
+ u32::from(self) * ticks as u32
+ }
+}