1 | //! Low-level timer driver. |
2 | mod prescaler; |
3 | |
4 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; |
5 | |
6 | #[cfg (any(lptim_v2a, lptim_v2b))] |
7 | use super::channel::Channel; |
8 | #[cfg (any(lptim_v2a, lptim_v2b))] |
9 | mod channel_direction; |
10 | #[cfg (any(lptim_v2a, lptim_v2b))] |
11 | pub use channel_direction::ChannelDirection; |
12 | use prescaler::Prescaler; |
13 | |
14 | use super::Instance; |
15 | use crate::rcc; |
16 | use crate::time::Hertz; |
17 | |
18 | /// Low-level timer driver. |
19 | pub struct Timer<'d, T: Instance> { |
20 | _tim: PeripheralRef<'d, T>, |
21 | } |
22 | |
23 | impl<'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))] |
90 | impl<'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)))] |
123 | impl<'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 | } |
134 | |