Skip to content

Commit 67de71a

Browse files
authored
lptim: impl PwmPin
1 parent 66f3a1f commit 67de71a

File tree

3 files changed

+212
-11
lines changed

3 files changed

+212
-11
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
### Added
9+
- Implement `embedded_hal::PwmPin` for `LpTim`.
10+
811
### Changed
912
- Inlined trivial `Rng` methods.
1013

hal/src/lptim/cfgr.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ impl Cfgr {
162162
/// use stm32wlxx_hal::lptim::Cfgr;
163163
/// const CFGR: Cfgr = Cfgr::new(0);
164164
/// ```
165+
#[must_use]
165166
pub const fn new(val: u32) -> Cfgr {
166167
Cfgr { val }
167168
}
@@ -175,14 +176,49 @@ impl Cfgr {
175176
/// const CFGR: Cfgr = Cfgr::new(0x1234_5678);
176177
/// assert_eq!(CFGR.raw(), 0x1234_5678);
177178
/// ```
179+
#[must_use]
178180
pub const fn raw(self) -> u32 {
179181
self.val
180182
}
181183

184+
/// Set the waveform polarity.
185+
///
186+
/// # Example
187+
///
188+
/// ```
189+
/// use stm32wlxx_hal::lptim::Cfgr;
190+
///
191+
/// let cfgr: Cfgr = Cfgr::RESET;
192+
/// assert_eq!(cfgr.wavepol(), false);
193+
///
194+
/// let cfgr: Cfgr = cfgr.set_wavepol(true);
195+
/// assert_eq!(cfgr.wavepol(), true);
196+
///
197+
/// let cfgr: Cfgr = cfgr.set_wavepol(false);
198+
/// assert_eq!(cfgr.wavepol(), false);
199+
/// ```
200+
#[inline]
201+
#[must_use = "set_wavepol returns a modified Cfgr"]
202+
pub const fn set_wavepol(mut self, wavepol: bool) -> Self {
203+
if wavepol {
204+
self.val |= 1 << 21;
205+
} else {
206+
self.val &= !(1 << 21);
207+
}
208+
self
209+
}
210+
211+
/// Get the waveform polarity.
212+
#[inline]
213+
#[must_use]
214+
pub const fn wavepol(&self) -> bool {
215+
self.val & (1 << 21) != 0
216+
}
217+
182218
/// Set the trigger polarity.
183219
#[inline]
184220
#[must_use = "set_trg_pol returns a modified Cfgr"]
185-
pub fn set_trg_pol(mut self, trg_pol: TrgPol) -> Self {
221+
pub const fn set_trg_pol(mut self, trg_pol: TrgPol) -> Self {
186222
self.val &= !(0b11 << 17);
187223
self.val |= (trg_pol as u32) << 17;
188224
self
@@ -216,6 +252,7 @@ impl Cfgr {
216252
/// assert_eq!(Cfgr::default().prescaler(), Prescaler::default());
217253
/// ```
218254
#[inline]
255+
#[must_use]
219256
pub const fn prescaler(&self) -> Prescaler {
220257
match (self.val >> 9) & 0b111 {
221258
0b000 => Prescaler::Div1,

hal/src/lptim/mod.rs

Lines changed: 171 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
//! Low-power timers
22
//!
3-
//! Unlike other modules most functionality is exposed via a single trait shared
4-
//! for all timers, [`LpTim`].
3+
//! The low power timers implements the `embedded-hal`
4+
//! [`PwmPin`](embedded_hal::PwmPin) and
5+
//! [`CountDown`](embedded_hal::timer::CountDown) traits.
56
//!
67
//! # Example
78
//!
@@ -36,7 +37,7 @@ pub use cr::Cr;
3637
use crate::{
3738
gpio::{
3839
pins,
39-
sealed::{LpTim1Etr, LpTim2Etr, LpTim3Etr},
40+
sealed::{LpTim1Etr, LpTim1Out, LpTim2Etr, LpTim2Out, LpTim3Etr, LpTim3Out},
4041
},
4142
pac, Ratio,
4243
};
@@ -101,6 +102,7 @@ pub(crate) mod sealed {
101102
fn modify_cfgr<F: FnOnce(Cfgr) -> Cfgr>(&mut self, f: F);
102103
fn cr(&self) -> Cr;
103104
fn set_cr(&mut self, cr: Cr);
105+
fn cmp(&self) -> u16;
104106
fn set_cmp(&mut self, cmp: u16);
105107
fn set_autoreload(&mut self, ar: u16);
106108
unsafe fn cnt() -> u16;
@@ -165,6 +167,11 @@ macro_rules! impl_lptim_base_for {
165167
self.cr.write(|w| unsafe { w.bits(u32::from(cr) & 0x1F) })
166168
}
167169

170+
#[inline(always)]
171+
fn cmp(&self) -> u16 {
172+
self.cmp.read().cmp().bits()
173+
}
174+
168175
#[inline(always)]
169176
fn set_cmp(&mut self, cmp: u16) {
170177
self.cmp.write(|w| w.cmp().bits(cmp));
@@ -472,6 +479,7 @@ pub trait LpTim: sealed::LpTim {
472479
}
473480

474481
/// Returns `true` if the timer is enabled.
482+
#[inline]
475483
fn is_enabled(&self) -> bool {
476484
self.as_tim().cr().enabled()
477485
}
@@ -498,7 +506,7 @@ impl LpTim for LpTim1 {
498506
rcc.ccipr.modify(|_, w| w.lptim1sel().bits(clk as u8));
499507
unsafe { Self::pulse_reset(rcc) }
500508
Self::enable_clock(rcc);
501-
tim.set_cfgr(Cfgr::RESET.set_prescaler(pre));
509+
tim.set_cfgr(Cfgr::RESET.set_prescaler(pre).set_wavepol(true));
502510

503511
let src: Ratio<u32> = match clk {
504512
Clk::Pclk => crate::rcc::apb1timx(rcc),
@@ -546,7 +554,7 @@ impl LpTim for LpTim2 {
546554
rcc.ccipr.modify(|_, w| w.lptim2sel().bits(clk as u8));
547555
unsafe { Self::pulse_reset(rcc) }
548556
Self::enable_clock(rcc);
549-
tim.set_cfgr(Cfgr::RESET.set_prescaler(pre));
557+
tim.set_cfgr(Cfgr::RESET.set_prescaler(pre).set_wavepol(true));
550558

551559
let src: Ratio<u32> = match clk {
552560
Clk::Pclk => crate::rcc::apb1timx(rcc),
@@ -594,7 +602,7 @@ impl LpTim for LpTim3 {
594602
rcc.ccipr.modify(|_, w| w.lptim3sel().bits(clk as u8));
595603
unsafe { Self::pulse_reset(rcc) }
596604
Self::enable_clock(rcc);
597-
tim.set_cfgr(Cfgr::RESET.set_prescaler(pre));
605+
tim.set_cfgr(Cfgr::RESET.set_prescaler(pre).set_wavepol(true));
598606

599607
let src: Ratio<u32> = match clk {
600608
Clk::Pclk => crate::rcc::apb1timx(rcc),
@@ -635,7 +643,7 @@ impl LpTim for LpTim3 {
635643
}
636644
}
637645

638-
macro_rules! impl_eh_for {
646+
macro_rules! impl_eh_countdown_for {
639647
($tim:ident) => {
640648
impl embedded_hal::timer::CountDown for $tim {
641649
type Time = u16;
@@ -681,9 +689,58 @@ macro_rules! impl_eh_for {
681689
};
682690
}
683691

684-
impl_eh_for!(LpTim1);
685-
impl_eh_for!(LpTim2);
686-
impl_eh_for!(LpTim3);
692+
impl_eh_countdown_for!(LpTim1);
693+
impl_eh_countdown_for!(LpTim2);
694+
impl_eh_countdown_for!(LpTim3);
695+
696+
macro_rules! impl_eh_pwmpin_for {
697+
($tim:ident) => {
698+
impl embedded_hal::PwmPin for $tim {
699+
type Duty = u16;
700+
701+
fn disable(&mut self) {
702+
self.as_mut_tim().set_cr(Cr::DISABLE);
703+
}
704+
705+
fn enable(&mut self) {
706+
const CR: Cr = Cr::RESET.enable().set_continuous();
707+
self.as_mut_tim().set_cr(CR);
708+
}
709+
710+
fn get_duty(&self) -> Self::Duty {
711+
self.as_tim().cmp()
712+
}
713+
714+
fn get_max_duty(&self) -> Self::Duty {
715+
u16::MAX
716+
}
717+
718+
fn set_duty(&mut self, duty: Self::Duty) {
719+
if !self.is_enabled() {
720+
const CR: Cr = Cr::RESET.enable();
721+
self.as_mut_tim().set_cr(CR);
722+
723+
// RM0461 Rev 4 "Timer enable":
724+
// After setting the ENABLE bit, a delay of two counter
725+
// clock is needed before the LPTIM is actually enabled.
726+
const MAX_SYS_FREQ: u32 = 48_000_000;
727+
let delay: u32 = (MAX_SYS_FREQ * 2) / self.hz().to_integer();
728+
cortex_m::asm::delay(delay);
729+
}
730+
731+
// can only be modified when enabled
732+
self.as_mut_tim().set_autoreload(u16::MAX);
733+
self.as_mut_tim().set_cmp(duty);
734+
while Self::isr() & (irq::ARROK | irq::CMPOK) == 0 {}
735+
unsafe { self.set_icr(irq::ARROK | irq::CMPOK) };
736+
}
737+
}
738+
};
739+
}
740+
741+
impl_eh_pwmpin_for!(LpTim1);
742+
impl_eh_pwmpin_for!(LpTim2);
743+
impl_eh_pwmpin_for!(LpTim3);
687744

688745
/// Low-power timer 1 trigger pin.
689746
///
@@ -917,3 +974,107 @@ impl LpTim3 {
917974
pin.free()
918975
}
919976
}
977+
978+
/// Low-power timer 1 output pin.
979+
///
980+
/// Constructed with [`new_output_pin`](LpTim1::new_output_pin).
981+
#[derive(Debug)]
982+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
983+
pub struct LpTim1OutPin<P> {
984+
pin: P,
985+
}
986+
987+
impl<P> LpTim1OutPin<P> {
988+
fn free(self) -> P {
989+
self.pin
990+
}
991+
}
992+
993+
// TODO: move to LpTim trait when GATs are stablized
994+
impl LpTim1 {
995+
/// Setup a new output pin.
996+
#[inline]
997+
pub fn new_output_pin<P: LpTim1Out>(
998+
&mut self,
999+
mut pin: P,
1000+
cs: &CriticalSection,
1001+
) -> LpTim1OutPin<P> {
1002+
pin.set_lptim1_out_af(cs);
1003+
LpTim1OutPin { pin }
1004+
}
1005+
1006+
/// Free the output pin previously created with
1007+
/// [`new_output_pin`](Self::new_output_pin).
1008+
#[inline]
1009+
pub fn free_output_pin<P: LpTim1Out>(&mut self, pin: LpTim1OutPin<P>) -> P {
1010+
pin.free()
1011+
}
1012+
}
1013+
1014+
/// Low-power timer 2 output pin.
1015+
///
1016+
/// Constructed with [`new_output_pin`](LpTim2::new_output_pin).
1017+
#[derive(Debug)]
1018+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1019+
pub struct LpTim2OutPin<P> {
1020+
pin: P,
1021+
}
1022+
1023+
impl<P> LpTim2OutPin<P> {
1024+
fn free(self) -> P {
1025+
self.pin
1026+
}
1027+
}
1028+
1029+
// TODO: move to LpTim trait when GATs are stablized
1030+
impl LpTim2 {
1031+
/// Setup a new output pin.
1032+
#[inline]
1033+
pub fn new_output_pin<P: LpTim2Out>(
1034+
&mut self,
1035+
mut pin: P,
1036+
cs: &CriticalSection,
1037+
) -> LpTim2OutPin<P> {
1038+
pin.set_lptim2_out_af(cs);
1039+
LpTim2OutPin { pin }
1040+
}
1041+
1042+
/// Free the output pin previously created with
1043+
/// [`new_output_pin`](Self::new_output_pin).
1044+
#[inline]
1045+
pub fn free_output_pin<P: LpTim2Out>(&mut self, pin: LpTim2OutPin<P>) -> P {
1046+
pin.free()
1047+
}
1048+
}
1049+
1050+
/// Low-power timer 3 output pin.
1051+
///
1052+
/// Constructed with [`new_output_pin`](LpTim3::new_output_pin).
1053+
#[derive(Debug)]
1054+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1055+
pub struct LpTim3OutPin {
1056+
pin: pins::A1,
1057+
}
1058+
1059+
impl LpTim3OutPin {
1060+
fn free(self) -> pins::A1 {
1061+
self.pin
1062+
}
1063+
}
1064+
1065+
// TODO: move to LpTim trait when GATs are stablized
1066+
impl LpTim3 {
1067+
/// Setup a new output pin.
1068+
#[inline]
1069+
pub fn new_output_pin(&mut self, mut pin: pins::A1, cs: &CriticalSection) -> LpTim3OutPin {
1070+
pin.set_lptim3_out_af(cs);
1071+
LpTim3OutPin { pin }
1072+
}
1073+
1074+
/// Free the output pin previously created with
1075+
/// [`new_output_pin`](Self::new_output_pin).
1076+
#[inline]
1077+
pub fn free_output_pin(&mut self, pin: LpTim3OutPin) -> pins::A1 {
1078+
pin.free()
1079+
}
1080+
}

0 commit comments

Comments
 (0)