aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/build.rs3
-rw-r--r--embassy-stm32/src/adc/mod.rs16
-rw-r--r--embassy-stm32/src/lib.rs2
-rw-r--r--embassy-stm32/src/lptim/channel.rs18
-rw-r--r--embassy-stm32/src/lptim/mod.rs48
-rw-r--r--embassy-stm32/src/lptim/pwm.rs168
-rw-r--r--embassy-stm32/src/lptim/timer/channel_direction.rs18
-rw-r--r--embassy-stm32/src/lptim/timer/mod.rs133
-rw-r--r--embassy-stm32/src/lptim/timer/prescaler.rs90
10 files changed, 491 insertions, 9 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 9a6a5908e..3c6484c96 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -72,7 +72,7 @@ rand_core = "0.6.3"
72sdio-host = "0.5.0" 72sdio-host = "0.5.0"
73critical-section = "1.1" 73critical-section = "1.1"
74#stm32-metapac = { version = "15" } 74#stm32-metapac = { version = "15" }
75stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5ef354f3e49f790e47f5c818f243459742c9b83b" } 75stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364" }
76 76
77vcell = "0.1.3" 77vcell = "0.1.3"
78nb = "1.0.0" 78nb = "1.0.0"
@@ -99,7 +99,7 @@ proc-macro2 = "1.0.36"
99quote = "1.0.15" 99quote = "1.0.15"
100 100
101#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} 101#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
102stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5ef354f3e49f790e47f5c818f243459742c9b83b", default-features = false, features = ["metadata"] } 102stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364", default-features = false, features = ["metadata"] }
103 103
104[features] 104[features]
105default = ["rt"] 105default = ["rt"]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 1984a1420..19cf193d9 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -1015,6 +1015,9 @@ fn main() {
1015 (("hrtim", "CHE2"), quote!(crate::hrtim::ChannelEComplementaryPin)), 1015 (("hrtim", "CHE2"), quote!(crate::hrtim::ChannelEComplementaryPin)),
1016 (("hrtim", "CHF1"), quote!(crate::hrtim::ChannelFPin)), 1016 (("hrtim", "CHF1"), quote!(crate::hrtim::ChannelFPin)),
1017 (("hrtim", "CHF2"), quote!(crate::hrtim::ChannelFComplementaryPin)), 1017 (("hrtim", "CHF2"), quote!(crate::hrtim::ChannelFComplementaryPin)),
1018 (("lptim", "CH1"), quote!(crate::lptim::Channel1Pin)),
1019 (("lptim", "CH2"), quote!(crate::lptim::Channel2Pin)),
1020 (("lptim", "OUT"), quote!(crate::lptim::OutputPin)),
1018 (("sdmmc", "CK"), quote!(crate::sdmmc::CkPin)), 1021 (("sdmmc", "CK"), quote!(crate::sdmmc::CkPin)),
1019 (("sdmmc", "CMD"), quote!(crate::sdmmc::CmdPin)), 1022 (("sdmmc", "CMD"), quote!(crate::sdmmc::CmdPin)),
1020 (("sdmmc", "D0"), quote!(crate::sdmmc::D0Pin)), 1023 (("sdmmc", "D0"), quote!(crate::sdmmc::D0Pin)),
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 2ac0c0083..4ab82c1d9 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -4,7 +4,7 @@
4#![allow(missing_docs)] // TODO 4#![allow(missing_docs)] // TODO
5#![cfg_attr(adc_f3_v2, allow(unused))] 5#![cfg_attr(adc_f3_v2, allow(unused))]
6 6
7#[cfg(not(adc_f3_v2))] 7#[cfg(not(any(adc_f3_v2, adc_u5)))]
8#[cfg_attr(adc_f1, path = "f1.rs")] 8#[cfg_attr(adc_f1, path = "f1.rs")]
9#[cfg_attr(adc_f3, path = "f3.rs")] 9#[cfg_attr(adc_f3, path = "f3.rs")]
10#[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")] 10#[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")]
@@ -19,14 +19,16 @@ mod _version;
19use core::marker::PhantomData; 19use core::marker::PhantomData;
20 20
21#[allow(unused)] 21#[allow(unused)]
22#[cfg(not(adc_f3_v2))] 22#[cfg(not(any(adc_f3_v2, adc_u5)))]
23pub use _version::*; 23pub use _version::*;
24#[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] 24#[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
25use embassy_sync::waitqueue::AtomicWaker; 25use embassy_sync::waitqueue::AtomicWaker;
26 26
27#[cfg(not(any(adc_u5)))]
27pub use crate::pac::adc::vals; 28pub use crate::pac::adc::vals;
28#[cfg(not(any(adc_f1, adc_f3_v2)))] 29#[cfg(not(any(adc_f1, adc_f3_v2, adc_u5)))]
29pub use crate::pac::adc::vals::Res as Resolution; 30pub use crate::pac::adc::vals::Res as Resolution;
31#[cfg(not(any(adc_u5)))]
30pub use crate::pac::adc::vals::SampleTime; 32pub use crate::pac::adc::vals::SampleTime;
31use crate::peripherals; 33use crate::peripherals;
32 34
@@ -36,7 +38,7 @@ dma_trait!(RxDma, Instance);
36pub struct Adc<'d, T: Instance> { 38pub struct Adc<'d, T: Instance> {
37 #[allow(unused)] 39 #[allow(unused)]
38 adc: crate::PeripheralRef<'d, T>, 40 adc: crate::PeripheralRef<'d, T>,
39 #[cfg(not(any(adc_f3_v2, adc_f3_v1_1)))] 41 #[cfg(not(any(adc_f3_v2, adc_f3_v1_1, adc_u5)))]
40 sample_time: SampleTime, 42 sample_time: SampleTime,
41} 43}
42 44
@@ -57,7 +59,7 @@ impl State {
57trait SealedInstance { 59trait SealedInstance {
58 #[allow(unused)] 60 #[allow(unused)]
59 fn regs() -> crate::pac::adc::Adc; 61 fn regs() -> crate::pac::adc::Adc;
60 #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] 62 #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0, adc_u5)))]
61 #[allow(unused)] 63 #[allow(unused)]
62 fn common_regs() -> crate::pac::adccommon::AdcCommon; 64 fn common_regs() -> crate::pac::adccommon::AdcCommon;
63 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] 65 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
@@ -163,7 +165,7 @@ foreach_adc!(
163 crate::pac::$inst 165 crate::pac::$inst
164 } 166 }
165 167
166 #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] 168 #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0, adc_u5)))]
167 fn common_regs() -> crate::pac::adccommon::AdcCommon { 169 fn common_regs() -> crate::pac::adccommon::AdcCommon {
168 return crate::pac::$common_inst 170 return crate::pac::$common_inst
169 } 171 }
@@ -200,7 +202,7 @@ macro_rules! impl_adc_pin {
200/// Get the maximum reading value for this resolution. 202/// Get the maximum reading value for this resolution.
201/// 203///
202/// This is `2**n - 1`. 204/// This is `2**n - 1`.
203#[cfg(not(any(adc_f1, adc_f3_v2)))] 205#[cfg(not(any(adc_f1, adc_f3_v2, adc_u5)))]
204pub const fn resolution_to_max_count(res: Resolution) -> u32 { 206pub const fn resolution_to_max_count(res: Resolution) -> u32 {
205 match res { 207 match res {
206 #[cfg(adc_v4)] 208 #[cfg(adc_v4)]
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 98695e738..451f595e0 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -89,6 +89,8 @@ pub mod i2s;
89pub mod ipcc; 89pub mod ipcc;
90#[cfg(feature = "low-power")] 90#[cfg(feature = "low-power")]
91pub mod low_power; 91pub mod low_power;
92#[cfg(lptim)]
93pub mod lptim;
92#[cfg(ltdc)] 94#[cfg(ltdc)]
93pub mod ltdc; 95pub mod ltdc;
94#[cfg(opamp)] 96#[cfg(opamp)]
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 @@
1/// Timer channel.
2#[derive(Clone, Copy)]
3pub enum Channel {
4 /// Channel 1.
5 Ch1,
6 /// Channel 2.
7 Ch2,
8}
9
10impl Channel {
11 /// Get the channel index (0..1)
12 pub fn index(&self) -> usize {
13 match self {
14 Channel::Ch1 => 0,
15 Channel::Ch2 => 1,
16 }
17 }
18}
diff --git a/embassy-stm32/src/lptim/mod.rs b/embassy-stm32/src/lptim/mod.rs
new file mode 100644
index 000000000..1649cc5b4
--- /dev/null
+++ b/embassy-stm32/src/lptim/mod.rs
@@ -0,0 +1,48 @@
1//! Low-power timer (LPTIM)
2
3pub mod pwm;
4pub mod timer;
5
6use crate::rcc::RccPeripheral;
7
8/// Timer channel.
9#[cfg(any(lptim_v2a, lptim_v2b))]
10mod channel;
11#[cfg(any(lptim_v2a, lptim_v2b))]
12pub use channel::Channel;
13
14pin_trait!(OutputPin, BasicInstance);
15pin_trait!(Channel1Pin, BasicInstance);
16pin_trait!(Channel2Pin, BasicInstance);
17
18pub(crate) trait SealedInstance: RccPeripheral {
19 fn regs() -> crate::pac::lptim::Lptim;
20}
21pub(crate) trait SealedBasicInstance: RccPeripheral {}
22
23/// LPTIM basic instance trait.
24#[allow(private_bounds)]
25pub trait BasicInstance: SealedBasicInstance + 'static {}
26
27/// LPTIM instance trait.
28#[allow(private_bounds)]
29pub trait Instance: BasicInstance + SealedInstance + 'static {}
30
31foreach_interrupt! {
32 ($inst:ident, lptim, LPTIM, GLOBAL, $irq:ident) => {
33 impl SealedInstance for crate::peripherals::$inst {
34 fn regs() -> crate::pac::lptim::Lptim {
35 crate::pac::$inst
36 }
37 }
38 impl SealedBasicInstance for crate::peripherals::$inst {
39 }
40 impl BasicInstance for crate::peripherals::$inst {}
41 impl Instance for crate::peripherals::$inst {}
42 };
43 ($inst:ident, lptim, LPTIM_BASIC, GLOBAL, $irq:ident) => {
44 impl SealedBasicInstance for crate::peripherals::$inst {
45 }
46 impl BasicInstance for crate::peripherals::$inst {}
47 };
48}
diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs
new file mode 100644
index 000000000..1f43eb6ee
--- /dev/null
+++ b/embassy-stm32/src/lptim/pwm.rs
@@ -0,0 +1,168 @@
1//! PWM driver.
2
3use core::marker::PhantomData;
4
5use embassy_hal_internal::{into_ref, PeripheralRef};
6
7use super::timer::Timer;
8#[cfg(not(any(lptim_v2a, lptim_v2b)))]
9use super::OutputPin;
10#[cfg(any(lptim_v2a, lptim_v2b))]
11use super::{channel::Channel, timer::ChannelDirection, Channel1Pin, Channel2Pin};
12use super::{BasicInstance, Instance};
13use crate::gpio::{AfType, AnyPin, OutputType, Speed};
14use crate::time::Hertz;
15use crate::Peripheral;
16
17/// Output marker type.
18pub enum Output {}
19/// Channel 1 marker type.
20pub enum Ch1 {}
21/// Channel 2 marker type.
22pub enum Ch2 {}
23
24/// PWM pin wrapper.
25///
26/// This wraps a pin to make it usable with PWM.
27pub struct PwmPin<'d, T, C> {
28 _pin: PeripheralRef<'d, AnyPin>,
29 phantom: PhantomData<(T, C)>,
30}
31
32macro_rules! channel_impl {
33 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
34 impl<'d, T: BasicInstance> PwmPin<'d, T, $channel> {
35 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
36 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self {
37 into_ref!(pin);
38 critical_section::with(|_| {
39 pin.set_low();
40 pin.set_as_af(
41 pin.af_num(),
42 AfType::output(OutputType::PushPull, Speed::VeryHigh),
43 );
44 });
45 PwmPin {
46 _pin: pin.map_into(),
47 phantom: PhantomData,
48 }
49 }
50 }
51 };
52}
53
54#[cfg(not(any(lptim_v2a, lptim_v2b)))]
55channel_impl!(new, Output, OutputPin);
56#[cfg(any(lptim_v2a, lptim_v2b))]
57channel_impl!(new_ch1, Ch1, Channel1Pin);
58#[cfg(any(lptim_v2a, lptim_v2b))]
59channel_impl!(new_ch2, Ch2, Channel2Pin);
60
61/// PWM driver.
62pub struct Pwm<'d, T: Instance> {
63 inner: Timer<'d, T>,
64}
65
66#[cfg(not(any(lptim_v2a, lptim_v2b)))]
67impl<'d, T: Instance> Pwm<'d, T> {
68 /// Create a new PWM driver.
69 pub fn new(tim: impl Peripheral<P = T> + 'd, _output_pin: PwmPin<'d, T, Output>, freq: Hertz) -> Self {
70 Self::new_inner(tim, freq)
71 }
72
73 /// Set the duty.
74 ///
75 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
76 pub fn set_duty(&mut self, duty: u16) {
77 assert!(duty <= self.get_max_duty());
78 self.inner.set_compare_value(duty)
79 }
80
81 /// Get the duty.
82 ///
83 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
84 pub fn get_duty(&self) -> u16 {
85 self.inner.get_compare_value()
86 }
87
88 fn post_init(&mut self) {}
89}
90
91#[cfg(any(lptim_v2a, lptim_v2b))]
92impl<'d, T: Instance> Pwm<'d, T> {
93 /// Create a new PWM driver.
94 pub fn new(
95 tim: impl Peripheral<P = T> + 'd,
96 _ch1_pin: Option<PwmPin<'d, T, Ch1>>,
97 _ch2_pin: Option<PwmPin<'d, T, Ch2>>,
98 freq: Hertz,
99 ) -> Self {
100 Self::new_inner(tim, freq)
101 }
102
103 /// Enable the given channel.
104 pub fn enable(&mut self, channel: Channel) {
105 self.inner.enable_channel(channel, true);
106 }
107
108 /// Disable the given channel.
109 pub fn disable(&mut self, channel: Channel) {
110 self.inner.enable_channel(channel, false);
111 }
112
113 /// Check whether given channel is enabled
114 pub fn is_enabled(&self, channel: Channel) -> bool {
115 self.inner.get_channel_enable_state(channel)
116 }
117
118 /// Set the duty for a given channel.
119 ///
120 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
121 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
122 assert!(duty <= self.get_max_duty());
123 self.inner.set_compare_value(channel, duty)
124 }
125
126 /// Get the duty for a given channel.
127 ///
128 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
129 pub fn get_duty(&self, channel: Channel) -> u16 {
130 self.inner.get_compare_value(channel)
131 }
132
133 fn post_init(&mut self) {
134 [Channel::Ch1, Channel::Ch2].iter().for_each(|&channel| {
135 self.inner.set_channel_direction(channel, ChannelDirection::OutputPwm);
136 });
137 }
138}
139
140impl<'d, T: Instance> Pwm<'d, T> {
141 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz) -> Self {
142 let mut this = Self { inner: Timer::new(tim) };
143
144 this.inner.enable();
145 this.set_frequency(freq);
146
147 this.post_init();
148
149 this.inner.continuous_mode_start();
150
151 this
152 }
153
154 /// Set PWM frequency.
155 ///
156 /// Note: when you call this, the max duty value changes, so you will have to
157 /// call `set_duty` on all channels with the duty calculated based on the new max duty.
158 pub fn set_frequency(&mut self, frequency: Hertz) {
159 self.inner.set_frequency(frequency);
160 }
161
162 /// Get max duty value.
163 ///
164 /// This value depends on the configured frequency and the timer's clock rate from RCC.
165 pub fn get_max_duty(&self) -> u16 {
166 self.inner.get_max_compare_value() + 1
167 }
168}
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 @@
1use crate::pac::lptim::vals;
2
3/// Direction of a low-power timer channel
4pub enum ChannelDirection {
5 /// Use channel as a PWM output
6 OutputPwm,
7 /// Use channel as an input capture
8 InputCapture,
9}
10
11impl From<ChannelDirection> for vals::Ccsel {
12 fn from(direction: ChannelDirection) -> Self {
13 match direction {
14 ChannelDirection::OutputPwm => vals::Ccsel::OUTPUTCOMPARE,
15 ChannelDirection::InputCapture => vals::Ccsel::INPUTCAPTURE,
16 }
17 }
18}
diff --git a/embassy-stm32/src/lptim/timer/mod.rs b/embassy-stm32/src/lptim/timer/mod.rs
new file mode 100644
index 000000000..e62fcab49
--- /dev/null
+++ b/embassy-stm32/src/lptim/timer/mod.rs
@@ -0,0 +1,133 @@
1//! Low-level timer driver.
2mod prescaler;
3
4use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
5
6#[cfg(any(lptim_v2a, lptim_v2b))]
7use super::channel::Channel;
8#[cfg(any(lptim_v2a, lptim_v2b))]
9mod channel_direction;
10#[cfg(any(lptim_v2a, lptim_v2b))]
11pub use channel_direction::ChannelDirection;
12use prescaler::Prescaler;
13
14use super::Instance;
15use crate::rcc;
16use crate::time::Hertz;
17
18/// Low-level timer driver.
19pub struct Timer<'d, T: Instance> {
20 _tim: PeripheralRef<'d, T>,
21}
22
23impl<'d, T: Instance> Timer<'d, T> {
24 /// Create a new timer driver.
25 pub fn new(tim: impl Peripheral<P = T> + 'd) -> Self {
26 into_ref!(tim);
27
28 rcc::enable_and_reset::<T>();
29
30 Self { _tim: tim }
31 }
32
33 /// Enable the timer.
34 pub fn enable(&self) {
35 T::regs().cr().modify(|w| w.set_enable(true));
36 }
37
38 /// Disable the timer.
39 pub fn disable(&self) {
40 T::regs().cr().modify(|w| w.set_enable(false));
41 }
42
43 /// Start the timer in single pulse mode.
44 pub fn single_mode_start(&self) {
45 T::regs().cr().modify(|w| w.set_sngstrt(true));
46 }
47
48 /// Start the timer in continuous mode.
49 pub fn continuous_mode_start(&self) {
50 T::regs().cr().modify(|w| w.set_cntstrt(true));
51 }
52
53 /// Set the frequency of how many times per second the timer counts up to the max value or down to 0.
54 pub fn set_frequency(&self, frequency: Hertz) {
55 let f = frequency.0;
56 assert!(f > 0);
57
58 let pclk_f = T::frequency().0;
59
60 let pclk_ticks_per_timer_period = pclk_f / f;
61
62 let psc = Prescaler::from_ticks(pclk_ticks_per_timer_period);
63 let arr = psc.scale_down(pclk_ticks_per_timer_period);
64
65 T::regs().cfgr().modify(|r| r.set_presc((&psc).into()));
66 T::regs().arr().modify(|r| r.set_arr(arr.into()));
67 }
68
69 /// Get the timer frequency.
70 pub fn get_frequency(&self) -> Hertz {
71 let pclk_f = T::frequency();
72 let arr = T::regs().arr().read().arr();
73 let psc = Prescaler::from(T::regs().cfgr().read().presc());
74
75 pclk_f / psc.scale_up(arr)
76 }
77
78 /// Get the clock frequency of the timer (before prescaler is applied).
79 pub fn get_clock_frequency(&self) -> Hertz {
80 T::frequency()
81 }
82
83 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
84 pub fn get_max_compare_value(&self) -> u16 {
85 T::regs().arr().read().arr()
86 }
87}
88
89#[cfg(any(lptim_v2a, lptim_v2b))]
90impl<'d, T: Instance> Timer<'d, T> {
91 /// Enable/disable a channel.
92 pub fn enable_channel(&self, channel: Channel, enable: bool) {
93 T::regs().ccmr(0).modify(|w| {
94 w.set_cce(channel.index(), enable);
95 });
96 }
97
98 /// Get enable/disable state of a channel
99 pub fn get_channel_enable_state(&self, channel: Channel) -> bool {
100 T::regs().ccmr(0).read().cce(channel.index())
101 }
102
103 /// Set compare value for a channel.
104 pub fn set_compare_value(&self, channel: Channel, value: u16) {
105 T::regs().ccr(channel.index()).modify(|w| w.set_ccr(value));
106 }
107
108 /// Get compare value for a channel.
109 pub fn get_compare_value(&self, channel: Channel) -> u16 {
110 T::regs().ccr(channel.index()).read().ccr()
111 }
112
113 /// Set channel direction.
114 #[cfg(any(lptim_v2a, lptim_v2b))]
115 pub fn set_channel_direction(&self, channel: Channel, direction: ChannelDirection) {
116 T::regs()
117 .ccmr(0)
118 .modify(|w| w.set_ccsel(channel.index(), direction.into()));
119 }
120}
121
122#[cfg(not(any(lptim_v2a, lptim_v2b)))]
123impl<'d, T: Instance> Timer<'d, T> {
124 /// Set compare value for a channel.
125 pub fn set_compare_value(&self, value: u16) {
126 T::regs().cmp().modify(|w| w.set_cmp(value));
127 }
128
129 /// Get compare value for a channel.
130 pub fn get_compare_value(&self) -> u16 {
131 T::regs().cmp().read().cmp()
132 }
133}
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 @@
1//! Low-level timer driver.
2
3use crate::pac::lptim::vals;
4
5pub enum Prescaler {
6 Div1,
7 Div2,
8 Div4,
9 Div8,
10 Div16,
11 Div32,
12 Div64,
13 Div128,
14}
15
16impl From<&Prescaler> for vals::Presc {
17 fn from(prescaler: &Prescaler) -> Self {
18 match prescaler {
19 Prescaler::Div1 => vals::Presc::DIV1,
20 Prescaler::Div2 => vals::Presc::DIV2,
21 Prescaler::Div4 => vals::Presc::DIV4,
22 Prescaler::Div8 => vals::Presc::DIV8,
23 Prescaler::Div16 => vals::Presc::DIV16,
24 Prescaler::Div32 => vals::Presc::DIV32,
25 Prescaler::Div64 => vals::Presc::DIV64,
26 Prescaler::Div128 => vals::Presc::DIV128,
27 }
28 }
29}
30
31impl From<vals::Presc> for Prescaler {
32 fn from(prescaler: vals::Presc) -> Self {
33 match prescaler {
34 vals::Presc::DIV1 => Prescaler::Div1,
35 vals::Presc::DIV2 => Prescaler::Div2,
36 vals::Presc::DIV4 => Prescaler::Div4,
37 vals::Presc::DIV8 => Prescaler::Div8,
38 vals::Presc::DIV16 => Prescaler::Div16,
39 vals::Presc::DIV32 => Prescaler::Div32,
40 vals::Presc::DIV64 => Prescaler::Div64,
41 vals::Presc::DIV128 => Prescaler::Div128,
42 }
43 }
44}
45
46impl From<&Prescaler> for u32 {
47 fn from(prescaler: &Prescaler) -> Self {
48 match prescaler {
49 Prescaler::Div1 => 1,
50 Prescaler::Div2 => 2,
51 Prescaler::Div4 => 4,
52 Prescaler::Div8 => 8,
53 Prescaler::Div16 => 16,
54 Prescaler::Div32 => 32,
55 Prescaler::Div64 => 64,
56 Prescaler::Div128 => 128,
57 }
58 }
59}
60
61impl From<u32> for Prescaler {
62 fn from(prescaler: u32) -> Self {
63 match prescaler {
64 1 => Prescaler::Div1,
65 2 => Prescaler::Div2,
66 4 => Prescaler::Div4,
67 8 => Prescaler::Div8,
68 16 => Prescaler::Div16,
69 32 => Prescaler::Div32,
70 64 => Prescaler::Div64,
71 128 => Prescaler::Div128,
72 _ => unreachable!(),
73 }
74 }
75}
76
77impl Prescaler {
78 pub fn from_ticks(ticks: u32) -> Self {
79 // We need to scale down to a 16-bit range
80 (ticks >> 16).next_power_of_two().into()
81 }
82
83 pub fn scale_down(&self, ticks: u32) -> u16 {
84 (ticks / u32::from(self)).try_into().unwrap()
85 }
86
87 pub fn scale_up(&self, ticks: u16) -> u32 {
88 u32::from(self) * ticks as u32
89 }
90}