diff options
| -rwxr-xr-x | ci.sh | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/time_driver.rs | 34 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/complementary_pwm.rs | 38 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/low_level.rs | 638 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/mod.rs | 1005 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/qei.rs | 33 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/simple_pwm.rs | 46 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/ws2812_pwm.rs | 5 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/dac_dma.rs | 26 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/low_level_timer_api.rs | 34 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/dac_dma.rs | 26 |
11 files changed, 882 insertions, 1004 deletions
| @@ -124,6 +124,7 @@ cargo batch \ | |||
| 124 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time \ | 124 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time \ |
| 125 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h725re,defmt,exti,time-driver-any,time \ | 125 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h725re,defmt,exti,time-driver-any,time \ |
| 126 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-any,time \ | 126 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-any,time \ |
| 127 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-tim1,time \ | ||
| 127 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l431cb,defmt,exti,time-driver-any,time \ | 128 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l431cb,defmt,exti,time-driver-any,time \ |
| 128 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \ | 129 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \ |
| 129 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l422cb,defmt,exti,time-driver-any,time \ | 130 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l422cb,defmt,exti,time-driver-any,time \ |
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index e78f81dca..c961fc14b 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs | |||
| @@ -8,7 +8,7 @@ use critical_section::CriticalSection; | |||
| 8 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 8 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 9 | use embassy_sync::blocking_mutex::Mutex; | 9 | use embassy_sync::blocking_mutex::Mutex; |
| 10 | use embassy_time_driver::{AlarmHandle, Driver, TICK_HZ}; | 10 | use embassy_time_driver::{AlarmHandle, Driver, TICK_HZ}; |
| 11 | use stm32_metapac::timer::regs; | 11 | use stm32_metapac::timer::{regs, TimGp16}; |
| 12 | 12 | ||
| 13 | use crate::interrupt::typelevel::Interrupt; | 13 | use crate::interrupt::typelevel::Interrupt; |
| 14 | use crate::pac::timer::vals; | 14 | use crate::pac::timer::vals; |
| @@ -16,8 +16,8 @@ use crate::rcc::sealed::RccPeripheral; | |||
| 16 | #[cfg(feature = "low-power")] | 16 | #[cfg(feature = "low-power")] |
| 17 | use crate::rtc::Rtc; | 17 | use crate::rtc::Rtc; |
| 18 | #[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))] | 18 | #[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))] |
| 19 | use crate::timer::sealed::AdvancedControlInstance; | 19 | use crate::timer::AdvancedInstance1Channel; |
| 20 | use crate::timer::sealed::{CoreInstance, GeneralPurpose16bitInstance as Instance}; | 20 | use crate::timer::CoreInstance; |
| 21 | use crate::{interrupt, peripherals}; | 21 | use crate::{interrupt, peripherals}; |
| 22 | 22 | ||
| 23 | // NOTE regarding ALARM_COUNT: | 23 | // NOTE regarding ALARM_COUNT: |
| @@ -207,6 +207,10 @@ foreach_interrupt! { | |||
| 207 | }; | 207 | }; |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | fn regs_gp16() -> TimGp16 { | ||
| 211 | unsafe { TimGp16::from_ptr(T::regs()) } | ||
| 212 | } | ||
| 213 | |||
| 210 | // Clock timekeeping works with something we call "periods", which are time intervals | 214 | // Clock timekeeping works with something we call "periods", which are time intervals |
| 211 | // of 2^15 ticks. The Clock counter value is 16 bits, so one "overflow cycle" is 2 periods. | 215 | // of 2^15 ticks. The Clock counter value is 16 bits, so one "overflow cycle" is 2 periods. |
| 212 | // | 216 | // |
| @@ -271,7 +275,7 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { | |||
| 271 | 275 | ||
| 272 | impl RtcDriver { | 276 | impl RtcDriver { |
| 273 | fn init(&'static self, cs: critical_section::CriticalSection) { | 277 | fn init(&'static self, cs: critical_section::CriticalSection) { |
| 274 | let r = T::regs_gp16(); | 278 | let r = regs_gp16(); |
| 275 | 279 | ||
| 276 | <T as RccPeripheral>::enable_and_reset_with_cs(cs); | 280 | <T as RccPeripheral>::enable_and_reset_with_cs(cs); |
| 277 | 281 | ||
| @@ -308,9 +312,9 @@ impl RtcDriver { | |||
| 308 | 312 | ||
| 309 | #[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))] | 313 | #[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))] |
| 310 | { | 314 | { |
| 311 | <T as AdvancedControlInstance>::CaptureCompareInterrupt::unpend(); | 315 | <T as AdvancedInstance1Channel>::CaptureCompareInterrupt::unpend(); |
| 312 | unsafe { | 316 | unsafe { |
| 313 | <T as AdvancedControlInstance>::CaptureCompareInterrupt::enable(); | 317 | <T as AdvancedInstance1Channel>::CaptureCompareInterrupt::enable(); |
| 314 | } | 318 | } |
| 315 | } | 319 | } |
| 316 | 320 | ||
| @@ -318,7 +322,7 @@ impl RtcDriver { | |||
| 318 | } | 322 | } |
| 319 | 323 | ||
| 320 | fn on_interrupt(&self) { | 324 | fn on_interrupt(&self) { |
| 321 | let r = T::regs_gp16(); | 325 | let r = regs_gp16(); |
| 322 | 326 | ||
| 323 | // XXX: reduce the size of this critical section ? | 327 | // XXX: reduce the size of this critical section ? |
| 324 | critical_section::with(|cs| { | 328 | critical_section::with(|cs| { |
| @@ -349,7 +353,7 @@ impl RtcDriver { | |||
| 349 | } | 353 | } |
| 350 | 354 | ||
| 351 | fn next_period(&self) { | 355 | fn next_period(&self) { |
| 352 | let r = T::regs_gp16(); | 356 | let r = regs_gp16(); |
| 353 | 357 | ||
| 354 | // We only modify the period from the timer interrupt, so we know this can't race. | 358 | // We only modify the period from the timer interrupt, so we know this can't race. |
| 355 | let period = self.period.load(Ordering::Relaxed) + 1; | 359 | let period = self.period.load(Ordering::Relaxed) + 1; |
| @@ -413,7 +417,7 @@ impl RtcDriver { | |||
| 413 | /// Add the given offset to the current time | 417 | /// Add the given offset to the current time |
| 414 | fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) { | 418 | fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) { |
| 415 | let offset = offset.as_ticks(); | 419 | let offset = offset.as_ticks(); |
| 416 | let cnt = T::regs_gp16().cnt().read().cnt() as u32; | 420 | let cnt = regs_gp16().cnt().read().cnt() as u32; |
| 417 | let period = self.period.load(Ordering::SeqCst); | 421 | let period = self.period.load(Ordering::SeqCst); |
| 418 | 422 | ||
| 419 | // Correct the race, if it exists | 423 | // Correct the race, if it exists |
| @@ -439,7 +443,7 @@ impl RtcDriver { | |||
| 439 | let period = if cnt > u16::MAX as u32 / 2 { period + 1 } else { period }; | 443 | let period = if cnt > u16::MAX as u32 / 2 { period + 1 } else { period }; |
| 440 | 444 | ||
| 441 | self.period.store(period, Ordering::SeqCst); | 445 | self.period.store(period, Ordering::SeqCst); |
| 442 | T::regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); | 446 | regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); |
| 443 | 447 | ||
| 444 | // Now, recompute all alarms | 448 | // Now, recompute all alarms |
| 445 | for i in 0..ALARM_COUNT { | 449 | for i in 0..ALARM_COUNT { |
| @@ -496,7 +500,7 @@ impl RtcDriver { | |||
| 496 | .unwrap() | 500 | .unwrap() |
| 497 | .start_wakeup_alarm(time_until_next_alarm, cs); | 501 | .start_wakeup_alarm(time_until_next_alarm, cs); |
| 498 | 502 | ||
| 499 | T::regs_gp16().cr1().modify(|w| w.set_cen(false)); | 503 | regs_gp16().cr1().modify(|w| w.set_cen(false)); |
| 500 | 504 | ||
| 501 | Ok(()) | 505 | Ok(()) |
| 502 | } | 506 | } |
| @@ -506,7 +510,7 @@ impl RtcDriver { | |||
| 506 | #[cfg(feature = "low-power")] | 510 | #[cfg(feature = "low-power")] |
| 507 | /// Resume the timer with the given offset | 511 | /// Resume the timer with the given offset |
| 508 | pub(crate) fn resume_time(&self) { | 512 | pub(crate) fn resume_time(&self) { |
| 509 | if T::regs_gp16().cr1().read().cen() { | 513 | if regs_gp16().cr1().read().cen() { |
| 510 | // Time isn't currently stopped | 514 | // Time isn't currently stopped |
| 511 | 515 | ||
| 512 | return; | 516 | return; |
| @@ -515,14 +519,14 @@ impl RtcDriver { | |||
| 515 | critical_section::with(|cs| { | 519 | critical_section::with(|cs| { |
| 516 | self.stop_wakeup_alarm(cs); | 520 | self.stop_wakeup_alarm(cs); |
| 517 | 521 | ||
| 518 | T::regs_gp16().cr1().modify(|w| w.set_cen(true)); | 522 | regs_gp16().cr1().modify(|w| w.set_cen(true)); |
| 519 | }) | 523 | }) |
| 520 | } | 524 | } |
| 521 | } | 525 | } |
| 522 | 526 | ||
| 523 | impl Driver for RtcDriver { | 527 | impl Driver for RtcDriver { |
| 524 | fn now(&self) -> u64 { | 528 | fn now(&self) -> u64 { |
| 525 | let r = T::regs_gp16(); | 529 | let r = regs_gp16(); |
| 526 | 530 | ||
| 527 | let period = self.period.load(Ordering::Relaxed); | 531 | let period = self.period.load(Ordering::Relaxed); |
| 528 | compiler_fence(Ordering::Acquire); | 532 | compiler_fence(Ordering::Acquire); |
| @@ -553,7 +557,7 @@ impl Driver for RtcDriver { | |||
| 553 | 557 | ||
| 554 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { | 558 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { |
| 555 | critical_section::with(|cs| { | 559 | critical_section::with(|cs| { |
| 556 | let r = T::regs_gp16(); | 560 | let r = regs_gp16(); |
| 557 | 561 | ||
| 558 | let n = alarm.id() as usize; | 562 | let n = alarm.id() as usize; |
| 559 | let alarm = self.get_alarm(cs, alarm); | 563 | let alarm = self.get_alarm(cs, alarm); |
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 723e8506b..a892646cf 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs | |||
| @@ -5,11 +5,15 @@ use core::marker::PhantomData; | |||
| 5 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 5 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 6 | use stm32_metapac::timer::vals::Ckd; | 6 | use stm32_metapac::timer::vals::Ckd; |
| 7 | 7 | ||
| 8 | use super::simple_pwm::*; | 8 | use super::low_level::{CountingMode, OutputPolarity, Timer}; |
| 9 | use super::*; | 9 | use super::simple_pwm::{Ch1, Ch2, Ch3, Ch4, PwmPin}; |
| 10 | #[allow(unused_imports)] | 10 | use super::{ |
| 11 | use crate::gpio::sealed::{AFType, Pin}; | 11 | AdvancedInstance4Channel, Channel, Channel1ComplementaryPin, Channel2ComplementaryPin, Channel3ComplementaryPin, |
| 12 | Channel4ComplementaryPin, | ||
| 13 | }; | ||
| 12 | use crate::gpio::{AnyPin, OutputType}; | 14 | use crate::gpio::{AnyPin, OutputType}; |
| 15 | use crate::time::Hertz; | ||
| 16 | use crate::timer::low_level::OutputCompareMode; | ||
| 13 | use crate::Peripheral; | 17 | use crate::Peripheral; |
| 14 | 18 | ||
| 15 | /// Complementary PWM pin wrapper. | 19 | /// Complementary PWM pin wrapper. |
| @@ -22,7 +26,7 @@ pub struct ComplementaryPwmPin<'d, T, C> { | |||
| 22 | 26 | ||
| 23 | macro_rules! complementary_channel_impl { | 27 | macro_rules! complementary_channel_impl { |
| 24 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | 28 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { |
| 25 | impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> { | 29 | impl<'d, T: AdvancedInstance4Channel> ComplementaryPwmPin<'d, T, $channel> { |
| 26 | #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] | 30 | #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] |
| 27 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self { | 31 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self { |
| 28 | into_ref!(pin); | 32 | into_ref!(pin); |
| @@ -47,11 +51,11 @@ complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin); | |||
| 47 | complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); | 51 | complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); |
| 48 | 52 | ||
| 49 | /// PWM driver with support for standard and complementary outputs. | 53 | /// PWM driver with support for standard and complementary outputs. |
| 50 | pub struct ComplementaryPwm<'d, T> { | 54 | pub struct ComplementaryPwm<'d, T: AdvancedInstance4Channel> { |
| 51 | inner: PeripheralRef<'d, T>, | 55 | inner: Timer<'d, T>, |
| 52 | } | 56 | } |
| 53 | 57 | ||
| 54 | impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | 58 | impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { |
| 55 | /// Create a new complementary PWM driver. | 59 | /// Create a new complementary PWM driver. |
| 56 | #[allow(clippy::too_many_arguments)] | 60 | #[allow(clippy::too_many_arguments)] |
| 57 | pub fn new( | 61 | pub fn new( |
| @@ -71,11 +75,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | |||
| 71 | } | 75 | } |
| 72 | 76 | ||
| 73 | fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self { | 77 | fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self { |
| 74 | into_ref!(tim); | 78 | let mut this = Self { inner: Timer::new(tim) }; |
| 75 | |||
| 76 | T::enable_and_reset(); | ||
| 77 | |||
| 78 | let mut this = Self { inner: tim }; | ||
| 79 | 79 | ||
| 80 | this.inner.set_counting_mode(counting_mode); | 80 | this.inner.set_counting_mode(counting_mode); |
| 81 | this.set_frequency(freq); | 81 | this.set_frequency(freq); |
| @@ -122,7 +122,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | |||
| 122 | /// | 122 | /// |
| 123 | /// This value depends on the configured frequency and the timer's clock rate from RCC. | 123 | /// This value depends on the configured frequency and the timer's clock rate from RCC. |
| 124 | pub fn get_max_duty(&self) -> u16 { | 124 | pub fn get_max_duty(&self) -> u16 { |
| 125 | self.inner.get_max_compare_value() + 1 | 125 | self.inner.get_max_compare_value() as u16 + 1 |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | /// Set the duty for a given channel. | 128 | /// Set the duty for a given channel. |
| @@ -130,7 +130,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | |||
| 130 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. | 130 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. |
| 131 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { | 131 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { |
| 132 | assert!(duty <= self.get_max_duty()); | 132 | assert!(duty <= self.get_max_duty()); |
| 133 | self.inner.set_compare_value(channel, duty) | 133 | self.inner.set_compare_value(channel, duty as _) |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | /// Set the output polarity for a given channel. | 136 | /// Set the output polarity for a given channel. |
| @@ -148,7 +148,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | |||
| 148 | } | 148 | } |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> { | 151 | impl<'d, T: AdvancedInstance4Channel> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> { |
| 152 | type Channel = Channel; | 152 | type Channel = Channel; |
| 153 | type Time = Hertz; | 153 | type Time = Hertz; |
| 154 | type Duty = u16; | 154 | type Duty = u16; |
| @@ -168,16 +168,16 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for C | |||
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | fn get_duty(&self, channel: Self::Channel) -> Self::Duty { | 170 | fn get_duty(&self, channel: Self::Channel) -> Self::Duty { |
| 171 | self.inner.get_compare_value(channel) | 171 | self.inner.get_compare_value(channel) as u16 |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | fn get_max_duty(&self) -> Self::Duty { | 174 | fn get_max_duty(&self) -> Self::Duty { |
| 175 | self.inner.get_max_compare_value() + 1 | 175 | self.inner.get_max_compare_value() as u16 + 1 |
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { | 178 | fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { |
| 179 | assert!(duty <= self.get_max_duty()); | 179 | assert!(duty <= self.get_max_duty()); |
| 180 | self.inner.set_compare_value(channel, duty) | 180 | self.inner.set_compare_value(channel, duty as u32) |
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | fn set_period<P>(&mut self, period: P) | 183 | fn set_period<P>(&mut self, period: P) |
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs new file mode 100644 index 000000000..a5d942314 --- /dev/null +++ b/embassy-stm32/src/timer/low_level.rs | |||
| @@ -0,0 +1,638 @@ | |||
| 1 | //! Low-level timer driver. | ||
| 2 | //! | ||
| 3 | //! This is an unopinionated, very low-level driver for all STM32 timers. It allows direct register | ||
| 4 | //! manipulation with the `regs_*()` methods, and has utility functions that are thin wrappers | ||
| 5 | //! over the registers. | ||
| 6 | //! | ||
| 7 | //! The available functionality depends on the timer type. | ||
| 8 | |||
| 9 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; | ||
| 10 | |||
| 11 | use super::*; | ||
| 12 | use crate::pac::timer::vals; | ||
| 13 | use crate::time::Hertz; | ||
| 14 | |||
| 15 | /// Input capture mode. | ||
| 16 | #[derive(Clone, Copy)] | ||
| 17 | pub enum InputCaptureMode { | ||
| 18 | /// Rising edge only. | ||
| 19 | Rising, | ||
| 20 | /// Falling edge only. | ||
| 21 | Falling, | ||
| 22 | /// Both rising or falling edges. | ||
| 23 | BothEdges, | ||
| 24 | } | ||
| 25 | |||
| 26 | /// Input TI selection. | ||
| 27 | #[derive(Clone, Copy)] | ||
| 28 | pub enum InputTISelection { | ||
| 29 | /// Normal | ||
| 30 | Normal, | ||
| 31 | /// Alternate | ||
| 32 | Alternate, | ||
| 33 | /// TRC | ||
| 34 | TRC, | ||
| 35 | } | ||
| 36 | |||
| 37 | impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs { | ||
| 38 | fn from(tisel: InputTISelection) -> Self { | ||
| 39 | match tisel { | ||
| 40 | InputTISelection::Normal => stm32_metapac::timer::vals::CcmrInputCcs::TI4, | ||
| 41 | InputTISelection::Alternate => stm32_metapac::timer::vals::CcmrInputCcs::TI3, | ||
| 42 | InputTISelection::TRC => stm32_metapac::timer::vals::CcmrInputCcs::TRC, | ||
| 43 | } | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | /// Timer counting mode. | ||
| 48 | #[repr(u8)] | ||
| 49 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] | ||
| 50 | pub enum CountingMode { | ||
| 51 | #[default] | ||
| 52 | /// The timer counts up to the reload value and then resets back to 0. | ||
| 53 | EdgeAlignedUp, | ||
| 54 | /// The timer counts down to 0 and then resets back to the reload value. | ||
| 55 | EdgeAlignedDown, | ||
| 56 | /// The timer counts up to the reload value and then counts back to 0. | ||
| 57 | /// | ||
| 58 | /// The output compare interrupt flags of channels configured in output are | ||
| 59 | /// set when the counter is counting down. | ||
| 60 | CenterAlignedDownInterrupts, | ||
| 61 | /// The timer counts up to the reload value and then counts back to 0. | ||
| 62 | /// | ||
| 63 | /// The output compare interrupt flags of channels configured in output are | ||
| 64 | /// set when the counter is counting up. | ||
| 65 | CenterAlignedUpInterrupts, | ||
| 66 | /// The timer counts up to the reload value and then counts back to 0. | ||
| 67 | /// | ||
| 68 | /// The output compare interrupt flags of channels configured in output are | ||
| 69 | /// set when the counter is counting both up or down. | ||
| 70 | CenterAlignedBothInterrupts, | ||
| 71 | } | ||
| 72 | |||
| 73 | impl CountingMode { | ||
| 74 | /// Return whether this mode is edge-aligned (up or down). | ||
| 75 | pub fn is_edge_aligned(&self) -> bool { | ||
| 76 | matches!(self, CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown) | ||
| 77 | } | ||
| 78 | |||
| 79 | /// Return whether this mode is center-aligned. | ||
| 80 | pub fn is_center_aligned(&self) -> bool { | ||
| 81 | matches!( | ||
| 82 | self, | ||
| 83 | CountingMode::CenterAlignedDownInterrupts | ||
| 84 | | CountingMode::CenterAlignedUpInterrupts | ||
| 85 | | CountingMode::CenterAlignedBothInterrupts | ||
| 86 | ) | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | impl From<CountingMode> for (vals::Cms, vals::Dir) { | ||
| 91 | fn from(value: CountingMode) -> Self { | ||
| 92 | match value { | ||
| 93 | CountingMode::EdgeAlignedUp => (vals::Cms::EDGEALIGNED, vals::Dir::UP), | ||
| 94 | CountingMode::EdgeAlignedDown => (vals::Cms::EDGEALIGNED, vals::Dir::DOWN), | ||
| 95 | CountingMode::CenterAlignedDownInterrupts => (vals::Cms::CENTERALIGNED1, vals::Dir::UP), | ||
| 96 | CountingMode::CenterAlignedUpInterrupts => (vals::Cms::CENTERALIGNED2, vals::Dir::UP), | ||
| 97 | CountingMode::CenterAlignedBothInterrupts => (vals::Cms::CENTERALIGNED3, vals::Dir::UP), | ||
| 98 | } | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | impl From<(vals::Cms, vals::Dir)> for CountingMode { | ||
| 103 | fn from(value: (vals::Cms, vals::Dir)) -> Self { | ||
| 104 | match value { | ||
| 105 | (vals::Cms::EDGEALIGNED, vals::Dir::UP) => CountingMode::EdgeAlignedUp, | ||
| 106 | (vals::Cms::EDGEALIGNED, vals::Dir::DOWN) => CountingMode::EdgeAlignedDown, | ||
| 107 | (vals::Cms::CENTERALIGNED1, _) => CountingMode::CenterAlignedDownInterrupts, | ||
| 108 | (vals::Cms::CENTERALIGNED2, _) => CountingMode::CenterAlignedUpInterrupts, | ||
| 109 | (vals::Cms::CENTERALIGNED3, _) => CountingMode::CenterAlignedBothInterrupts, | ||
| 110 | } | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | /// Output compare mode. | ||
| 115 | #[derive(Clone, Copy)] | ||
| 116 | pub enum OutputCompareMode { | ||
| 117 | /// The comparison between the output compare register TIMx_CCRx and | ||
| 118 | /// the counter TIMx_CNT has no effect on the outputs. | ||
| 119 | /// (this mode is used to generate a timing base). | ||
| 120 | Frozen, | ||
| 121 | /// Set channel to active level on match. OCxREF signal is forced high when the | ||
| 122 | /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx). | ||
| 123 | ActiveOnMatch, | ||
| 124 | /// Set channel to inactive level on match. OCxREF signal is forced low when the | ||
| 125 | /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx). | ||
| 126 | InactiveOnMatch, | ||
| 127 | /// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx. | ||
| 128 | Toggle, | ||
| 129 | /// Force inactive level - OCxREF is forced low. | ||
| 130 | ForceInactive, | ||
| 131 | /// Force active level - OCxREF is forced high. | ||
| 132 | ForceActive, | ||
| 133 | /// PWM mode 1 - In upcounting, channel is active as long as TIMx_CNT<TIMx_CCRx | ||
| 134 | /// else inactive. In downcounting, channel is inactive (OCxREF=0) as long as | ||
| 135 | /// TIMx_CNT>TIMx_CCRx else active (OCxREF=1). | ||
| 136 | PwmMode1, | ||
| 137 | /// PWM mode 2 - In upcounting, channel is inactive as long as | ||
| 138 | /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as | ||
| 139 | /// TIMx_CNT>TIMx_CCRx else inactive. | ||
| 140 | PwmMode2, | ||
| 141 | // TODO: there's more modes here depending on the chip family. | ||
| 142 | } | ||
| 143 | |||
| 144 | impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { | ||
| 145 | fn from(mode: OutputCompareMode) -> Self { | ||
| 146 | match mode { | ||
| 147 | OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN, | ||
| 148 | OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVEONMATCH, | ||
| 149 | OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVEONMATCH, | ||
| 150 | OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE, | ||
| 151 | OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCEINACTIVE, | ||
| 152 | OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCEACTIVE, | ||
| 153 | OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWMMODE1, | ||
| 154 | OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWMMODE2, | ||
| 155 | } | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | /// Timer output pin polarity. | ||
| 160 | #[derive(Clone, Copy)] | ||
| 161 | pub enum OutputPolarity { | ||
| 162 | /// Active high (higher duty value makes the pin spend more time high). | ||
| 163 | ActiveHigh, | ||
| 164 | /// Active low (higher duty value makes the pin spend more time low). | ||
| 165 | ActiveLow, | ||
| 166 | } | ||
| 167 | |||
| 168 | impl From<OutputPolarity> for bool { | ||
| 169 | fn from(mode: OutputPolarity) -> Self { | ||
| 170 | match mode { | ||
| 171 | OutputPolarity::ActiveHigh => false, | ||
| 172 | OutputPolarity::ActiveLow => true, | ||
| 173 | } | ||
| 174 | } | ||
| 175 | } | ||
| 176 | |||
| 177 | /// Low-level timer driver. | ||
| 178 | pub struct Timer<'d, T: CoreInstance> { | ||
| 179 | tim: PeripheralRef<'d, T>, | ||
| 180 | } | ||
| 181 | |||
| 182 | impl<'d, T: CoreInstance> Drop for Timer<'d, T> { | ||
| 183 | fn drop(&mut self) { | ||
| 184 | T::disable() | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | impl<'d, T: CoreInstance> Timer<'d, T> { | ||
| 189 | /// Create a new timer driver. | ||
| 190 | pub fn new(tim: impl Peripheral<P = T> + 'd) -> Self { | ||
| 191 | into_ref!(tim); | ||
| 192 | |||
| 193 | T::enable_and_reset(); | ||
| 194 | |||
| 195 | Self { tim } | ||
| 196 | } | ||
| 197 | |||
| 198 | /// Get access to the virutal core 16bit timer registers. | ||
| 199 | /// | ||
| 200 | /// Note: This works even if the timer is more capable, because registers | ||
| 201 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 202 | /// for a given set of capabilities, and having it transparently work with | ||
| 203 | /// more capable timers. | ||
| 204 | pub fn regs_core(&self) -> crate::pac::timer::TimCore { | ||
| 205 | unsafe { crate::pac::timer::TimCore::from_ptr(T::regs()) } | ||
| 206 | } | ||
| 207 | |||
| 208 | #[cfg(not(stm32l0))] | ||
| 209 | fn regs_gp32_unchecked(&self) -> crate::pac::timer::TimGp32 { | ||
| 210 | unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) } | ||
| 211 | } | ||
| 212 | |||
| 213 | /// Start the timer. | ||
| 214 | pub fn start(&self) { | ||
| 215 | self.regs_core().cr1().modify(|r| r.set_cen(true)); | ||
| 216 | } | ||
| 217 | |||
| 218 | /// Stop the timer. | ||
| 219 | pub fn stop(&self) { | ||
| 220 | self.regs_core().cr1().modify(|r| r.set_cen(false)); | ||
| 221 | } | ||
| 222 | |||
| 223 | /// Reset the counter value to 0 | ||
| 224 | pub fn reset(&self) { | ||
| 225 | self.regs_core().cnt().write(|r| r.set_cnt(0)); | ||
| 226 | } | ||
| 227 | |||
| 228 | /// Set the frequency of how many times per second the timer counts up to the max value or down to 0. | ||
| 229 | /// | ||
| 230 | /// This means that in the default edge-aligned mode, | ||
| 231 | /// the timer counter will wrap around at the same frequency as is being set. | ||
| 232 | /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved | ||
| 233 | /// because it needs to count up and down. | ||
| 234 | pub fn set_frequency(&self, frequency: Hertz) { | ||
| 235 | let f = frequency.0; | ||
| 236 | assert!(f > 0); | ||
| 237 | let timer_f = T::frequency().0; | ||
| 238 | |||
| 239 | match T::BITS { | ||
| 240 | TimerBits::Bits16 => { | ||
| 241 | let pclk_ticks_per_timer_period = timer_f / f; | ||
| 242 | let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into()); | ||
| 243 | let divide_by = pclk_ticks_per_timer_period / (u32::from(psc) + 1); | ||
| 244 | |||
| 245 | // the timer counts `0..=arr`, we want it to count `0..divide_by` | ||
| 246 | let arr = unwrap!(u16::try_from(divide_by - 1)); | ||
| 247 | |||
| 248 | let regs = self.regs_core(); | ||
| 249 | regs.psc().write_value(psc); | ||
| 250 | regs.arr().write(|r| r.set_arr(arr)); | ||
| 251 | |||
| 252 | regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); | ||
| 253 | regs.egr().write(|r| r.set_ug(true)); | ||
| 254 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); | ||
| 255 | } | ||
| 256 | #[cfg(not(stm32l0))] | ||
| 257 | TimerBits::Bits32 => { | ||
| 258 | let pclk_ticks_per_timer_period = (timer_f / f) as u64; | ||
| 259 | let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into()); | ||
| 260 | let arr: u32 = unwrap!((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into()); | ||
| 261 | |||
| 262 | let regs = self.regs_gp32_unchecked(); | ||
| 263 | regs.psc().write_value(psc); | ||
| 264 | regs.arr().write_value(arr); | ||
| 265 | |||
| 266 | regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); | ||
| 267 | regs.egr().write(|r| r.set_ug(true)); | ||
| 268 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); | ||
| 269 | } | ||
| 270 | } | ||
| 271 | } | ||
| 272 | |||
| 273 | /// Clear update interrupt. | ||
| 274 | /// | ||
| 275 | /// Returns whether the update interrupt flag was set. | ||
| 276 | pub fn clear_update_interrupt(&self) -> bool { | ||
| 277 | let regs = self.regs_core(); | ||
| 278 | let sr = regs.sr().read(); | ||
| 279 | if sr.uif() { | ||
| 280 | regs.sr().modify(|r| { | ||
| 281 | r.set_uif(false); | ||
| 282 | }); | ||
| 283 | true | ||
| 284 | } else { | ||
| 285 | false | ||
| 286 | } | ||
| 287 | } | ||
| 288 | |||
| 289 | /// Enable/disable the update interrupt. | ||
| 290 | pub fn enable_update_interrupt(&self, enable: bool) { | ||
| 291 | self.regs_core().dier().modify(|r| r.set_uie(enable)); | ||
| 292 | } | ||
| 293 | |||
| 294 | /// Enable/disable autoreload preload. | ||
| 295 | pub fn set_autoreload_preload(&self, enable: bool) { | ||
| 296 | self.regs_core().cr1().modify(|r| r.set_arpe(enable)); | ||
| 297 | } | ||
| 298 | |||
| 299 | /// Get the timer frequency. | ||
| 300 | pub fn get_frequency(&self) -> Hertz { | ||
| 301 | let timer_f = T::frequency(); | ||
| 302 | |||
| 303 | match T::BITS { | ||
| 304 | TimerBits::Bits16 => { | ||
| 305 | let regs = self.regs_core(); | ||
| 306 | let arr = regs.arr().read().arr(); | ||
| 307 | let psc = regs.psc().read(); | ||
| 308 | |||
| 309 | timer_f / arr / (psc + 1) | ||
| 310 | } | ||
| 311 | #[cfg(not(stm32l0))] | ||
| 312 | TimerBits::Bits32 => { | ||
| 313 | let regs = self.regs_gp32_unchecked(); | ||
| 314 | let arr = regs.arr().read(); | ||
| 315 | let psc = regs.psc().read(); | ||
| 316 | |||
| 317 | timer_f / arr / (psc + 1) | ||
| 318 | } | ||
| 319 | } | ||
| 320 | } | ||
| 321 | } | ||
| 322 | |||
| 323 | impl<'d, T: BasicNoCr2Instance> Timer<'d, T> { | ||
| 324 | /// Get access to the Baisc 16bit timer registers. | ||
| 325 | /// | ||
| 326 | /// Note: This works even if the timer is more capable, because registers | ||
| 327 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 328 | /// for a given set of capabilities, and having it transparently work with | ||
| 329 | /// more capable timers. | ||
| 330 | pub fn regs_basic_no_cr2(&self) -> crate::pac::timer::TimBasicNoCr2 { | ||
| 331 | unsafe { crate::pac::timer::TimBasicNoCr2::from_ptr(T::regs()) } | ||
| 332 | } | ||
| 333 | |||
| 334 | /// Enable/disable the update dma. | ||
| 335 | pub fn enable_update_dma(&self, enable: bool) { | ||
| 336 | self.regs_basic_no_cr2().dier().modify(|r| r.set_ude(enable)); | ||
| 337 | } | ||
| 338 | |||
| 339 | /// Get the update dma enable/disable state. | ||
| 340 | pub fn get_update_dma_state(&self) -> bool { | ||
| 341 | self.regs_basic_no_cr2().dier().read().ude() | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | impl<'d, T: BasicInstance> Timer<'d, T> { | ||
| 346 | /// Get access to the Baisc 16bit timer registers. | ||
| 347 | /// | ||
| 348 | /// Note: This works even if the timer is more capable, because registers | ||
| 349 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 350 | /// for a given set of capabilities, and having it transparently work with | ||
| 351 | /// more capable timers. | ||
| 352 | pub fn regs_basic(&self) -> crate::pac::timer::TimBasic { | ||
| 353 | unsafe { crate::pac::timer::TimBasic::from_ptr(T::regs()) } | ||
| 354 | } | ||
| 355 | } | ||
| 356 | |||
| 357 | impl<'d, T: GeneralInstance1Channel> Timer<'d, T> { | ||
| 358 | /// Get access to the general purpose 1 channel 16bit timer registers. | ||
| 359 | /// | ||
| 360 | /// Note: This works even if the timer is more capable, because registers | ||
| 361 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 362 | /// for a given set of capabilities, and having it transparently work with | ||
| 363 | /// more capable timers. | ||
| 364 | pub fn regs_1ch(&self) -> crate::pac::timer::Tim1ch { | ||
| 365 | unsafe { crate::pac::timer::Tim1ch::from_ptr(T::regs()) } | ||
| 366 | } | ||
| 367 | |||
| 368 | /// Set clock divider. | ||
| 369 | pub fn set_clock_division(&self, ckd: vals::Ckd) { | ||
| 370 | self.regs_1ch().cr1().modify(|r| r.set_ckd(ckd)); | ||
| 371 | } | ||
| 372 | |||
| 373 | /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. | ||
| 374 | pub fn get_max_compare_value(&self) -> u32 { | ||
| 375 | match T::BITS { | ||
| 376 | TimerBits::Bits16 => self.regs_1ch().arr().read().arr() as u32, | ||
| 377 | #[cfg(not(stm32l0))] | ||
| 378 | TimerBits::Bits32 => self.regs_gp32_unchecked().arr().read(), | ||
| 379 | } | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | impl<'d, T: GeneralInstance2Channel> Timer<'d, T> { | ||
| 384 | /// Get access to the general purpose 2 channel 16bit timer registers. | ||
| 385 | /// | ||
| 386 | /// Note: This works even if the timer is more capable, because registers | ||
| 387 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 388 | /// for a given set of capabilities, and having it transparently work with | ||
| 389 | /// more capable timers. | ||
| 390 | pub fn regs_2ch(&self) -> crate::pac::timer::Tim2ch { | ||
| 391 | unsafe { crate::pac::timer::Tim2ch::from_ptr(T::regs()) } | ||
| 392 | } | ||
| 393 | } | ||
| 394 | |||
| 395 | impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { | ||
| 396 | /// Get access to the general purpose 16bit timer registers. | ||
| 397 | /// | ||
| 398 | /// Note: This works even if the timer is more capable, because registers | ||
| 399 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 400 | /// for a given set of capabilities, and having it transparently work with | ||
| 401 | /// more capable timers. | ||
| 402 | pub fn regs_gp16(&self) -> crate::pac::timer::TimGp16 { | ||
| 403 | unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) } | ||
| 404 | } | ||
| 405 | |||
| 406 | /// Enable timer outputs. | ||
| 407 | pub fn enable_outputs(&self) { | ||
| 408 | self.tim.enable_outputs() | ||
| 409 | } | ||
| 410 | |||
| 411 | /// Set counting mode. | ||
| 412 | pub fn set_counting_mode(&self, mode: CountingMode) { | ||
| 413 | let (cms, dir) = mode.into(); | ||
| 414 | |||
| 415 | let timer_enabled = self.regs_core().cr1().read().cen(); | ||
| 416 | // Changing from edge aligned to center aligned (and vice versa) is not allowed while the timer is running. | ||
| 417 | // Changing direction is discouraged while the timer is running. | ||
| 418 | assert!(!timer_enabled); | ||
| 419 | |||
| 420 | self.regs_gp16().cr1().modify(|r| r.set_dir(dir)); | ||
| 421 | self.regs_gp16().cr1().modify(|r| r.set_cms(cms)) | ||
| 422 | } | ||
| 423 | |||
| 424 | /// Get counting mode. | ||
| 425 | pub fn get_counting_mode(&self) -> CountingMode { | ||
| 426 | let cr1 = self.regs_gp16().cr1().read(); | ||
| 427 | (cr1.cms(), cr1.dir()).into() | ||
| 428 | } | ||
| 429 | |||
| 430 | /// Set input capture filter. | ||
| 431 | pub fn set_input_capture_filter(&self, channel: Channel, icf: vals::FilterValue) { | ||
| 432 | let raw_channel = channel.index(); | ||
| 433 | self.regs_gp16() | ||
| 434 | .ccmr_input(raw_channel / 2) | ||
| 435 | .modify(|r| r.set_icf(raw_channel % 2, icf)); | ||
| 436 | } | ||
| 437 | |||
| 438 | /// Clear input interrupt. | ||
| 439 | pub fn clear_input_interrupt(&self, channel: Channel) { | ||
| 440 | self.regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false)); | ||
| 441 | } | ||
| 442 | |||
| 443 | /// Enable input interrupt. | ||
| 444 | pub fn enable_input_interrupt(&self, channel: Channel, enable: bool) { | ||
| 445 | self.regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable)); | ||
| 446 | } | ||
| 447 | |||
| 448 | /// Set input capture prescaler. | ||
| 449 | pub fn set_input_capture_prescaler(&self, channel: Channel, factor: u8) { | ||
| 450 | let raw_channel = channel.index(); | ||
| 451 | self.regs_gp16() | ||
| 452 | .ccmr_input(raw_channel / 2) | ||
| 453 | .modify(|r| r.set_icpsc(raw_channel % 2, factor)); | ||
| 454 | } | ||
| 455 | |||
| 456 | /// Set input TI selection. | ||
| 457 | pub fn set_input_ti_selection(&self, channel: Channel, tisel: InputTISelection) { | ||
| 458 | let raw_channel = channel.index(); | ||
| 459 | self.regs_gp16() | ||
| 460 | .ccmr_input(raw_channel / 2) | ||
| 461 | .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); | ||
| 462 | } | ||
| 463 | |||
| 464 | /// Set input capture mode. | ||
| 465 | pub fn set_input_capture_mode(&self, channel: Channel, mode: InputCaptureMode) { | ||
| 466 | self.regs_gp16().ccer().modify(|r| match mode { | ||
| 467 | InputCaptureMode::Rising => { | ||
| 468 | r.set_ccnp(channel.index(), false); | ||
| 469 | r.set_ccp(channel.index(), false); | ||
| 470 | } | ||
| 471 | InputCaptureMode::Falling => { | ||
| 472 | r.set_ccnp(channel.index(), false); | ||
| 473 | r.set_ccp(channel.index(), true); | ||
| 474 | } | ||
| 475 | InputCaptureMode::BothEdges => { | ||
| 476 | r.set_ccnp(channel.index(), true); | ||
| 477 | r.set_ccp(channel.index(), true); | ||
| 478 | } | ||
| 479 | }); | ||
| 480 | } | ||
| 481 | |||
| 482 | /// Set output compare mode. | ||
| 483 | pub fn set_output_compare_mode(&self, channel: Channel, mode: OutputCompareMode) { | ||
| 484 | let raw_channel: usize = channel.index(); | ||
| 485 | self.regs_gp16() | ||
| 486 | .ccmr_output(raw_channel / 2) | ||
| 487 | .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); | ||
| 488 | } | ||
| 489 | |||
| 490 | /// Set output polarity. | ||
| 491 | pub fn set_output_polarity(&self, channel: Channel, polarity: OutputPolarity) { | ||
| 492 | self.regs_gp16() | ||
| 493 | .ccer() | ||
| 494 | .modify(|w| w.set_ccp(channel.index(), polarity.into())); | ||
| 495 | } | ||
| 496 | |||
| 497 | /// Enable/disable a channel. | ||
| 498 | pub fn enable_channel(&self, channel: Channel, enable: bool) { | ||
| 499 | self.regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable)); | ||
| 500 | } | ||
| 501 | |||
| 502 | /// Get enable/disable state of a channel | ||
| 503 | pub fn get_channel_enable_state(&self, channel: Channel) -> bool { | ||
| 504 | self.regs_gp16().ccer().read().cce(channel.index()) | ||
| 505 | } | ||
| 506 | |||
| 507 | /// Set compare value for a channel. | ||
| 508 | pub fn set_compare_value(&self, channel: Channel, value: u32) { | ||
| 509 | match T::BITS { | ||
| 510 | TimerBits::Bits16 => { | ||
| 511 | let value = unwrap!(u16::try_from(value)); | ||
| 512 | self.regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); | ||
| 513 | } | ||
| 514 | #[cfg(not(stm32l0))] | ||
| 515 | TimerBits::Bits32 => { | ||
| 516 | self.regs_gp32_unchecked().ccr(channel.index()).write_value(value); | ||
| 517 | } | ||
| 518 | } | ||
| 519 | } | ||
| 520 | |||
| 521 | /// Get compare value for a channel. | ||
| 522 | pub fn get_compare_value(&self, channel: Channel) -> u32 { | ||
| 523 | match T::BITS { | ||
| 524 | TimerBits::Bits16 => self.regs_gp16().ccr(channel.index()).read().ccr() as u32, | ||
| 525 | #[cfg(not(stm32l0))] | ||
| 526 | TimerBits::Bits32 => self.regs_gp32_unchecked().ccr(channel.index()).read(), | ||
| 527 | } | ||
| 528 | } | ||
| 529 | |||
| 530 | /// Get capture value for a channel. | ||
| 531 | pub fn get_capture_value(&self, channel: Channel) -> u32 { | ||
| 532 | self.get_compare_value(channel) | ||
| 533 | } | ||
| 534 | |||
| 535 | /// Set output compare preload. | ||
| 536 | pub fn set_output_compare_preload(&self, channel: Channel, preload: bool) { | ||
| 537 | let channel_index = channel.index(); | ||
| 538 | self.regs_gp16() | ||
| 539 | .ccmr_output(channel_index / 2) | ||
| 540 | .modify(|w| w.set_ocpe(channel_index % 2, preload)); | ||
| 541 | } | ||
| 542 | |||
| 543 | /// Get capture compare DMA selection | ||
| 544 | pub fn get_cc_dma_selection(&self) -> vals::Ccds { | ||
| 545 | self.regs_gp16().cr2().read().ccds() | ||
| 546 | } | ||
| 547 | |||
| 548 | /// Set capture compare DMA selection | ||
| 549 | pub fn set_cc_dma_selection(&self, ccds: vals::Ccds) { | ||
| 550 | self.regs_gp16().cr2().modify(|w| w.set_ccds(ccds)) | ||
| 551 | } | ||
| 552 | |||
| 553 | /// Get capture compare DMA enable state | ||
| 554 | pub fn get_cc_dma_enable_state(&self, channel: Channel) -> bool { | ||
| 555 | self.regs_gp16().dier().read().ccde(channel.index()) | ||
| 556 | } | ||
| 557 | |||
| 558 | /// Set capture compare DMA enable state | ||
| 559 | pub fn set_cc_dma_enable_state(&self, channel: Channel, ccde: bool) { | ||
| 560 | self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde)) | ||
| 561 | } | ||
| 562 | } | ||
| 563 | |||
| 564 | #[cfg(not(stm32l0))] | ||
| 565 | impl<'d, T: GeneralInstance32bit4Channel> Timer<'d, T> { | ||
| 566 | /// Get access to the general purpose 32bit timer registers. | ||
| 567 | /// | ||
| 568 | /// Note: This works even if the timer is more capable, because registers | ||
| 569 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 570 | /// for a given set of capabilities, and having it transparently work with | ||
| 571 | /// more capable timers. | ||
| 572 | pub fn regs_gp32(&self) -> crate::pac::timer::TimGp32 { | ||
| 573 | unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) } | ||
| 574 | } | ||
| 575 | } | ||
| 576 | |||
| 577 | #[cfg(not(stm32l0))] | ||
| 578 | impl<'d, T: AdvancedInstance1Channel> Timer<'d, T> { | ||
| 579 | /// Get access to the general purpose 1 channel with one complementary 16bit timer registers. | ||
| 580 | /// | ||
| 581 | /// Note: This works even if the timer is more capable, because registers | ||
| 582 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 583 | /// for a given set of capabilities, and having it transparently work with | ||
| 584 | /// more capable timers. | ||
| 585 | pub fn regs_1ch_cmp(&self) -> crate::pac::timer::Tim1chCmp { | ||
| 586 | unsafe { crate::pac::timer::Tim1chCmp::from_ptr(T::regs()) } | ||
| 587 | } | ||
| 588 | |||
| 589 | /// Set clock divider for the dead time. | ||
| 590 | pub fn set_dead_time_clock_division(&self, value: vals::Ckd) { | ||
| 591 | self.regs_1ch_cmp().cr1().modify(|w| w.set_ckd(value)); | ||
| 592 | } | ||
| 593 | |||
| 594 | /// Set dead time, as a fraction of the max duty value. | ||
| 595 | pub fn set_dead_time_value(&self, value: u8) { | ||
| 596 | self.regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value)); | ||
| 597 | } | ||
| 598 | |||
| 599 | /// Set state of MOE-bit in BDTR register to en-/disable output | ||
| 600 | pub fn set_moe(&self, enable: bool) { | ||
| 601 | self.regs_1ch_cmp().bdtr().modify(|w| w.set_moe(enable)); | ||
| 602 | } | ||
| 603 | } | ||
| 604 | |||
| 605 | #[cfg(not(stm32l0))] | ||
| 606 | impl<'d, T: AdvancedInstance2Channel> Timer<'d, T> { | ||
| 607 | /// Get access to the general purpose 2 channel with one complementary 16bit timer registers. | ||
| 608 | /// | ||
| 609 | /// Note: This works even if the timer is more capable, because registers | ||
| 610 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 611 | /// for a given set of capabilities, and having it transparently work with | ||
| 612 | /// more capable timers. | ||
| 613 | pub fn regs_2ch_cmp(&self) -> crate::pac::timer::Tim2chCmp { | ||
| 614 | unsafe { crate::pac::timer::Tim2chCmp::from_ptr(T::regs()) } | ||
| 615 | } | ||
| 616 | } | ||
| 617 | |||
| 618 | #[cfg(not(stm32l0))] | ||
| 619 | impl<'d, T: AdvancedInstance4Channel> Timer<'d, T> { | ||
| 620 | /// Get access to the advanced timer registers. | ||
| 621 | pub fn regs_advanced(&self) -> crate::pac::timer::TimAdv { | ||
| 622 | unsafe { crate::pac::timer::TimAdv::from_ptr(T::regs()) } | ||
| 623 | } | ||
| 624 | |||
| 625 | /// Set complementary output polarity. | ||
| 626 | pub fn set_complementary_output_polarity(&self, channel: Channel, polarity: OutputPolarity) { | ||
| 627 | self.regs_advanced() | ||
| 628 | .ccer() | ||
| 629 | .modify(|w| w.set_ccnp(channel.index(), polarity.into())); | ||
| 630 | } | ||
| 631 | |||
| 632 | /// Enable/disable a complementary channel. | ||
| 633 | pub fn enable_complementary_channel(&self, channel: Channel, enable: bool) { | ||
| 634 | self.regs_advanced() | ||
| 635 | .ccer() | ||
| 636 | .modify(|w| w.set_ccne(channel.index(), enable)); | ||
| 637 | } | ||
| 638 | } | ||
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index e5e84c255..2ba6b3f11 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs | |||
| @@ -1,490 +1,13 @@ | |||
| 1 | //! Timers, PWM, quadrature decoder. | 1 | //! Timers, PWM, quadrature decoder. |
| 2 | //! | ||
| 3 | |||
| 4 | //! Timer inheritance | ||
| 5 | //! | ||
| 6 | |||
| 7 | // sealed: | ||
| 8 | // | ||
| 9 | // Core -------------------------> 1CH -------------------------> 1CH_CMP | ||
| 10 | // | | ^ | | ||
| 11 | // +--> Basic_NoCr2 --> Basic +--> 2CH --> GP16 --> GP32 | +--> 2CH_CMP --> ADV | ||
| 12 | // | | | ^ | | ^ ^ | ||
| 13 | // | | +------|--|--------------|-----------+ | | ||
| 14 | // | +--------------------+ +--------------|-----------|---------+ | ||
| 15 | // | | | | | ||
| 16 | // | +--------------------------------------|-----------+ | ||
| 17 | // +----------------------------------------------------+ | ||
| 18 | |||
| 19 | //! ```text | ||
| 20 | //! BasicInstance --> CaptureCompare16bitInstance --+--> ComplementaryCaptureCompare16bitInstance | ||
| 21 | //! | | ||
| 22 | //! +--> CaptureCompare32bitInstance | ||
| 23 | //! ``` | ||
| 24 | //! | ||
| 25 | //! Mapping: | ||
| 26 | //! | ||
| 27 | //! | trait | timer | | ||
| 28 | //! | :----------------------------------------: | ------------------------------------------------------------------------------------------------- | | ||
| 29 | //! | [BasicInstance] | Basic Timer | | ||
| 30 | //! | [CaptureCompare16bitInstance] | 1-channel Timer, 2-channel Timer, General Purpose 16-bit Timer | | ||
| 31 | //! | [CaptureCompare32bitInstance] | General Purpose 32-bit Timer | | ||
| 32 | //! | [ComplementaryCaptureCompare16bitInstance] | 1-channel with one complentary Timer, 2-channel with one complentary Timer, Advance Control Timer | | ||
| 33 | 2 | ||
| 34 | #[cfg(not(stm32l0))] | 3 | #[cfg(not(stm32l0))] |
| 35 | pub mod complementary_pwm; | 4 | pub mod complementary_pwm; |
| 5 | pub mod low_level; | ||
| 36 | pub mod qei; | 6 | pub mod qei; |
| 37 | pub mod simple_pwm; | 7 | pub mod simple_pwm; |
| 38 | 8 | ||
| 39 | use stm32_metapac::timer::vals; | ||
| 40 | |||
| 41 | use crate::interrupt; | 9 | use crate::interrupt; |
| 42 | use crate::rcc::RccPeripheral; | 10 | use crate::rcc::RccPeripheral; |
| 43 | use crate::time::Hertz; | ||
| 44 | |||
| 45 | /// Low-level timer access. | ||
| 46 | #[cfg(feature = "unstable-pac")] | ||
| 47 | pub mod low_level { | ||
| 48 | pub use super::sealed::*; | ||
| 49 | } | ||
| 50 | |||
| 51 | pub(crate) mod sealed { | ||
| 52 | use super::*; | ||
| 53 | |||
| 54 | /// Virtual Core 16-bit timer instance. | ||
| 55 | pub trait CoreInstance: RccPeripheral { | ||
| 56 | /// Interrupt for this timer. | ||
| 57 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 58 | |||
| 59 | /// Get access to the virutal core 16bit timer registers. | ||
| 60 | /// | ||
| 61 | /// Note: This works even if the timer is more capable, because registers | ||
| 62 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 63 | /// for a given set of capabilities, and having it transparently work with | ||
| 64 | /// more capable timers. | ||
| 65 | fn regs_core() -> crate::pac::timer::TimCore; | ||
| 66 | |||
| 67 | /// Start the timer. | ||
| 68 | fn start(&self) { | ||
| 69 | Self::regs_core().cr1().modify(|r| r.set_cen(true)); | ||
| 70 | } | ||
| 71 | |||
| 72 | /// Stop the timer. | ||
| 73 | fn stop(&self) { | ||
| 74 | Self::regs_core().cr1().modify(|r| r.set_cen(false)); | ||
| 75 | } | ||
| 76 | |||
| 77 | /// Reset the counter value to 0 | ||
| 78 | fn reset(&self) { | ||
| 79 | Self::regs_core().cnt().write(|r| r.set_cnt(0)); | ||
| 80 | } | ||
| 81 | |||
| 82 | /// Set the frequency of how many times per second the timer counts up to the max value or down to 0. | ||
| 83 | /// | ||
| 84 | /// This means that in the default edge-aligned mode, | ||
| 85 | /// the timer counter will wrap around at the same frequency as is being set. | ||
| 86 | /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved | ||
| 87 | /// because it needs to count up and down. | ||
| 88 | fn set_frequency(&self, frequency: Hertz) { | ||
| 89 | let f = frequency.0; | ||
| 90 | let timer_f = Self::frequency().0; | ||
| 91 | assert!(f > 0); | ||
| 92 | let pclk_ticks_per_timer_period = timer_f / f; | ||
| 93 | let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into()); | ||
| 94 | let divide_by = pclk_ticks_per_timer_period / (u32::from(psc) + 1); | ||
| 95 | |||
| 96 | // the timer counts `0..=arr`, we want it to count `0..divide_by` | ||
| 97 | let arr = unwrap!(u16::try_from(divide_by - 1)); | ||
| 98 | |||
| 99 | let regs = Self::regs_core(); | ||
| 100 | regs.psc().write_value(psc); | ||
| 101 | regs.arr().write(|r| r.set_arr(arr)); | ||
| 102 | |||
| 103 | regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); | ||
| 104 | regs.egr().write(|r| r.set_ug(true)); | ||
| 105 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); | ||
| 106 | } | ||
| 107 | |||
| 108 | /// Clear update interrupt. | ||
| 109 | /// | ||
| 110 | /// Returns whether the update interrupt flag was set. | ||
| 111 | fn clear_update_interrupt(&self) -> bool { | ||
| 112 | let regs = Self::regs_core(); | ||
| 113 | let sr = regs.sr().read(); | ||
| 114 | if sr.uif() { | ||
| 115 | regs.sr().modify(|r| { | ||
| 116 | r.set_uif(false); | ||
| 117 | }); | ||
| 118 | true | ||
| 119 | } else { | ||
| 120 | false | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | /// Enable/disable the update interrupt. | ||
| 125 | fn enable_update_interrupt(&self, enable: bool) { | ||
| 126 | Self::regs_core().dier().modify(|r| r.set_uie(enable)); | ||
| 127 | } | ||
| 128 | |||
| 129 | /// Enable/disable autoreload preload. | ||
| 130 | fn set_autoreload_preload(&self, enable: bool) { | ||
| 131 | Self::regs_core().cr1().modify(|r| r.set_arpe(enable)); | ||
| 132 | } | ||
| 133 | |||
| 134 | /// Get the timer frequency. | ||
| 135 | fn get_frequency(&self) -> Hertz { | ||
| 136 | let timer_f = Self::frequency(); | ||
| 137 | |||
| 138 | let regs = Self::regs_core(); | ||
| 139 | let arr = regs.arr().read().arr(); | ||
| 140 | let psc = regs.psc().read(); | ||
| 141 | |||
| 142 | timer_f / arr / (psc + 1) | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | /// Virtual Basic without CR2 16-bit timer instance. | ||
| 147 | pub trait BasicNoCr2Instance: CoreInstance { | ||
| 148 | /// Get access to the Baisc 16bit timer registers. | ||
| 149 | /// | ||
| 150 | /// Note: This works even if the timer is more capable, because registers | ||
| 151 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 152 | /// for a given set of capabilities, and having it transparently work with | ||
| 153 | /// more capable timers. | ||
| 154 | fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2; | ||
| 155 | |||
| 156 | /// Enable/disable the update dma. | ||
| 157 | fn enable_update_dma(&self, enable: bool) { | ||
| 158 | Self::regs_basic_no_cr2().dier().modify(|r| r.set_ude(enable)); | ||
| 159 | } | ||
| 160 | |||
| 161 | /// Get the update dma enable/disable state. | ||
| 162 | fn get_update_dma_state(&self) -> bool { | ||
| 163 | Self::regs_basic_no_cr2().dier().read().ude() | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | /// Basic 16-bit timer instance. | ||
| 168 | pub trait BasicInstance: BasicNoCr2Instance { | ||
| 169 | /// Get access to the Baisc 16bit timer registers. | ||
| 170 | /// | ||
| 171 | /// Note: This works even if the timer is more capable, because registers | ||
| 172 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 173 | /// for a given set of capabilities, and having it transparently work with | ||
| 174 | /// more capable timers. | ||
| 175 | fn regs_basic() -> crate::pac::timer::TimBasic; | ||
| 176 | } | ||
| 177 | |||
| 178 | /// Gneral-purpose 1 channel 16-bit timer instance. | ||
| 179 | pub trait GeneralPurpose1ChannelInstance: CoreInstance { | ||
| 180 | /// Get access to the general purpose 1 channel 16bit timer registers. | ||
| 181 | /// | ||
| 182 | /// Note: This works even if the timer is more capable, because registers | ||
| 183 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 184 | /// for a given set of capabilities, and having it transparently work with | ||
| 185 | /// more capable timers. | ||
| 186 | fn regs_1ch() -> crate::pac::timer::Tim1ch; | ||
| 187 | |||
| 188 | /// Set clock divider. | ||
| 189 | fn set_clock_division(&self, ckd: vals::Ckd) { | ||
| 190 | Self::regs_1ch().cr1().modify(|r| r.set_ckd(ckd)); | ||
| 191 | } | ||
| 192 | |||
| 193 | /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. | ||
| 194 | fn get_max_compare_value(&self) -> u16 { | ||
| 195 | Self::regs_1ch().arr().read().arr() | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | /// Gneral-purpose 1 channel 16-bit timer instance. | ||
| 200 | pub trait GeneralPurpose2ChannelInstance: GeneralPurpose1ChannelInstance { | ||
| 201 | /// Get access to the general purpose 2 channel 16bit timer registers. | ||
| 202 | /// | ||
| 203 | /// Note: This works even if the timer is more capable, because registers | ||
| 204 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 205 | /// for a given set of capabilities, and having it transparently work with | ||
| 206 | /// more capable timers. | ||
| 207 | fn regs_2ch() -> crate::pac::timer::Tim2ch; | ||
| 208 | } | ||
| 209 | |||
| 210 | /// Gneral-purpose 16-bit timer instance. | ||
| 211 | pub trait GeneralPurpose16bitInstance: BasicInstance + GeneralPurpose2ChannelInstance { | ||
| 212 | /// Get access to the general purpose 16bit timer registers. | ||
| 213 | /// | ||
| 214 | /// Note: This works even if the timer is more capable, because registers | ||
| 215 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 216 | /// for a given set of capabilities, and having it transparently work with | ||
| 217 | /// more capable timers. | ||
| 218 | fn regs_gp16() -> crate::pac::timer::TimGp16; | ||
| 219 | |||
| 220 | /// Set counting mode. | ||
| 221 | fn set_counting_mode(&self, mode: CountingMode) { | ||
| 222 | let (cms, dir) = mode.into(); | ||
| 223 | |||
| 224 | let timer_enabled = Self::regs_core().cr1().read().cen(); | ||
| 225 | // Changing from edge aligned to center aligned (and vice versa) is not allowed while the timer is running. | ||
| 226 | // Changing direction is discouraged while the timer is running. | ||
| 227 | assert!(!timer_enabled); | ||
| 228 | |||
| 229 | Self::regs_gp16().cr1().modify(|r| r.set_dir(dir)); | ||
| 230 | Self::regs_gp16().cr1().modify(|r| r.set_cms(cms)) | ||
| 231 | } | ||
| 232 | |||
| 233 | /// Get counting mode. | ||
| 234 | fn get_counting_mode(&self) -> CountingMode { | ||
| 235 | let cr1 = Self::regs_gp16().cr1().read(); | ||
| 236 | (cr1.cms(), cr1.dir()).into() | ||
| 237 | } | ||
| 238 | |||
| 239 | /// Set input capture filter. | ||
| 240 | fn set_input_capture_filter(&self, channel: Channel, icf: vals::FilterValue) { | ||
| 241 | let raw_channel = channel.index(); | ||
| 242 | Self::regs_gp16() | ||
| 243 | .ccmr_input(raw_channel / 2) | ||
| 244 | .modify(|r| r.set_icf(raw_channel % 2, icf)); | ||
| 245 | } | ||
| 246 | |||
| 247 | /// Clear input interrupt. | ||
| 248 | fn clear_input_interrupt(&self, channel: Channel) { | ||
| 249 | Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false)); | ||
| 250 | } | ||
| 251 | |||
| 252 | /// Enable input interrupt. | ||
| 253 | fn enable_input_interrupt(&self, channel: Channel, enable: bool) { | ||
| 254 | Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable)); | ||
| 255 | } | ||
| 256 | |||
| 257 | /// Set input capture prescaler. | ||
| 258 | fn set_input_capture_prescaler(&self, channel: Channel, factor: u8) { | ||
| 259 | let raw_channel = channel.index(); | ||
| 260 | Self::regs_gp16() | ||
| 261 | .ccmr_input(raw_channel / 2) | ||
| 262 | .modify(|r| r.set_icpsc(raw_channel % 2, factor)); | ||
| 263 | } | ||
| 264 | |||
| 265 | /// Set input TI selection. | ||
| 266 | fn set_input_ti_selection(&self, channel: Channel, tisel: InputTISelection) { | ||
| 267 | let raw_channel = channel.index(); | ||
| 268 | Self::regs_gp16() | ||
| 269 | .ccmr_input(raw_channel / 2) | ||
| 270 | .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); | ||
| 271 | } | ||
| 272 | |||
| 273 | /// Set input capture mode. | ||
| 274 | fn set_input_capture_mode(&self, channel: Channel, mode: InputCaptureMode) { | ||
| 275 | Self::regs_gp16().ccer().modify(|r| match mode { | ||
| 276 | InputCaptureMode::Rising => { | ||
| 277 | r.set_ccnp(channel.index(), false); | ||
| 278 | r.set_ccp(channel.index(), false); | ||
| 279 | } | ||
| 280 | InputCaptureMode::Falling => { | ||
| 281 | r.set_ccnp(channel.index(), false); | ||
| 282 | r.set_ccp(channel.index(), true); | ||
| 283 | } | ||
| 284 | InputCaptureMode::BothEdges => { | ||
| 285 | r.set_ccnp(channel.index(), true); | ||
| 286 | r.set_ccp(channel.index(), true); | ||
| 287 | } | ||
| 288 | }); | ||
| 289 | } | ||
| 290 | |||
| 291 | /// Set output compare mode. | ||
| 292 | fn set_output_compare_mode(&self, channel: Channel, mode: OutputCompareMode) { | ||
| 293 | let raw_channel: usize = channel.index(); | ||
| 294 | Self::regs_gp16() | ||
| 295 | .ccmr_output(raw_channel / 2) | ||
| 296 | .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); | ||
| 297 | } | ||
| 298 | |||
| 299 | /// Set output polarity. | ||
| 300 | fn set_output_polarity(&self, channel: Channel, polarity: OutputPolarity) { | ||
| 301 | Self::regs_gp16() | ||
| 302 | .ccer() | ||
| 303 | .modify(|w| w.set_ccp(channel.index(), polarity.into())); | ||
| 304 | } | ||
| 305 | |||
| 306 | /// Enable/disable a channel. | ||
| 307 | fn enable_channel(&self, channel: Channel, enable: bool) { | ||
| 308 | Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable)); | ||
| 309 | } | ||
| 310 | |||
| 311 | /// Get enable/disable state of a channel | ||
| 312 | fn get_channel_enable_state(&self, channel: Channel) -> bool { | ||
| 313 | Self::regs_gp16().ccer().read().cce(channel.index()) | ||
| 314 | } | ||
| 315 | |||
| 316 | /// Set compare value for a channel. | ||
| 317 | fn set_compare_value(&self, channel: Channel, value: u16) { | ||
| 318 | Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); | ||
| 319 | } | ||
| 320 | |||
| 321 | /// Get capture value for a channel. | ||
| 322 | fn get_capture_value(&self, channel: Channel) -> u16 { | ||
| 323 | Self::regs_gp16().ccr(channel.index()).read().ccr() | ||
| 324 | } | ||
| 325 | |||
| 326 | /// Get compare value for a channel. | ||
| 327 | fn get_compare_value(&self, channel: Channel) -> u16 { | ||
| 328 | Self::regs_gp16().ccr(channel.index()).read().ccr() | ||
| 329 | } | ||
| 330 | |||
| 331 | /// Set output compare preload. | ||
| 332 | fn set_output_compare_preload(&self, channel: Channel, preload: bool) { | ||
| 333 | let channel_index = channel.index(); | ||
| 334 | Self::regs_gp16() | ||
| 335 | .ccmr_output(channel_index / 2) | ||
| 336 | .modify(|w| w.set_ocpe(channel_index % 2, preload)); | ||
| 337 | } | ||
| 338 | |||
| 339 | /// Get capture compare DMA selection | ||
| 340 | fn get_cc_dma_selection(&self) -> super::vals::Ccds { | ||
| 341 | Self::regs_gp16().cr2().read().ccds() | ||
| 342 | } | ||
| 343 | |||
| 344 | /// Set capture compare DMA selection | ||
| 345 | fn set_cc_dma_selection(&self, ccds: super::vals::Ccds) { | ||
| 346 | Self::regs_gp16().cr2().modify(|w| w.set_ccds(ccds)) | ||
| 347 | } | ||
| 348 | |||
| 349 | /// Get capture compare DMA enable state | ||
| 350 | fn get_cc_dma_enable_state(&self, channel: Channel) -> bool { | ||
| 351 | Self::regs_gp16().dier().read().ccde(channel.index()) | ||
| 352 | } | ||
| 353 | |||
| 354 | /// Set capture compare DMA enable state | ||
| 355 | fn set_cc_dma_enable_state(&self, channel: Channel, ccde: bool) { | ||
| 356 | Self::regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde)) | ||
| 357 | } | ||
| 358 | } | ||
| 359 | |||
| 360 | #[cfg(not(stm32l0))] | ||
| 361 | /// Gneral-purpose 32-bit timer instance. | ||
| 362 | pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { | ||
| 363 | /// Get access to the general purpose 32bit timer registers. | ||
| 364 | /// | ||
| 365 | /// Note: This works even if the timer is more capable, because registers | ||
| 366 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 367 | /// for a given set of capabilities, and having it transparently work with | ||
| 368 | /// more capable timers. | ||
| 369 | fn regs_gp32() -> crate::pac::timer::TimGp32; | ||
| 370 | |||
| 371 | /// Set timer frequency. | ||
| 372 | fn set_frequency(&self, frequency: Hertz) { | ||
| 373 | let f = frequency.0; | ||
| 374 | assert!(f > 0); | ||
| 375 | let timer_f = Self::frequency().0; | ||
| 376 | let pclk_ticks_per_timer_period = (timer_f / f) as u64; | ||
| 377 | let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into()); | ||
| 378 | let arr: u32 = unwrap!((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into()); | ||
| 379 | |||
| 380 | let regs = Self::regs_gp32(); | ||
| 381 | regs.psc().write_value(psc); | ||
| 382 | regs.arr().write_value(arr); | ||
| 383 | |||
| 384 | regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); | ||
| 385 | regs.egr().write(|r| r.set_ug(true)); | ||
| 386 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); | ||
| 387 | } | ||
| 388 | |||
| 389 | /// Get timer frequency. | ||
| 390 | fn get_frequency(&self) -> Hertz { | ||
| 391 | let timer_f = Self::frequency(); | ||
| 392 | |||
| 393 | let regs = Self::regs_gp32(); | ||
| 394 | let arr = regs.arr().read(); | ||
| 395 | let psc = regs.psc().read(); | ||
| 396 | |||
| 397 | timer_f / arr / (psc + 1) | ||
| 398 | } | ||
| 399 | |||
| 400 | /// Set comapre value for a channel. | ||
| 401 | fn set_compare_value(&self, channel: Channel, value: u32) { | ||
| 402 | Self::regs_gp32().ccr(channel.index()).write_value(value); | ||
| 403 | } | ||
| 404 | |||
| 405 | /// Get capture value for a channel. | ||
| 406 | fn get_capture_value(&self, channel: Channel) -> u32 { | ||
| 407 | Self::regs_gp32().ccr(channel.index()).read() | ||
| 408 | } | ||
| 409 | |||
| 410 | /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. | ||
| 411 | fn get_max_compare_value(&self) -> u32 { | ||
| 412 | Self::regs_gp32().arr().read() | ||
| 413 | } | ||
| 414 | |||
| 415 | /// Get compare value for a channel. | ||
| 416 | fn get_compare_value(&self, channel: Channel) -> u32 { | ||
| 417 | Self::regs_gp32().ccr(channel.index()).read() | ||
| 418 | } | ||
| 419 | } | ||
| 420 | |||
| 421 | #[cfg(not(stm32l0))] | ||
| 422 | /// Gneral-purpose 1 channel with one complementary 16-bit timer instance. | ||
| 423 | pub trait GeneralPurpose1ChannelComplementaryInstance: BasicNoCr2Instance + GeneralPurpose1ChannelInstance { | ||
| 424 | /// Get access to the general purpose 1 channel with one complementary 16bit timer registers. | ||
| 425 | /// | ||
| 426 | /// Note: This works even if the timer is more capable, because registers | ||
| 427 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 428 | /// for a given set of capabilities, and having it transparently work with | ||
| 429 | /// more capable timers. | ||
| 430 | fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp; | ||
| 431 | |||
| 432 | /// Set clock divider for the dead time. | ||
| 433 | fn set_dead_time_clock_division(&self, value: vals::Ckd) { | ||
| 434 | Self::regs_1ch_cmp().cr1().modify(|w| w.set_ckd(value)); | ||
| 435 | } | ||
| 436 | |||
| 437 | /// Set dead time, as a fraction of the max duty value. | ||
| 438 | fn set_dead_time_value(&self, value: u8) { | ||
| 439 | Self::regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value)); | ||
| 440 | } | ||
| 441 | |||
| 442 | /// Set state of MOE-bit in BDTR register to en-/disable output | ||
| 443 | fn set_moe(&self, enable: bool) { | ||
| 444 | Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(enable)); | ||
| 445 | } | ||
| 446 | } | ||
| 447 | |||
| 448 | #[cfg(not(stm32l0))] | ||
| 449 | /// Gneral-purpose 2 channel with one complementary 16-bit timer instance. | ||
| 450 | pub trait GeneralPurpose2ChannelComplementaryInstance: | ||
| 451 | BasicInstance + GeneralPurpose2ChannelInstance + GeneralPurpose1ChannelComplementaryInstance | ||
| 452 | { | ||
| 453 | /// Get access to the general purpose 2 channel with one complementary 16bit timer registers. | ||
| 454 | /// | ||
| 455 | /// Note: This works even if the timer is more capable, because registers | ||
| 456 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 457 | /// for a given set of capabilities, and having it transparently work with | ||
| 458 | /// more capable timers. | ||
| 459 | fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp; | ||
| 460 | } | ||
| 461 | |||
| 462 | #[cfg(not(stm32l0))] | ||
| 463 | /// Advanced control timer instance. | ||
| 464 | pub trait AdvancedControlInstance: | ||
| 465 | GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance | ||
| 466 | { | ||
| 467 | /// Capture compare interrupt for this timer. | ||
| 468 | type CaptureCompareInterrupt: interrupt::typelevel::Interrupt; | ||
| 469 | |||
| 470 | /// Get access to the advanced timer registers. | ||
| 471 | fn regs_advanced() -> crate::pac::timer::TimAdv; | ||
| 472 | |||
| 473 | /// Set complementary output polarity. | ||
| 474 | fn set_complementary_output_polarity(&self, channel: Channel, polarity: OutputPolarity) { | ||
| 475 | Self::regs_advanced() | ||
| 476 | .ccer() | ||
| 477 | .modify(|w| w.set_ccnp(channel.index(), polarity.into())); | ||
| 478 | } | ||
| 479 | |||
| 480 | /// Enable/disable a complementary channel. | ||
| 481 | fn enable_complementary_channel(&self, channel: Channel, enable: bool) { | ||
| 482 | Self::regs_advanced() | ||
| 483 | .ccer() | ||
| 484 | .modify(|w| w.set_ccne(channel.index(), enable)); | ||
| 485 | } | ||
| 486 | } | ||
| 487 | } | ||
| 488 | 11 | ||
| 489 | /// Timer channel. | 12 | /// Timer channel. |
| 490 | #[derive(Clone, Copy)] | 13 | #[derive(Clone, Copy)] |
| @@ -511,181 +34,44 @@ impl Channel { | |||
| 511 | } | 34 | } |
| 512 | } | 35 | } |
| 513 | 36 | ||
| 514 | /// Input capture mode. | 37 | /// Amount of bits of a timer. |
| 515 | #[derive(Clone, Copy)] | 38 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| 516 | pub enum InputCaptureMode { | 39 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 517 | /// Rising edge only. | 40 | pub enum TimerBits { |
| 518 | Rising, | 41 | /// 16 bits. |
| 519 | /// Falling edge only. | 42 | Bits16, |
| 520 | Falling, | 43 | /// 32 bits. |
| 521 | /// Both rising or falling edges. | 44 | #[cfg(not(stm32l0))] |
| 522 | BothEdges, | 45 | Bits32, |
| 523 | } | 46 | } |
| 524 | 47 | ||
| 525 | /// Input TI selection. | 48 | /// Core timer instance. |
| 526 | #[derive(Clone, Copy)] | 49 | pub trait CoreInstance: RccPeripheral + 'static { |
| 527 | pub enum InputTISelection { | 50 | /// Interrupt for this timer. |
| 528 | /// Normal | 51 | type Interrupt: interrupt::typelevel::Interrupt; |
| 529 | Normal, | ||
| 530 | /// Alternate | ||
| 531 | Alternate, | ||
| 532 | /// TRC | ||
| 533 | TRC, | ||
| 534 | } | ||
| 535 | 52 | ||
| 536 | impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs { | 53 | /// Amount of bits this timer has. |
| 537 | fn from(tisel: InputTISelection) -> Self { | 54 | const BITS: TimerBits; |
| 538 | match tisel { | ||
| 539 | InputTISelection::Normal => stm32_metapac::timer::vals::CcmrInputCcs::TI4, | ||
| 540 | InputTISelection::Alternate => stm32_metapac::timer::vals::CcmrInputCcs::TI3, | ||
| 541 | InputTISelection::TRC => stm32_metapac::timer::vals::CcmrInputCcs::TRC, | ||
| 542 | } | ||
| 543 | } | ||
| 544 | } | ||
| 545 | 55 | ||
| 546 | /// Timer counting mode. | 56 | /// Registers for this timer. |
| 547 | #[repr(u8)] | ||
| 548 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] | ||
| 549 | pub enum CountingMode { | ||
| 550 | #[default] | ||
| 551 | /// The timer counts up to the reload value and then resets back to 0. | ||
| 552 | EdgeAlignedUp, | ||
| 553 | /// The timer counts down to 0 and then resets back to the reload value. | ||
| 554 | EdgeAlignedDown, | ||
| 555 | /// The timer counts up to the reload value and then counts back to 0. | ||
| 556 | /// | 57 | /// |
| 557 | /// The output compare interrupt flags of channels configured in output are | 58 | /// This is a raw pointer to the register block. The actual register block layout varies depending on the timer type. |
| 558 | /// set when the counter is counting down. | 59 | fn regs() -> *mut (); |
| 559 | CenterAlignedDownInterrupts, | ||
| 560 | /// The timer counts up to the reload value and then counts back to 0. | ||
| 561 | /// | ||
| 562 | /// The output compare interrupt flags of channels configured in output are | ||
| 563 | /// set when the counter is counting up. | ||
| 564 | CenterAlignedUpInterrupts, | ||
| 565 | /// The timer counts up to the reload value and then counts back to 0. | ||
| 566 | /// | ||
| 567 | /// The output compare interrupt flags of channels configured in output are | ||
| 568 | /// set when the counter is counting both up or down. | ||
| 569 | CenterAlignedBothInterrupts, | ||
| 570 | } | ||
| 571 | |||
| 572 | impl CountingMode { | ||
| 573 | /// Return whether this mode is edge-aligned (up or down). | ||
| 574 | pub fn is_edge_aligned(&self) -> bool { | ||
| 575 | matches!(self, CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown) | ||
| 576 | } | ||
| 577 | |||
| 578 | /// Return whether this mode is center-aligned. | ||
| 579 | pub fn is_center_aligned(&self) -> bool { | ||
| 580 | matches!( | ||
| 581 | self, | ||
| 582 | CountingMode::CenterAlignedDownInterrupts | ||
| 583 | | CountingMode::CenterAlignedUpInterrupts | ||
| 584 | | CountingMode::CenterAlignedBothInterrupts | ||
| 585 | ) | ||
| 586 | } | ||
| 587 | } | ||
| 588 | |||
| 589 | impl From<CountingMode> for (vals::Cms, vals::Dir) { | ||
| 590 | fn from(value: CountingMode) -> Self { | ||
| 591 | match value { | ||
| 592 | CountingMode::EdgeAlignedUp => (vals::Cms::EDGEALIGNED, vals::Dir::UP), | ||
| 593 | CountingMode::EdgeAlignedDown => (vals::Cms::EDGEALIGNED, vals::Dir::DOWN), | ||
| 594 | CountingMode::CenterAlignedDownInterrupts => (vals::Cms::CENTERALIGNED1, vals::Dir::UP), | ||
| 595 | CountingMode::CenterAlignedUpInterrupts => (vals::Cms::CENTERALIGNED2, vals::Dir::UP), | ||
| 596 | CountingMode::CenterAlignedBothInterrupts => (vals::Cms::CENTERALIGNED3, vals::Dir::UP), | ||
| 597 | } | ||
| 598 | } | ||
| 599 | } | ||
| 600 | |||
| 601 | impl From<(vals::Cms, vals::Dir)> for CountingMode { | ||
| 602 | fn from(value: (vals::Cms, vals::Dir)) -> Self { | ||
| 603 | match value { | ||
| 604 | (vals::Cms::EDGEALIGNED, vals::Dir::UP) => CountingMode::EdgeAlignedUp, | ||
| 605 | (vals::Cms::EDGEALIGNED, vals::Dir::DOWN) => CountingMode::EdgeAlignedDown, | ||
| 606 | (vals::Cms::CENTERALIGNED1, _) => CountingMode::CenterAlignedDownInterrupts, | ||
| 607 | (vals::Cms::CENTERALIGNED2, _) => CountingMode::CenterAlignedUpInterrupts, | ||
| 608 | (vals::Cms::CENTERALIGNED3, _) => CountingMode::CenterAlignedBothInterrupts, | ||
| 609 | } | ||
| 610 | } | ||
| 611 | } | ||
| 612 | |||
| 613 | /// Output compare mode. | ||
| 614 | #[derive(Clone, Copy)] | ||
| 615 | pub enum OutputCompareMode { | ||
| 616 | /// The comparison between the output compare register TIMx_CCRx and | ||
| 617 | /// the counter TIMx_CNT has no effect on the outputs. | ||
| 618 | /// (this mode is used to generate a timing base). | ||
| 619 | Frozen, | ||
| 620 | /// Set channel to active level on match. OCxREF signal is forced high when the | ||
| 621 | /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx). | ||
| 622 | ActiveOnMatch, | ||
| 623 | /// Set channel to inactive level on match. OCxREF signal is forced low when the | ||
| 624 | /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx). | ||
| 625 | InactiveOnMatch, | ||
| 626 | /// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx. | ||
| 627 | Toggle, | ||
| 628 | /// Force inactive level - OCxREF is forced low. | ||
| 629 | ForceInactive, | ||
| 630 | /// Force active level - OCxREF is forced high. | ||
| 631 | ForceActive, | ||
| 632 | /// PWM mode 1 - In upcounting, channel is active as long as TIMx_CNT<TIMx_CCRx | ||
| 633 | /// else inactive. In downcounting, channel is inactive (OCxREF=0) as long as | ||
| 634 | /// TIMx_CNT>TIMx_CCRx else active (OCxREF=1). | ||
| 635 | PwmMode1, | ||
| 636 | /// PWM mode 2 - In upcounting, channel is inactive as long as | ||
| 637 | /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as | ||
| 638 | /// TIMx_CNT>TIMx_CCRx else inactive. | ||
| 639 | PwmMode2, | ||
| 640 | // TODO: there's more modes here depending on the chip family. | ||
| 641 | } | ||
| 642 | |||
| 643 | impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { | ||
| 644 | fn from(mode: OutputCompareMode) -> Self { | ||
| 645 | match mode { | ||
| 646 | OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN, | ||
| 647 | OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVEONMATCH, | ||
| 648 | OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVEONMATCH, | ||
| 649 | OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE, | ||
| 650 | OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCEINACTIVE, | ||
| 651 | OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCEACTIVE, | ||
| 652 | OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWMMODE1, | ||
| 653 | OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWMMODE2, | ||
| 654 | } | ||
| 655 | } | ||
| 656 | } | 60 | } |
| 61 | /// Cut-down basic timer instance. | ||
| 62 | pub trait BasicNoCr2Instance: CoreInstance {} | ||
| 63 | /// Basic timer instance. | ||
| 64 | pub trait BasicInstance: BasicNoCr2Instance {} | ||
| 657 | 65 | ||
| 658 | /// Timer output pin polarity. | 66 | /// General-purpose 16-bit timer with 1 channel instance. |
| 659 | #[derive(Clone, Copy)] | 67 | pub trait GeneralInstance1Channel: CoreInstance {} |
| 660 | pub enum OutputPolarity { | ||
| 661 | /// Active high (higher duty value makes the pin spend more time high). | ||
| 662 | ActiveHigh, | ||
| 663 | /// Active low (higher duty value makes the pin spend more time low). | ||
| 664 | ActiveLow, | ||
| 665 | } | ||
| 666 | 68 | ||
| 667 | impl From<OutputPolarity> for bool { | 69 | /// General-purpose 16-bit timer with 2 channels instance. |
| 668 | fn from(mode: OutputPolarity) -> Self { | 70 | pub trait GeneralInstance2Channel: GeneralInstance1Channel {} |
| 669 | match mode { | ||
| 670 | OutputPolarity::ActiveHigh => false, | ||
| 671 | OutputPolarity::ActiveLow => true, | ||
| 672 | } | ||
| 673 | } | ||
| 674 | } | ||
| 675 | 71 | ||
| 676 | /// Basic 16-bit timer instance. | 72 | /// General-purpose 16-bit timer with 4 channels instance. |
| 677 | pub trait BasicInstance: sealed::BasicInstance + sealed::BasicNoCr2Instance + sealed::CoreInstance + 'static {} | 73 | pub trait GeneralInstance4Channel: BasicInstance + GeneralInstance2Channel { |
| 678 | 74 | // SimplePwm<'d, T> is implemented for T: GeneralInstance4Channel | |
| 679 | // It's just a General-purpose 16-bit timer instance. | ||
| 680 | /// Capture Compare timer instance. | ||
| 681 | pub trait CaptureCompare16bitInstance: | ||
| 682 | BasicInstance | ||
| 683 | + sealed::GeneralPurpose2ChannelInstance | ||
| 684 | + sealed::GeneralPurpose1ChannelInstance | ||
| 685 | + sealed::GeneralPurpose16bitInstance | ||
| 686 | + 'static | ||
| 687 | { | ||
| 688 | // SimplePwm<'d, T> is implemented for T: CaptureCompare16bitInstance | ||
| 689 | // Advanced timers implement this trait, but the output needs to be | 75 | // Advanced timers implement this trait, but the output needs to be |
| 690 | // enabled explicitly. | 76 | // enabled explicitly. |
| 691 | // To support general-purpose and advanced timers, this function is added | 77 | // To support general-purpose and advanced timers, this function is added |
| @@ -694,296 +80,149 @@ pub trait CaptureCompare16bitInstance: | |||
| 694 | fn enable_outputs(&self) {} | 80 | fn enable_outputs(&self) {} |
| 695 | } | 81 | } |
| 696 | 82 | ||
| 697 | #[cfg(not(stm32l0))] | 83 | /// General-purpose 32-bit timer with 4 channels instance. |
| 698 | // It's just a General-purpose 32-bit timer instance. | 84 | pub trait GeneralInstance32bit4Channel: GeneralInstance4Channel {} |
| 699 | /// Capture Compare 32-bit timer instance. | ||
| 700 | pub trait CaptureCompare32bitInstance: | ||
| 701 | CaptureCompare16bitInstance + sealed::GeneralPurpose32bitInstance + 'static | ||
| 702 | { | ||
| 703 | } | ||
| 704 | |||
| 705 | #[cfg(not(stm32l0))] | ||
| 706 | // It's just a Advanced Control timer instance. | ||
| 707 | /// Complementary Capture Compare 32-bit timer instance. | ||
| 708 | pub trait ComplementaryCaptureCompare16bitInstance: | ||
| 709 | CaptureCompare16bitInstance | ||
| 710 | + sealed::GeneralPurpose1ChannelComplementaryInstance | ||
| 711 | + sealed::GeneralPurpose2ChannelComplementaryInstance | ||
| 712 | + sealed::AdvancedControlInstance | ||
| 713 | + 'static | ||
| 714 | { | ||
| 715 | } | ||
| 716 | |||
| 717 | pin_trait!(Channel1Pin, CaptureCompare16bitInstance); | ||
| 718 | pin_trait!(Channel2Pin, CaptureCompare16bitInstance); | ||
| 719 | pin_trait!(Channel3Pin, CaptureCompare16bitInstance); | ||
| 720 | pin_trait!(Channel4Pin, CaptureCompare16bitInstance); | ||
| 721 | pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance); | ||
| 722 | |||
| 723 | cfg_if::cfg_if! { | ||
| 724 | if #[cfg(not(stm32l0))] { | ||
| 725 | pin_trait!(Channel1ComplementaryPin, ComplementaryCaptureCompare16bitInstance); | ||
| 726 | pin_trait!(Channel2ComplementaryPin, ComplementaryCaptureCompare16bitInstance); | ||
| 727 | pin_trait!(Channel3ComplementaryPin, ComplementaryCaptureCompare16bitInstance); | ||
| 728 | pin_trait!(Channel4ComplementaryPin, ComplementaryCaptureCompare16bitInstance); | ||
| 729 | |||
| 730 | pin_trait!(BreakInputPin, ComplementaryCaptureCompare16bitInstance); | ||
| 731 | pin_trait!(BreakInput2Pin, ComplementaryCaptureCompare16bitInstance); | ||
| 732 | 85 | ||
| 733 | pin_trait!(BreakInputComparator1Pin, ComplementaryCaptureCompare16bitInstance); | 86 | /// Advanced 16-bit timer with 1 channel instance. |
| 734 | pin_trait!(BreakInputComparator2Pin, ComplementaryCaptureCompare16bitInstance); | 87 | pub trait AdvancedInstance1Channel: BasicNoCr2Instance + GeneralInstance1Channel { |
| 735 | 88 | /// Capture compare interrupt for this timer. | |
| 736 | pin_trait!(BreakInput2Comparator1Pin, ComplementaryCaptureCompare16bitInstance); | 89 | type CaptureCompareInterrupt: interrupt::typelevel::Interrupt; |
| 737 | pin_trait!(BreakInput2Comparator2Pin, ComplementaryCaptureCompare16bitInstance); | ||
| 738 | } | ||
| 739 | } | 90 | } |
| 91 | /// Advanced 16-bit timer with 2 channels instance. | ||
| 740 | 92 | ||
| 741 | #[allow(unused)] | 93 | pub trait AdvancedInstance2Channel: BasicInstance + GeneralInstance2Channel + AdvancedInstance1Channel {} |
| 742 | macro_rules! impl_core_timer { | ||
| 743 | ($inst:ident, $irq:ident) => { | ||
| 744 | impl sealed::CoreInstance for crate::peripherals::$inst { | ||
| 745 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 746 | 94 | ||
| 747 | fn regs_core() -> crate::pac::timer::TimCore { | 95 | /// Advanced 16-bit timer with 4 channels instance. |
| 748 | unsafe { crate::pac::timer::TimCore::from_ptr(crate::pac::$inst.as_ptr()) } | 96 | pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {} |
| 749 | } | ||
| 750 | } | ||
| 751 | }; | ||
| 752 | } | ||
| 753 | 97 | ||
| 754 | #[allow(unused)] | 98 | pin_trait!(Channel1Pin, GeneralInstance4Channel); |
| 755 | macro_rules! impl_basic_no_cr2_timer { | 99 | pin_trait!(Channel2Pin, GeneralInstance4Channel); |
| 756 | ($inst:ident) => { | 100 | pin_trait!(Channel3Pin, GeneralInstance4Channel); |
| 757 | impl sealed::BasicNoCr2Instance for crate::peripherals::$inst { | 101 | pin_trait!(Channel4Pin, GeneralInstance4Channel); |
| 758 | fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2 { | 102 | pin_trait!(ExternalTriggerPin, GeneralInstance4Channel); |
| 759 | unsafe { crate::pac::timer::TimBasicNoCr2::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 760 | } | ||
| 761 | } | ||
| 762 | }; | ||
| 763 | } | ||
| 764 | 103 | ||
| 765 | #[allow(unused)] | 104 | pin_trait!(Channel1ComplementaryPin, AdvancedInstance4Channel); |
| 766 | macro_rules! impl_basic_timer { | 105 | pin_trait!(Channel2ComplementaryPin, AdvancedInstance4Channel); |
| 767 | ($inst:ident) => { | 106 | pin_trait!(Channel3ComplementaryPin, AdvancedInstance4Channel); |
| 768 | impl sealed::BasicInstance for crate::peripherals::$inst { | 107 | pin_trait!(Channel4ComplementaryPin, AdvancedInstance4Channel); |
| 769 | fn regs_basic() -> crate::pac::timer::TimBasic { | ||
| 770 | unsafe { crate::pac::timer::TimBasic::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 771 | } | ||
| 772 | } | ||
| 773 | }; | ||
| 774 | } | ||
| 775 | 108 | ||
| 776 | #[allow(unused)] | 109 | pin_trait!(BreakInputPin, AdvancedInstance4Channel); |
| 777 | macro_rules! impl_1ch_timer { | 110 | pin_trait!(BreakInput2Pin, AdvancedInstance4Channel); |
| 778 | ($inst:ident) => { | ||
| 779 | impl sealed::GeneralPurpose1ChannelInstance for crate::peripherals::$inst { | ||
| 780 | fn regs_1ch() -> crate::pac::timer::Tim1ch { | ||
| 781 | unsafe { crate::pac::timer::Tim1ch::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 782 | } | ||
| 783 | } | ||
| 784 | }; | ||
| 785 | } | ||
| 786 | 111 | ||
| 787 | #[allow(unused)] | 112 | pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel); |
| 788 | macro_rules! impl_2ch_timer { | 113 | pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel); |
| 789 | ($inst:ident) => { | ||
| 790 | impl sealed::GeneralPurpose2ChannelInstance for crate::peripherals::$inst { | ||
| 791 | fn regs_2ch() -> crate::pac::timer::Tim2ch { | ||
| 792 | unsafe { crate::pac::timer::Tim2ch::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 793 | } | ||
| 794 | } | ||
| 795 | }; | ||
| 796 | } | ||
| 797 | 114 | ||
| 798 | #[allow(unused)] | 115 | pin_trait!(BreakInput2Comparator1Pin, AdvancedInstance4Channel); |
| 799 | macro_rules! impl_gp16_timer { | 116 | pin_trait!(BreakInput2Comparator2Pin, AdvancedInstance4Channel); |
| 800 | ($inst:ident) => { | ||
| 801 | impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { | ||
| 802 | fn regs_gp16() -> crate::pac::timer::TimGp16 { | ||
| 803 | unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 804 | } | ||
| 805 | } | ||
| 806 | }; | ||
| 807 | } | ||
| 808 | 117 | ||
| 809 | #[allow(unused)] | 118 | // Update Event trigger DMA for every timer |
| 810 | macro_rules! impl_gp32_timer { | 119 | dma_trait!(UpDma, BasicInstance); |
| 811 | ($inst:ident) => { | ||
| 812 | impl sealed::GeneralPurpose32bitInstance for crate::peripherals::$inst { | ||
| 813 | fn regs_gp32() -> crate::pac::timer::TimGp32 { | ||
| 814 | crate::pac::$inst | ||
| 815 | } | ||
| 816 | } | ||
| 817 | }; | ||
| 818 | } | ||
| 819 | 120 | ||
| 820 | #[allow(unused)] | 121 | dma_trait!(Ch1Dma, GeneralInstance4Channel); |
| 821 | macro_rules! impl_1ch_cmp_timer { | 122 | dma_trait!(Ch2Dma, GeneralInstance4Channel); |
| 822 | ($inst:ident) => { | 123 | dma_trait!(Ch3Dma, GeneralInstance4Channel); |
| 823 | impl sealed::GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst { | 124 | dma_trait!(Ch4Dma, GeneralInstance4Channel); |
| 824 | fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp { | ||
| 825 | unsafe { crate::pac::timer::Tim1chCmp::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 826 | } | ||
| 827 | } | ||
| 828 | }; | ||
| 829 | } | ||
| 830 | 125 | ||
| 831 | #[allow(unused)] | 126 | #[allow(unused)] |
| 832 | macro_rules! impl_2ch_cmp_timer { | 127 | macro_rules! impl_core_timer { |
| 833 | ($inst:ident) => { | 128 | ($inst:ident, $bits:expr) => { |
| 834 | impl sealed::GeneralPurpose2ChannelComplementaryInstance for crate::peripherals::$inst { | 129 | impl CoreInstance for crate::peripherals::$inst { |
| 835 | fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp { | 130 | type Interrupt = crate::_generated::peripheral_interrupts::$inst::UP; |
| 836 | unsafe { crate::pac::timer::Tim2chCmp::from_ptr(crate::pac::$inst.as_ptr()) } | ||
| 837 | } | ||
| 838 | } | ||
| 839 | }; | ||
| 840 | } | ||
| 841 | 131 | ||
| 842 | #[allow(unused)] | 132 | const BITS: TimerBits = $bits; |
| 843 | macro_rules! impl_adv_timer { | ||
| 844 | ($inst:ident, $irq:ident) => { | ||
| 845 | impl sealed::AdvancedControlInstance for crate::peripherals::$inst { | ||
| 846 | type CaptureCompareInterrupt = crate::interrupt::typelevel::$irq; | ||
| 847 | 133 | ||
| 848 | fn regs_advanced() -> crate::pac::timer::TimAdv { | 134 | fn regs() -> *mut () { |
| 849 | unsafe { crate::pac::timer::TimAdv::from_ptr(crate::pac::$inst.as_ptr()) } | 135 | crate::pac::$inst.as_ptr() |
| 850 | } | 136 | } |
| 851 | } | 137 | } |
| 852 | }; | 138 | }; |
| 853 | } | 139 | } |
| 854 | 140 | ||
| 855 | foreach_interrupt! { | 141 | foreach_interrupt! { |
| 856 | |||
| 857 | ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { | 142 | ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { |
| 858 | impl_core_timer!($inst, $irq); | 143 | impl_core_timer!($inst, TimerBits::Bits16); |
| 859 | impl_basic_no_cr2_timer!($inst); | 144 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 860 | impl_basic_timer!($inst); | ||
| 861 | impl BasicInstance for crate::peripherals::$inst {} | 145 | impl BasicInstance for crate::peripherals::$inst {} |
| 862 | }; | 146 | }; |
| 863 | 147 | ||
| 864 | ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => { | 148 | ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => { |
| 865 | impl_core_timer!($inst, $irq); | 149 | impl_core_timer!($inst, TimerBits::Bits16); |
| 866 | impl_basic_no_cr2_timer!($inst); | 150 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 867 | impl_basic_timer!($inst); | ||
| 868 | impl_1ch_timer!($inst); | ||
| 869 | impl_2ch_timer!($inst); | ||
| 870 | impl_gp16_timer!($inst); | ||
| 871 | impl BasicInstance for crate::peripherals::$inst {} | 151 | impl BasicInstance for crate::peripherals::$inst {} |
| 872 | impl CaptureCompare16bitInstance for crate::peripherals::$inst {} | 152 | impl GeneralInstance1Channel for crate::peripherals::$inst {} |
| 153 | impl GeneralInstance2Channel for crate::peripherals::$inst {} | ||
| 154 | impl GeneralInstance4Channel for crate::peripherals::$inst {} | ||
| 873 | }; | 155 | }; |
| 874 | 156 | ||
| 875 | |||
| 876 | ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { | 157 | ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { |
| 877 | impl_core_timer!($inst, $irq); | 158 | impl_core_timer!($inst, TimerBits::Bits16); |
| 878 | impl_basic_no_cr2_timer!($inst); | 159 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 879 | impl_basic_timer!($inst); | ||
| 880 | impl_1ch_timer!($inst); | ||
| 881 | impl_2ch_timer!($inst); | ||
| 882 | impl_gp16_timer!($inst); | ||
| 883 | impl BasicInstance for crate::peripherals::$inst {} | 160 | impl BasicInstance for crate::peripherals::$inst {} |
| 884 | impl CaptureCompare16bitInstance for crate::peripherals::$inst {} | 161 | impl GeneralInstance1Channel for crate::peripherals::$inst {} |
| 162 | impl GeneralInstance2Channel for crate::peripherals::$inst {} | ||
| 163 | impl GeneralInstance4Channel for crate::peripherals::$inst {} | ||
| 885 | }; | 164 | }; |
| 886 | 165 | ||
| 887 | ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { | 166 | ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { |
| 888 | impl_core_timer!($inst, $irq); | 167 | impl_core_timer!($inst, TimerBits::Bits16); |
| 889 | impl_basic_no_cr2_timer!($inst); | 168 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 890 | impl_basic_timer!($inst); | ||
| 891 | impl_1ch_timer!($inst); | ||
| 892 | impl_2ch_timer!($inst); | ||
| 893 | impl_gp16_timer!($inst); | ||
| 894 | impl BasicInstance for crate::peripherals::$inst {} | 169 | impl BasicInstance for crate::peripherals::$inst {} |
| 895 | impl CaptureCompare16bitInstance for crate::peripherals::$inst {} | 170 | impl GeneralInstance1Channel for crate::peripherals::$inst {} |
| 171 | impl GeneralInstance2Channel for crate::peripherals::$inst {} | ||
| 172 | impl GeneralInstance4Channel for crate::peripherals::$inst {} | ||
| 896 | }; | 173 | }; |
| 897 | 174 | ||
| 898 | ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { | 175 | ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { |
| 899 | impl_core_timer!($inst, $irq); | 176 | impl_core_timer!($inst, TimerBits::Bits32); |
| 900 | impl_basic_no_cr2_timer!($inst); | 177 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 901 | impl_basic_timer!($inst); | ||
| 902 | impl_1ch_timer!($inst); | ||
| 903 | impl_2ch_timer!($inst); | ||
| 904 | impl_gp16_timer!($inst); | ||
| 905 | impl_gp32_timer!($inst); | ||
| 906 | impl BasicInstance for crate::peripherals::$inst {} | 178 | impl BasicInstance for crate::peripherals::$inst {} |
| 907 | impl CaptureCompare16bitInstance for crate::peripherals::$inst {} | 179 | impl GeneralInstance1Channel for crate::peripherals::$inst {} |
| 908 | impl CaptureCompare32bitInstance for crate::peripherals::$inst {} | 180 | impl GeneralInstance2Channel for crate::peripherals::$inst {} |
| 181 | impl GeneralInstance4Channel for crate::peripherals::$inst {} | ||
| 182 | impl GeneralInstance32bit4Channel for crate::peripherals::$inst {} | ||
| 909 | }; | 183 | }; |
| 910 | 184 | ||
| 911 | ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => { | 185 | ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => { |
| 912 | impl_core_timer!($inst, $irq); | 186 | impl_core_timer!($inst, TimerBits::Bits16); |
| 913 | impl_basic_no_cr2_timer!($inst); | 187 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 914 | impl_basic_timer!($inst); | ||
| 915 | impl_1ch_timer!($inst); | ||
| 916 | impl_2ch_timer!($inst); | ||
| 917 | impl_gp16_timer!($inst); | ||
| 918 | impl_1ch_cmp_timer!($inst); | ||
| 919 | impl_2ch_cmp_timer!($inst); | ||
| 920 | impl BasicInstance for crate::peripherals::$inst {} | 188 | impl BasicInstance for crate::peripherals::$inst {} |
| 921 | impl CaptureCompare16bitInstance for crate::peripherals::$inst { | 189 | impl GeneralInstance1Channel for crate::peripherals::$inst {} |
| 922 | /// Enable timer outputs. | 190 | impl GeneralInstance2Channel for crate::peripherals::$inst {} |
| 923 | fn enable_outputs(&self) { | 191 | impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::<Self>() }} |
| 924 | use crate::timer::sealed::GeneralPurpose1ChannelComplementaryInstance; | 192 | impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; } |
| 925 | self.set_moe(true); | 193 | impl AdvancedInstance2Channel for crate::peripherals::$inst {} |
| 926 | } | 194 | impl AdvancedInstance4Channel for crate::peripherals::$inst {} |
| 927 | } | ||
| 928 | impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} | ||
| 929 | }; | ||
| 930 | ($inst:ident, timer, TIM_1CH_CMP, CC, $irq:ident) => { | ||
| 931 | impl_adv_timer!($inst, $irq); | ||
| 932 | }; | 195 | }; |
| 933 | 196 | ||
| 934 | |||
| 935 | ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => { | 197 | ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => { |
| 936 | impl_core_timer!($inst, $irq); | 198 | impl_core_timer!($inst, TimerBits::Bits16); |
| 937 | impl_basic_no_cr2_timer!($inst); | 199 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 938 | impl_basic_timer!($inst); | ||
| 939 | impl_1ch_timer!($inst); | ||
| 940 | impl_2ch_timer!($inst); | ||
| 941 | impl_gp16_timer!($inst); | ||
| 942 | impl_1ch_cmp_timer!($inst); | ||
| 943 | impl_2ch_cmp_timer!($inst); | ||
| 944 | impl BasicInstance for crate::peripherals::$inst {} | 200 | impl BasicInstance for crate::peripherals::$inst {} |
| 945 | impl CaptureCompare16bitInstance for crate::peripherals::$inst { | 201 | impl GeneralInstance1Channel for crate::peripherals::$inst {} |
| 946 | /// Enable timer outputs. | 202 | impl GeneralInstance2Channel for crate::peripherals::$inst {} |
| 947 | fn enable_outputs(&self) { | 203 | impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::<Self>() }} |
| 948 | use crate::timer::sealed::GeneralPurpose1ChannelComplementaryInstance; | 204 | impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; } |
| 949 | self.set_moe(true); | 205 | impl AdvancedInstance2Channel for crate::peripherals::$inst {} |
| 950 | } | 206 | impl AdvancedInstance4Channel for crate::peripherals::$inst {} |
| 951 | } | ||
| 952 | impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} | ||
| 953 | }; | ||
| 954 | ($inst:ident, timer, TIM_2CH_CMP, CC, $irq:ident) => { | ||
| 955 | impl_adv_timer!($inst, $irq); | ||
| 956 | }; | 207 | }; |
| 957 | 208 | ||
| 958 | |||
| 959 | ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { | 209 | ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { |
| 960 | impl_core_timer!($inst, $irq); | 210 | impl_core_timer!($inst, TimerBits::Bits16); |
| 961 | impl_basic_no_cr2_timer!($inst); | 211 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 962 | impl_basic_timer!($inst); | ||
| 963 | impl_1ch_timer!($inst); | ||
| 964 | impl_2ch_timer!($inst); | ||
| 965 | impl_gp16_timer!($inst); | ||
| 966 | impl_1ch_cmp_timer!($inst); | ||
| 967 | impl_2ch_cmp_timer!($inst); | ||
| 968 | impl BasicInstance for crate::peripherals::$inst {} | 212 | impl BasicInstance for crate::peripherals::$inst {} |
| 969 | impl CaptureCompare16bitInstance for crate::peripherals::$inst { | 213 | impl GeneralInstance1Channel for crate::peripherals::$inst {} |
| 970 | /// Enable timer outputs. | 214 | impl GeneralInstance2Channel for crate::peripherals::$inst {} |
| 971 | fn enable_outputs(&self) { | 215 | impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::<Self>() }} |
| 972 | use crate::timer::sealed::GeneralPurpose1ChannelComplementaryInstance; | 216 | impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; } |
| 973 | self.set_moe(true); | 217 | impl AdvancedInstance2Channel for crate::peripherals::$inst {} |
| 974 | } | 218 | impl AdvancedInstance4Channel for crate::peripherals::$inst {} |
| 975 | } | ||
| 976 | impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} | ||
| 977 | }; | ||
| 978 | ($inst:ident, timer, TIM_ADV, CC, $irq:ident) => { | ||
| 979 | impl_adv_timer!($inst, $irq); | ||
| 980 | }; | 219 | }; |
| 981 | } | 220 | } |
| 982 | 221 | ||
| 983 | // Update Event trigger DMA for every timer | 222 | #[cfg(not(stm32l0))] |
| 984 | dma_trait!(UpDma, BasicInstance); | 223 | #[allow(unused)] |
| 985 | 224 | fn set_moe<T: GeneralInstance4Channel>() { | |
| 986 | dma_trait!(Ch1Dma, CaptureCompare16bitInstance); | 225 | unsafe { crate::pac::timer::Tim1chCmp::from_ptr(T::regs()) } |
| 987 | dma_trait!(Ch2Dma, CaptureCompare16bitInstance); | 226 | .bdtr() |
| 988 | dma_trait!(Ch3Dma, CaptureCompare16bitInstance); | 227 | .modify(|w| w.set_moe(true)); |
| 989 | dma_trait!(Ch4Dma, CaptureCompare16bitInstance); | 228 | } |
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index 59efb72ba..b6ab939cc 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs | |||
| @@ -3,8 +3,10 @@ | |||
| 3 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 4 | 4 | ||
| 5 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 5 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 6 | use stm32_metapac::timer::vals; | ||
| 6 | 7 | ||
| 7 | use super::*; | 8 | use super::low_level::Timer; |
| 9 | use super::{Channel1Pin, Channel2Pin, GeneralInstance4Channel}; | ||
| 8 | use crate::gpio::sealed::AFType; | 10 | use crate::gpio::sealed::AFType; |
| 9 | use crate::gpio::AnyPin; | 11 | use crate::gpio::AnyPin; |
| 10 | use crate::Peripheral; | 12 | use crate::Peripheral; |
| @@ -30,7 +32,7 @@ pub struct QeiPin<'d, T, Channel> { | |||
| 30 | 32 | ||
| 31 | macro_rules! channel_impl { | 33 | macro_rules! channel_impl { |
| 32 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | 34 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { |
| 33 | impl<'d, T: CaptureCompare16bitInstance> QeiPin<'d, T, $channel> { | 35 | impl<'d, T: GeneralInstance4Channel> QeiPin<'d, T, $channel> { |
| 34 | #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")] | 36 | #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")] |
| 35 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self { | 37 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self { |
| 36 | into_ref!(pin); | 38 | into_ref!(pin); |
| @@ -53,29 +55,28 @@ channel_impl!(new_ch1, Ch1, Channel1Pin); | |||
| 53 | channel_impl!(new_ch2, Ch2, Channel2Pin); | 55 | channel_impl!(new_ch2, Ch2, Channel2Pin); |
| 54 | 56 | ||
| 55 | /// Quadrature decoder driver. | 57 | /// Quadrature decoder driver. |
| 56 | pub struct Qei<'d, T> { | 58 | pub struct Qei<'d, T: GeneralInstance4Channel> { |
| 57 | _inner: PeripheralRef<'d, T>, | 59 | inner: Timer<'d, T>, |
| 58 | } | 60 | } |
| 59 | 61 | ||
| 60 | impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { | 62 | impl<'d, T: GeneralInstance4Channel> Qei<'d, T> { |
| 61 | /// Create a new quadrature decoder driver. | 63 | /// Create a new quadrature decoder driver. |
| 62 | pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { | 64 | pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { |
| 63 | Self::new_inner(tim) | 65 | Self::new_inner(tim) |
| 64 | } | 66 | } |
| 65 | 67 | ||
| 66 | fn new_inner(tim: impl Peripheral<P = T> + 'd) -> Self { | 68 | fn new_inner(tim: impl Peripheral<P = T> + 'd) -> Self { |
| 67 | into_ref!(tim); | 69 | let inner = Timer::new(tim); |
| 68 | 70 | let r = inner.regs_gp16(); | |
| 69 | T::enable_and_reset(); | ||
| 70 | 71 | ||
| 71 | // Configure TxC1 and TxC2 as captures | 72 | // Configure TxC1 and TxC2 as captures |
| 72 | T::regs_gp16().ccmr_input(0).modify(|w| { | 73 | r.ccmr_input(0).modify(|w| { |
| 73 | w.set_ccs(0, vals::CcmrInputCcs::TI4); | 74 | w.set_ccs(0, vals::CcmrInputCcs::TI4); |
| 74 | w.set_ccs(1, vals::CcmrInputCcs::TI4); | 75 | w.set_ccs(1, vals::CcmrInputCcs::TI4); |
| 75 | }); | 76 | }); |
| 76 | 77 | ||
| 77 | // enable and configure to capture on rising edge | 78 | // enable and configure to capture on rising edge |
| 78 | T::regs_gp16().ccer().modify(|w| { | 79 | r.ccer().modify(|w| { |
| 79 | w.set_cce(0, true); | 80 | w.set_cce(0, true); |
| 80 | w.set_cce(1, true); | 81 | w.set_cce(1, true); |
| 81 | 82 | ||
| @@ -83,19 +84,19 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { | |||
| 83 | w.set_ccp(1, false); | 84 | w.set_ccp(1, false); |
| 84 | }); | 85 | }); |
| 85 | 86 | ||
| 86 | T::regs_gp16().smcr().modify(|w| { | 87 | r.smcr().modify(|w| { |
| 87 | w.set_sms(vals::Sms::ENCODER_MODE_3); | 88 | w.set_sms(vals::Sms::ENCODER_MODE_3); |
| 88 | }); | 89 | }); |
| 89 | 90 | ||
| 90 | T::regs_gp16().arr().modify(|w| w.set_arr(u16::MAX)); | 91 | r.arr().modify(|w| w.set_arr(u16::MAX)); |
| 91 | T::regs_gp16().cr1().modify(|w| w.set_cen(true)); | 92 | r.cr1().modify(|w| w.set_cen(true)); |
| 92 | 93 | ||
| 93 | Self { _inner: tim } | 94 | Self { inner } |
| 94 | } | 95 | } |
| 95 | 96 | ||
| 96 | /// Get direction. | 97 | /// Get direction. |
| 97 | pub fn read_direction(&self) -> Direction { | 98 | pub fn read_direction(&self) -> Direction { |
| 98 | match T::regs_gp16().cr1().read().dir() { | 99 | match self.inner.regs_gp16().cr1().read().dir() { |
| 99 | vals::Dir::DOWN => Direction::Downcounting, | 100 | vals::Dir::DOWN => Direction::Downcounting, |
| 100 | vals::Dir::UP => Direction::Upcounting, | 101 | vals::Dir::UP => Direction::Upcounting, |
| 101 | } | 102 | } |
| @@ -103,6 +104,6 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { | |||
| 103 | 104 | ||
| 104 | /// Get count. | 105 | /// Get count. |
| 105 | pub fn count(&self) -> u16 { | 106 | pub fn count(&self) -> u16 { |
| 106 | T::regs_gp16().cnt().read().cnt() | 107 | self.inner.regs_gp16().cnt().read().cnt() |
| 107 | } | 108 | } |
| 108 | } | 109 | } |
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 4669fc6cc..b54e9a0d6 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs | |||
| @@ -4,10 +4,10 @@ use core::marker::PhantomData; | |||
| 4 | 4 | ||
| 5 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 5 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 6 | 6 | ||
| 7 | use super::*; | 7 | use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; |
| 8 | #[allow(unused_imports)] | 8 | use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel}; |
| 9 | use crate::gpio::sealed::{AFType, Pin}; | ||
| 10 | use crate::gpio::{AnyPin, OutputType}; | 9 | use crate::gpio::{AnyPin, OutputType}; |
| 10 | use crate::time::Hertz; | ||
| 11 | use crate::Peripheral; | 11 | use crate::Peripheral; |
| 12 | 12 | ||
| 13 | /// Channel 1 marker type. | 13 | /// Channel 1 marker type. |
| @@ -29,7 +29,7 @@ pub struct PwmPin<'d, T, C> { | |||
| 29 | 29 | ||
| 30 | macro_rules! channel_impl { | 30 | macro_rules! channel_impl { |
| 31 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | 31 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { |
| 32 | impl<'d, T: CaptureCompare16bitInstance> PwmPin<'d, T, $channel> { | 32 | impl<'d, T: GeneralInstance4Channel> PwmPin<'d, T, $channel> { |
| 33 | #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] | 33 | #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] |
| 34 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self { | 34 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self { |
| 35 | into_ref!(pin); | 35 | into_ref!(pin); |
| @@ -54,11 +54,11 @@ channel_impl!(new_ch3, Ch3, Channel3Pin); | |||
| 54 | channel_impl!(new_ch4, Ch4, Channel4Pin); | 54 | channel_impl!(new_ch4, Ch4, Channel4Pin); |
| 55 | 55 | ||
| 56 | /// Simple PWM driver. | 56 | /// Simple PWM driver. |
| 57 | pub struct SimplePwm<'d, T> { | 57 | pub struct SimplePwm<'d, T: GeneralInstance4Channel> { |
| 58 | inner: PeripheralRef<'d, T>, | 58 | inner: Timer<'d, T>, |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | 61 | impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { |
| 62 | /// Create a new simple PWM driver. | 62 | /// Create a new simple PWM driver. |
| 63 | pub fn new( | 63 | pub fn new( |
| 64 | tim: impl Peripheral<P = T> + 'd, | 64 | tim: impl Peripheral<P = T> + 'd, |
| @@ -73,15 +73,11 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self { | 75 | fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self { |
| 76 | into_ref!(tim); | 76 | let mut this = Self { inner: Timer::new(tim) }; |
| 77 | |||
| 78 | T::enable_and_reset(); | ||
| 79 | |||
| 80 | let mut this = Self { inner: tim }; | ||
| 81 | 77 | ||
| 82 | this.inner.set_counting_mode(counting_mode); | 78 | this.inner.set_counting_mode(counting_mode); |
| 83 | this.set_frequency(freq); | 79 | this.set_frequency(freq); |
| 84 | this.inner.enable_outputs(); // Required for advanced timers, see CaptureCompare16bitInstance for details | 80 | this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details |
| 85 | this.inner.start(); | 81 | this.inner.start(); |
| 86 | 82 | ||
| 87 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] | 83 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] |
| @@ -126,14 +122,14 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 126 | /// Get max duty value. | 122 | /// Get max duty value. |
| 127 | /// | 123 | /// |
| 128 | /// This value depends on the configured frequency and the timer's clock rate from RCC. | 124 | /// This value depends on the configured frequency and the timer's clock rate from RCC. |
| 129 | pub fn get_max_duty(&self) -> u16 { | 125 | pub fn get_max_duty(&self) -> u32 { |
| 130 | self.inner.get_max_compare_value() + 1 | 126 | self.inner.get_max_compare_value() + 1 |
| 131 | } | 127 | } |
| 132 | 128 | ||
| 133 | /// Set the duty for a given channel. | 129 | /// Set the duty for a given channel. |
| 134 | /// | 130 | /// |
| 135 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. | 131 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. |
| 136 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { | 132 | pub fn set_duty(&mut self, channel: Channel, duty: u32) { |
| 137 | assert!(duty <= self.get_max_duty()); | 133 | assert!(duty <= self.get_max_duty()); |
| 138 | self.inner.set_compare_value(channel, duty) | 134 | self.inner.set_compare_value(channel, duty) |
| 139 | } | 135 | } |
| @@ -141,7 +137,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 141 | /// Get the duty for a given channel. | 137 | /// Get the duty for a given channel. |
| 142 | /// | 138 | /// |
| 143 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. | 139 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. |
| 144 | pub fn get_duty(&self, channel: Channel) -> u16 { | 140 | pub fn get_duty(&self, channel: Channel) -> u32 { |
| 145 | self.inner.get_compare_value(channel) | 141 | self.inner.get_compare_value(channel) |
| 146 | } | 142 | } |
| 147 | 143 | ||
| @@ -165,8 +161,6 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 165 | channel: Channel, | 161 | channel: Channel, |
| 166 | duty: &[u16], | 162 | duty: &[u16], |
| 167 | ) { | 163 | ) { |
| 168 | assert!(duty.iter().all(|v| *v <= self.get_max_duty())); | ||
| 169 | |||
| 170 | into_ref!(dma); | 164 | into_ref!(dma); |
| 171 | 165 | ||
| 172 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | 166 | #[allow(clippy::let_unit_value)] // eg. stm32f334 |
| @@ -201,7 +195,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 201 | &mut dma, | 195 | &mut dma, |
| 202 | req, | 196 | req, |
| 203 | duty, | 197 | duty, |
| 204 | T::regs_1ch().ccr(channel.index()).as_ptr() as *mut _, | 198 | self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut _, |
| 205 | dma_transfer_option, | 199 | dma_transfer_option, |
| 206 | ) | 200 | ) |
| 207 | .await | 201 | .await |
| @@ -227,22 +221,20 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 227 | 221 | ||
| 228 | macro_rules! impl_waveform_chx { | 222 | macro_rules! impl_waveform_chx { |
| 229 | ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => { | 223 | ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => { |
| 230 | impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | 224 | impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { |
| 231 | /// Generate a sequence of PWM waveform | 225 | /// Generate a sequence of PWM waveform |
| 232 | /// | 226 | /// |
| 233 | /// Note: | 227 | /// Note: |
| 234 | /// you will need to provide corresponding TIMx_CHy DMA channel to use this method. | 228 | /// you will need to provide corresponding TIMx_CHy DMA channel to use this method. |
| 235 | pub async fn $fn_name(&mut self, dma: impl Peripheral<P = impl super::$dma_ch<T>>, duty: &[u16]) { | 229 | pub async fn $fn_name(&mut self, dma: impl Peripheral<P = impl super::$dma_ch<T>>, duty: &[u16]) { |
| 236 | use super::vals::Ccds; | 230 | use crate::pac::timer::vals::Ccds; |
| 237 | |||
| 238 | assert!(duty.iter().all(|v| *v <= self.get_max_duty())); | ||
| 239 | 231 | ||
| 240 | into_ref!(dma); | 232 | into_ref!(dma); |
| 241 | 233 | ||
| 242 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | 234 | #[allow(clippy::let_unit_value)] // eg. stm32f334 |
| 243 | let req = dma.request(); | 235 | let req = dma.request(); |
| 244 | 236 | ||
| 245 | let cc_channel = super::Channel::$cc_ch; | 237 | let cc_channel = Channel::$cc_ch; |
| 246 | 238 | ||
| 247 | let original_duty_state = self.get_duty(cc_channel); | 239 | let original_duty_state = self.get_duty(cc_channel); |
| 248 | let original_enable_state = self.is_enabled(cc_channel); | 240 | let original_enable_state = self.is_enabled(cc_channel); |
| @@ -279,7 +271,7 @@ macro_rules! impl_waveform_chx { | |||
| 279 | &mut dma, | 271 | &mut dma, |
| 280 | req, | 272 | req, |
| 281 | duty, | 273 | duty, |
| 282 | T::regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _, | 274 | self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _, |
| 283 | dma_transfer_option, | 275 | dma_transfer_option, |
| 284 | ) | 276 | ) |
| 285 | .await | 277 | .await |
| @@ -314,10 +306,10 @@ impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2); | |||
| 314 | impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); | 306 | impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); |
| 315 | impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); | 307 | impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); |
| 316 | 308 | ||
| 317 | impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> { | 309 | impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> { |
| 318 | type Channel = Channel; | 310 | type Channel = Channel; |
| 319 | type Time = Hertz; | 311 | type Time = Hertz; |
| 320 | type Duty = u16; | 312 | type Duty = u32; |
| 321 | 313 | ||
| 322 | fn disable(&mut self, channel: Self::Channel) { | 314 | fn disable(&mut self, channel: Self::Channel) { |
| 323 | self.inner.enable_channel(channel, false); | 315 | self.inner.enable_channel(channel, false); |
diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs index 6122cea2d..cbaff75fc 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm.rs | |||
| @@ -15,8 +15,9 @@ | |||
| 15 | use embassy_executor::Spawner; | 15 | use embassy_executor::Spawner; |
| 16 | use embassy_stm32::gpio::OutputType; | 16 | use embassy_stm32::gpio::OutputType; |
| 17 | use embassy_stm32::time::khz; | 17 | use embassy_stm32::time::khz; |
| 18 | use embassy_stm32::timer::low_level::CountingMode; | ||
| 18 | use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; | 19 | use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; |
| 19 | use embassy_stm32::timer::{Channel, CountingMode}; | 20 | use embassy_stm32::timer::Channel; |
| 20 | use embassy_time::{Duration, Ticker, Timer}; | 21 | use embassy_time::{Duration, Ticker, Timer}; |
| 21 | use {defmt_rtt as _, panic_probe as _}; | 22 | use {defmt_rtt as _, panic_probe as _}; |
| 22 | 23 | ||
| @@ -60,7 +61,7 @@ async fn main(_spawner: Spawner) { | |||
| 60 | // construct ws2812 non-return-to-zero (NRZ) code bit by bit | 61 | // construct ws2812 non-return-to-zero (NRZ) code bit by bit |
| 61 | // ws2812 only need 24 bits for each LED, but we add one bit more to keep PWM output low | 62 | // ws2812 only need 24 bits for each LED, but we add one bit more to keep PWM output low |
| 62 | 63 | ||
| 63 | let max_duty = ws2812_pwm.get_max_duty(); | 64 | let max_duty = ws2812_pwm.get_max_duty() as u16; |
| 64 | let n0 = 8 * max_duty / 25; // ws2812 Bit 0 high level timing | 65 | let n0 = 8 * max_duty / 25; // ws2812 Bit 0 high level timing |
| 65 | let n1 = 2 * n0; // ws2812 Bit 1 high level timing | 66 | let n1 = 2 * n0; // ws2812 Bit 1 high level timing |
| 66 | 67 | ||
diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs index feec28993..c45747f35 100644 --- a/examples/stm32h7/src/bin/dac_dma.rs +++ b/examples/stm32h7/src/bin/dac_dma.rs | |||
| @@ -8,7 +8,7 @@ use embassy_stm32::pac::timer::vals::Mms; | |||
| 8 | use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; | 8 | use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; |
| 9 | use embassy_stm32::rcc::low_level::RccPeripheral; | 9 | use embassy_stm32::rcc::low_level::RccPeripheral; |
| 10 | use embassy_stm32::time::Hertz; | 10 | use embassy_stm32::time::Hertz; |
| 11 | use embassy_stm32::timer::low_level::BasicInstance; | 11 | use embassy_stm32::timer::low_level::Timer; |
| 12 | use micromath::F32Ext; | 12 | use micromath::F32Ext; |
| 13 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 14 | 14 | ||
| @@ -51,12 +51,12 @@ async fn main(spawner: Spawner) { | |||
| 51 | // Obtain two independent channels (p.DAC1 can only be consumed once, though!) | 51 | // Obtain two independent channels (p.DAC1 can only be consumed once, though!) |
| 52 | let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); | 52 | let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); |
| 53 | 53 | ||
| 54 | spawner.spawn(dac_task1(dac_ch1)).ok(); | 54 | spawner.spawn(dac_task1(p.TIM6, dac_ch1)).ok(); |
| 55 | spawner.spawn(dac_task2(dac_ch2)).ok(); | 55 | spawner.spawn(dac_task2(p.TIM7, dac_ch2)).ok(); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | #[embassy_executor::task] | 58 | #[embassy_executor::task] |
| 59 | async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { | 59 | async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { |
| 60 | let data: &[u8; 256] = &calculate_array::<256>(); | 60 | let data: &[u8; 256] = &calculate_array::<256>(); |
| 61 | 61 | ||
| 62 | info!("TIM6 frequency is {}", TIM6::frequency()); | 62 | info!("TIM6 frequency is {}", TIM6::frequency()); |
| @@ -74,10 +74,10 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { | |||
| 74 | dac.set_triggering(true); | 74 | dac.set_triggering(true); |
| 75 | dac.enable(); | 75 | dac.enable(); |
| 76 | 76 | ||
| 77 | TIM6::enable_and_reset(); | 77 | let tim = Timer::new(tim); |
| 78 | TIM6::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); | 78 | tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); |
| 79 | TIM6::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); | 79 | tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); |
| 80 | TIM6::regs_basic().cr1().modify(|w| { | 80 | tim.regs_basic().cr1().modify(|w| { |
| 81 | w.set_opm(false); | 81 | w.set_opm(false); |
| 82 | w.set_cen(true); | 82 | w.set_cen(true); |
| 83 | }); | 83 | }); |
| @@ -99,7 +99,7 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { | |||
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | #[embassy_executor::task] | 101 | #[embassy_executor::task] |
| 102 | async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { | 102 | async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { |
| 103 | let data: &[u8; 256] = &calculate_array::<256>(); | 103 | let data: &[u8; 256] = &calculate_array::<256>(); |
| 104 | 104 | ||
| 105 | info!("TIM7 frequency is {}", TIM7::frequency()); | 105 | info!("TIM7 frequency is {}", TIM7::frequency()); |
| @@ -111,10 +111,10 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { | |||
| 111 | error!("Reload value {} below threshold!", reload); | 111 | error!("Reload value {} below threshold!", reload); |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | TIM7::enable_and_reset(); | 114 | let tim = Timer::new(tim); |
| 115 | TIM7::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); | 115 | tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); |
| 116 | TIM7::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); | 116 | tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); |
| 117 | TIM7::regs_basic().cr1().modify(|w| { | 117 | tim.regs_basic().cr1().modify(|w| { |
| 118 | w.set_opm(false); | 118 | w.set_opm(false); |
| 119 | w.set_cen(true); | 119 | w.set_cen(true); |
| 120 | }); | 120 | }); |
diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index 049d9967d..780fbc6f0 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs | |||
| @@ -6,8 +6,9 @@ use embassy_executor::Spawner; | |||
| 6 | use embassy_stm32::gpio::low_level::AFType; | 6 | use embassy_stm32::gpio::low_level::AFType; |
| 7 | use embassy_stm32::gpio::Speed; | 7 | use embassy_stm32::gpio::Speed; |
| 8 | use embassy_stm32::time::{khz, Hertz}; | 8 | use embassy_stm32::time::{khz, Hertz}; |
| 9 | use embassy_stm32::timer::*; | 9 | use embassy_stm32::timer::low_level::{OutputCompareMode, Timer as LLTimer}; |
| 10 | use embassy_stm32::{into_ref, Config, Peripheral, PeripheralRef}; | 10 | use embassy_stm32::timer::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance32bit4Channel}; |
| 11 | use embassy_stm32::{into_ref, Config, Peripheral}; | ||
| 11 | use embassy_time::Timer; | 12 | use embassy_time::Timer; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 13 | 14 | ||
| @@ -56,11 +57,11 @@ async fn main(_spawner: Spawner) { | |||
| 56 | Timer::after_millis(300).await; | 57 | Timer::after_millis(300).await; |
| 57 | } | 58 | } |
| 58 | } | 59 | } |
| 59 | pub struct SimplePwm32<'d, T: CaptureCompare32bitInstance> { | 60 | pub struct SimplePwm32<'d, T: GeneralInstance32bit4Channel> { |
| 60 | inner: PeripheralRef<'d, T>, | 61 | tim: LLTimer<'d, T>, |
| 61 | } | 62 | } |
| 62 | 63 | ||
| 63 | impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { | 64 | impl<'d, T: GeneralInstance32bit4Channel> SimplePwm32<'d, T> { |
| 64 | pub fn new( | 65 | pub fn new( |
| 65 | tim: impl Peripheral<P = T> + 'd, | 66 | tim: impl Peripheral<P = T> + 'd, |
| 66 | ch1: impl Peripheral<P = impl Channel1Pin<T>> + 'd, | 67 | ch1: impl Peripheral<P = impl Channel1Pin<T>> + 'd, |
| @@ -69,9 +70,7 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { | |||
| 69 | ch4: impl Peripheral<P = impl Channel4Pin<T>> + 'd, | 70 | ch4: impl Peripheral<P = impl Channel4Pin<T>> + 'd, |
| 70 | freq: Hertz, | 71 | freq: Hertz, |
| 71 | ) -> Self { | 72 | ) -> Self { |
| 72 | into_ref!(tim, ch1, ch2, ch3, ch4); | 73 | into_ref!(ch1, ch2, ch3, ch4); |
| 73 | |||
| 74 | T::enable_and_reset(); | ||
| 75 | 74 | ||
| 76 | ch1.set_speed(Speed::VeryHigh); | 75 | ch1.set_speed(Speed::VeryHigh); |
| 77 | ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull); | 76 | ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull); |
| @@ -82,12 +81,12 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { | |||
| 82 | ch4.set_speed(Speed::VeryHigh); | 81 | ch4.set_speed(Speed::VeryHigh); |
| 83 | ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull); | 82 | ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull); |
| 84 | 83 | ||
| 85 | let mut this = Self { inner: tim }; | 84 | let mut this = Self { tim: LLTimer::new(tim) }; |
| 86 | 85 | ||
| 87 | this.set_frequency(freq); | 86 | this.set_frequency(freq); |
| 88 | this.inner.start(); | 87 | this.tim.start(); |
| 89 | 88 | ||
| 90 | let r = T::regs_gp32(); | 89 | let r = this.tim.regs_gp32(); |
| 91 | r.ccmr_output(0) | 90 | r.ccmr_output(0) |
| 92 | .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); | 91 | .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); |
| 93 | r.ccmr_output(0) | 92 | r.ccmr_output(0) |
| @@ -101,23 +100,26 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { | |||
| 101 | } | 100 | } |
| 102 | 101 | ||
| 103 | pub fn enable(&mut self, channel: Channel) { | 102 | pub fn enable(&mut self, channel: Channel) { |
| 104 | T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), true)); | 103 | self.tim.regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), true)); |
| 105 | } | 104 | } |
| 106 | 105 | ||
| 107 | pub fn disable(&mut self, channel: Channel) { | 106 | pub fn disable(&mut self, channel: Channel) { |
| 108 | T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), false)); | 107 | self.tim |
| 108 | .regs_gp32() | ||
| 109 | .ccer() | ||
| 110 | .modify(|w| w.set_cce(channel.index(), false)); | ||
| 109 | } | 111 | } |
| 110 | 112 | ||
| 111 | pub fn set_frequency(&mut self, freq: Hertz) { | 113 | pub fn set_frequency(&mut self, freq: Hertz) { |
| 112 | <T as embassy_stm32::timer::low_level::GeneralPurpose32bitInstance>::set_frequency(&mut self.inner, freq); | 114 | self.tim.set_frequency(freq); |
| 113 | } | 115 | } |
| 114 | 116 | ||
| 115 | pub fn get_max_duty(&self) -> u32 { | 117 | pub fn get_max_duty(&self) -> u32 { |
| 116 | T::regs_gp32().arr().read() | 118 | self.tim.regs_gp32().arr().read() |
| 117 | } | 119 | } |
| 118 | 120 | ||
| 119 | pub fn set_duty(&mut self, channel: Channel, duty: u32) { | 121 | pub fn set_duty(&mut self, channel: Channel, duty: u32) { |
| 120 | defmt::assert!(duty < self.get_max_duty()); | 122 | defmt::assert!(duty < self.get_max_duty()); |
| 121 | T::regs_gp32().ccr(channel.index()).write_value(duty) | 123 | self.tim.regs_gp32().ccr(channel.index()).write_value(duty) |
| 122 | } | 124 | } |
| 123 | } | 125 | } |
diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs index f227812cd..98edd39c0 100644 --- a/examples/stm32l4/src/bin/dac_dma.rs +++ b/examples/stm32l4/src/bin/dac_dma.rs | |||
| @@ -8,7 +8,7 @@ use embassy_stm32::pac::timer::vals::Mms; | |||
| 8 | use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; | 8 | use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; |
| 9 | use embassy_stm32::rcc::low_level::RccPeripheral; | 9 | use embassy_stm32::rcc::low_level::RccPeripheral; |
| 10 | use embassy_stm32::time::Hertz; | 10 | use embassy_stm32::time::Hertz; |
| 11 | use embassy_stm32::timer::low_level::BasicInstance; | 11 | use embassy_stm32::timer::low_level::Timer; |
| 12 | use micromath::F32Ext; | 12 | use micromath::F32Ext; |
| 13 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 14 | 14 | ||
| @@ -22,12 +22,12 @@ async fn main(spawner: Spawner) { | |||
| 22 | // Obtain two independent channels (p.DAC1 can only be consumed once, though!) | 22 | // Obtain two independent channels (p.DAC1 can only be consumed once, though!) |
| 23 | let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); | 23 | let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); |
| 24 | 24 | ||
| 25 | spawner.spawn(dac_task1(dac_ch1)).ok(); | 25 | spawner.spawn(dac_task1(p.TIM6, dac_ch1)).ok(); |
| 26 | spawner.spawn(dac_task2(dac_ch2)).ok(); | 26 | spawner.spawn(dac_task2(p.TIM7, dac_ch2)).ok(); |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | #[embassy_executor::task] | 29 | #[embassy_executor::task] |
| 30 | async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { | 30 | async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { |
| 31 | let data: &[u8; 256] = &calculate_array::<256>(); | 31 | let data: &[u8; 256] = &calculate_array::<256>(); |
| 32 | 32 | ||
| 33 | info!("TIM6 frequency is {}", TIM6::frequency()); | 33 | info!("TIM6 frequency is {}", TIM6::frequency()); |
| @@ -45,10 +45,10 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { | |||
| 45 | dac.set_triggering(true); | 45 | dac.set_triggering(true); |
| 46 | dac.enable(); | 46 | dac.enable(); |
| 47 | 47 | ||
| 48 | TIM6::enable_and_reset(); | 48 | let tim = Timer::new(tim); |
| 49 | TIM6::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); | 49 | tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); |
| 50 | TIM6::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); | 50 | tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); |
| 51 | TIM6::regs_basic().cr1().modify(|w| { | 51 | tim.regs_basic().cr1().modify(|w| { |
| 52 | w.set_opm(false); | 52 | w.set_opm(false); |
| 53 | w.set_cen(true); | 53 | w.set_cen(true); |
| 54 | }); | 54 | }); |
| @@ -70,7 +70,7 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { | |||
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | #[embassy_executor::task] | 72 | #[embassy_executor::task] |
| 73 | async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { | 73 | async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { |
| 74 | let data: &[u8; 256] = &calculate_array::<256>(); | 74 | let data: &[u8; 256] = &calculate_array::<256>(); |
| 75 | 75 | ||
| 76 | info!("TIM7 frequency is {}", TIM7::frequency()); | 76 | info!("TIM7 frequency is {}", TIM7::frequency()); |
| @@ -82,10 +82,10 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { | |||
| 82 | error!("Reload value {} below threshold!", reload); | 82 | error!("Reload value {} below threshold!", reload); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | TIM7::enable_and_reset(); | 85 | let tim = Timer::new(tim); |
| 86 | TIM7::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); | 86 | tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); |
| 87 | TIM7::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); | 87 | tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); |
| 88 | TIM7::regs_basic().cr1().modify(|w| { | 88 | tim.regs_basic().cr1().modify(|w| { |
| 89 | w.set_opm(false); | 89 | w.set_opm(false); |
| 90 | w.set_cen(true); | 90 | w.set_cen(true); |
| 91 | }); | 91 | }); |
