py32_hal/timer/
pwm_input.rs

1//! PWM Input driver.
2
3// The following code is modified from embassy-stm32
4// https://github.com/embassy-rs/embassy/tree/main/embassy-stm32
5// Special thanks to the Embassy Project and its contributors for their work!
6
7use embassy_hal_internal::into_ref;
8
9use super::low_level::{
10    CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource,
11};
12use super::{Channel, Channel1Pin, Channel2Pin, GeneralInstance4Channel};
13use crate::gpio::{AfType, Pull};
14use crate::time::Hertz;
15use crate::Peripheral;
16
17/// PWM Input driver.
18pub struct PwmInput<'d, T: GeneralInstance4Channel> {
19    channel: Channel,
20    inner: Timer<'d, T>,
21}
22
23impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> {
24    /// Create a new PWM input driver.
25    pub fn new(
26        tim: impl Peripheral<P = T> + 'd,
27        pin: impl Peripheral<P = impl Channel1Pin<T>> + 'd,
28        pull: Pull,
29        freq: Hertz,
30    ) -> Self {
31        into_ref!(pin);
32
33        pin.set_as_af(pin.af_num(), AfType::input(pull));
34
35        Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2)
36    }
37
38    /// Create a new PWM input driver.
39    pub fn new_alt(
40        tim: impl Peripheral<P = T> + 'd,
41        pin: impl Peripheral<P = impl Channel2Pin<T>> + 'd,
42        pull: Pull,
43        freq: Hertz,
44    ) -> Self {
45        into_ref!(pin);
46
47        pin.set_as_af(pin.af_num(), AfType::input(pull));
48
49        Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1)
50    }
51
52    fn new_inner(
53        tim: impl Peripheral<P = T> + 'd,
54        freq: Hertz,
55        ch1: Channel,
56        ch2: Channel,
57    ) -> Self {
58        let mut inner = Timer::new(tim);
59
60        inner.set_counting_mode(CountingMode::EdgeAlignedUp);
61        inner.set_tick_freq(freq);
62        inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
63        inner.start();
64
65        // Configuration steps from ST RM0390 (STM32F446) chapter 17.3.6
66        // or ST RM0008 (STM32F103) chapter 15.3.6 Input capture mode
67        inner.set_input_ti_selection(ch1, InputTISelection::Normal);
68        inner.set_input_capture_mode(ch1, InputCaptureMode::Rising);
69
70        inner.set_input_ti_selection(ch2, InputTISelection::Alternate);
71        inner.set_input_capture_mode(ch2, InputCaptureMode::Falling);
72
73        inner.set_trigger_source(match ch1 {
74            Channel::Ch1 => TriggerSource::TI1FP1,
75            Channel::Ch2 => TriggerSource::TI2FP2,
76            _ => panic!("Invalid channel for PWM input"),
77        });
78
79        inner.set_slave_mode(SlaveMode::RESET_MODE);
80
81        // Must call the `enable` function after
82
83        Self {
84            channel: ch1,
85            inner,
86        }
87    }
88
89    /// Enable the given channel.
90    pub fn enable(&mut self) {
91        self.inner.enable_channel(Channel::Ch1, true);
92        self.inner.enable_channel(Channel::Ch2, true);
93    }
94
95    /// Disable the given channel.
96    pub fn disable(&mut self) {
97        self.inner.enable_channel(Channel::Ch1, false);
98        self.inner.enable_channel(Channel::Ch2, false);
99    }
100
101    /// Check whether given channel is enabled
102    pub fn is_enabled(&self) -> bool {
103        self.inner.get_channel_enable_state(Channel::Ch1)
104    }
105
106    /// Get the period tick count
107    pub fn get_period_ticks(&self) -> u32 {
108        self.inner.get_capture_value(self.channel)
109    }
110
111    /// Get the pulse width tick count
112    pub fn get_width_ticks(&self) -> u32 {
113        self.inner.get_capture_value(match self.channel {
114            Channel::Ch1 => Channel::Ch2,
115            Channel::Ch2 => Channel::Ch1,
116            _ => panic!("Invalid channel for PWM input"),
117        })
118    }
119
120    /// Get the duty cycle in 100%
121    pub fn get_duty_cycle(&self) -> f32 {
122        let period = self.get_period_ticks();
123        if period == 0 {
124            return 0.;
125        }
126        100. * (self.get_width_ticks() as f32) / (period as f32)
127    }
128}