| 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 | |