From c274f72f75951c493e1c13955979ed9a7229abdc Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 4 Feb 2022 08:49:06 +0300 Subject: [PATCH] const channel --- CHANGELOG.md | 2 + src/fugit/pwm.rs | 14 +- src/pwm.rs | 152 ++++++++++---------- src/pwm_input.rs | 4 +- src/qei.rs | 12 +- src/timer.rs | 349 +++++++++------------------------------------- src/timer/pins.rs | 220 +++++++++++++++++++++++++++++ 7 files changed, 381 insertions(+), 372 deletions(-) create mode 100644 src/timer/pins.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 33eac4b9f..07dd0dad7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Move `i2c` `embedded-hal` trait impls to `I2c` methods [#431] - Reexport pins in `gpio` module +- Pwm channels now constants [#432] - Add channel events, make Event use bitflags (simplify interrupt handling) [#425] - reexport `digital::v2::PinState` again [#428] - Timer impls with time based on `fugit` moved to `fugit` module, added `Pwm` and `fugit-timer` impls [#423] @@ -34,6 +35,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). [#425]: https://github.com/stm32-rs/stm32f4xx-hal/pull/425 [#429]: https://github.com/stm32-rs/stm32f4xx-hal/pull/429 [#431]: https://github.com/stm32-rs/stm32f4xx-hal/pull/431 +[#432]: https://github.com/stm32-rs/stm32f4xx-hal/pull/432 ### Changed diff --git a/src/fugit/pwm.rs b/src/fugit/pwm.rs index d8a8c1f30..c4f415ba9 100644 --- a/src/fugit/pwm.rs +++ b/src/fugit/pwm.rs @@ -145,31 +145,29 @@ where type Time = TimerDurationU32; fn enable(&mut self, channel: Self::Channel) { - self.tim.enable_channel(PINS::check_used(channel), true) + TIM::enable_channel(PINS::check_used(channel) as u8, true) } fn disable(&mut self, channel: Self::Channel) { - self.tim.enable_channel(PINS::check_used(channel), false) + TIM::enable_channel(PINS::check_used(channel) as u8, false) } fn get_duty(&self, channel: Self::Channel) -> Self::Duty { - let duty: u32 = self.tim.read_cc_value(PINS::check_used(channel)).into(); + let duty: u32 = TIM::read_cc_value(PINS::check_used(channel) as u8).into(); duty as u16 } fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { - self.tim - .set_cc_value(PINS::check_used(channel), duty.into()) + TIM::set_cc_value(PINS::check_used(channel) as u8, duty.into()) } /// If `0` returned means max_duty is 2^16 fn get_max_duty(&self) -> Self::Duty { - let arr: u32 = self.tim.read_auto_reload().into(); - (arr as u16).wrapping_add(1) + (TIM::read_auto_reload() as u16).wrapping_add(1) } fn get_period(&self) -> Self::Time { - Self::Time::from_ticks(self.tim.read_auto_reload().into() + 1) + Self::Time::from_ticks(TIM::read_auto_reload() + 1) } fn set_period(&mut self, period: T) diff --git a/src/pwm.rs b/src/pwm.rs index 8e3da512a..3bc3cfb9f 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -25,25 +25,25 @@ pub trait Pins { fn split() -> Self::Channels; } -pub use crate::timer::{CPin, C1, C2, C3, C4}; +pub use crate::timer::{CPin, Ch, C1, C2, C3, C4}; -pub struct PwmChannel { - _channel: PhantomData, - _tim: PhantomData, +pub struct PwmChannel { + pub(super) _tim: PhantomData, } macro_rules! pins_impl { - ( $( ( $($PINX:ident),+ ), ( $($ENCHX:ident),* ); )+ ) => { + ( $( ( $($PINX:ident),+ ), ( $($ENCHX:ident),+ ); )+ ) => { $( #[allow(unused_parens)] - impl Pins for ($($PINX),+) + impl Pins),+)> for ($($PINX),+) where - $($PINX: CPin<$ENCHX, TIM>,)+ + TIM: WithPwm, + $($PINX: CPin,)+ { $(const $ENCHX: bool = true;)+ type Channels = ($(PwmChannel),+); fn split() -> Self::Channels { - ($(PwmChannel:: { _channel: PhantomData, _tim: PhantomData }),+) + ($(PwmChannel::::new()),+) } } )+ @@ -68,71 +68,83 @@ pins_impl!( (P4), (C4); ); -impl, P2: CPin> CPin for (P1, P2) {} -impl, P2: CPin, P3: CPin> CPin for (P1, P2, P3) {} -impl, P2: CPin, P3: CPin, P4: CPin> CPin - for (P1, P2, P3, P4) +impl CPin for (P1, P2) +where + P1: CPin, + P2: CPin, +{ +} +impl CPin for (P1, P2, P3) +where + P1: CPin, + P2: CPin, + P3: CPin, +{ +} +impl CPin for (P1, P2, P3, P4) +where + P1: CPin, + P2: CPin, + P3: CPin, + P4: CPin, { } -macro_rules! pwm_pin { - ($TIMX:ty, $C:ty, $ccr: ident, $bit:literal) => { - impl PwmChannel<$TIMX, $C> { - #[inline] - pub fn disable(&mut self) { - //NOTE(unsafe) atomic write with no side effects - unsafe { bb::clear(&(*<$TIMX>::ptr()).ccer, $bit) } - } - - #[inline] - pub fn enable(&mut self) { - //NOTE(unsafe) atomic write with no side effects - unsafe { bb::set(&(*<$TIMX>::ptr()).ccer, $bit) } - } +impl PwmChannel { + pub(crate) fn new() -> Self { + Self { + _tim: core::marker::PhantomData, + } + } +} - #[inline] - pub fn get_duty(&self) -> u16 { - //NOTE(unsafe) atomic read with no side effects - unsafe { (*<$TIMX>::ptr()).$ccr.read().bits() as u16 } - } +impl PwmChannel { + #[inline] + pub fn disable(&mut self) { + TIM::enable_channel(C, false); + } - /// If `0` returned means max_duty is 2^16 - #[inline] - pub fn get_max_duty(&self) -> u16 { - //NOTE(unsafe) atomic read with no side effects - unsafe { ((*<$TIMX>::ptr()).arr.read().bits() as u16).wrapping_add(1) } - } + #[inline] + pub fn enable(&mut self) { + TIM::enable_channel(C, true); + } - #[inline] - pub fn set_duty(&mut self, duty: u16) { - //NOTE(unsafe) atomic write with no side effects - unsafe { (*<$TIMX>::ptr()).$ccr.write(|w| w.bits(duty.into())) } - } - } + #[inline] + pub fn get_duty(&self) -> u16 { + TIM::read_cc_value(C) as u16 + } - impl embedded_hal::PwmPin for PwmChannel<$TIMX, $C> { - type Duty = u16; + /// If `0` returned means max_duty is 2^16 + #[inline] + pub fn get_max_duty(&self) -> u16 { + (TIM::read_auto_reload() as u16).wrapping_add(1) + } - fn disable(&mut self) { - self.disable() - } - fn enable(&mut self) { - self.enable() - } - fn get_duty(&self) -> Self::Duty { - self.get_duty() - } - fn get_max_duty(&self) -> Self::Duty { - self.get_max_duty() - } - fn set_duty(&mut self, duty: Self::Duty) { - self.set_duty(duty) - } - } - }; + #[inline] + pub fn set_duty(&mut self, duty: u16) { + TIM::set_cc_value(C, duty as u32) + } } -pub(crate) use pwm_pin; +impl embedded_hal::PwmPin for PwmChannel { + type Duty = u16; + + fn disable(&mut self) { + self.disable() + } + fn enable(&mut self) { + self.enable() + } + fn get_duty(&self) -> Self::Duty { + self.get_duty() + } + fn get_max_duty(&self) -> Self::Duty { + self.get_max_duty() + } + fn set_duty(&mut self, duty: Self::Duty) { + self.set_duty(duty) + } +} impl Timer { pub fn pwm(mut self, _pins: PINS, freq: T) -> Pwm @@ -207,33 +219,31 @@ where type Time = Hertz; fn enable(&mut self, channel: Self::Channel) { - self.tim.enable_channel(PINS::check_used(channel), true) + TIM::enable_channel(PINS::check_used(channel) as u8, true) } fn disable(&mut self, channel: Self::Channel) { - self.tim.enable_channel(PINS::check_used(channel), false) + TIM::enable_channel(PINS::check_used(channel) as u8, false) } fn get_duty(&self, channel: Self::Channel) -> Self::Duty { - let duty: u32 = self.tim.read_cc_value(PINS::check_used(channel)).into(); + let duty: u32 = TIM::read_cc_value(PINS::check_used(channel) as u8).into(); duty as u16 } fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { - self.tim - .set_cc_value(PINS::check_used(channel), duty.into()) + TIM::set_cc_value(PINS::check_used(channel) as u8, duty as u32) } /// If `0` returned means max_duty is 2^16 fn get_max_duty(&self) -> Self::Duty { - let arr: u32 = self.tim.read_auto_reload().into(); - (arr as u16).wrapping_add(1) + (TIM::read_auto_reload() as u16).wrapping_add(1) } fn get_period(&self) -> Self::Time { let clk = self.clk; let psc = self.tim.read_prescaler() as u32; - let arr: u32 = self.tim.read_auto_reload().into(); + let arr = TIM::read_auto_reload(); // Length in ms of an internal clock pulse (clk.0 / (psc * arr)).hz() diff --git a/src/pwm_input.rs b/src/pwm_input.rs index 08cc154d6..5e46b0a58 100644 --- a/src/pwm_input.rs +++ b/src/pwm_input.rs @@ -1,13 +1,13 @@ use crate::{ time::Hertz, - timer::{CPin, General, Timer, C1}, + timer::{CPin, General, Timer}, }; use cast::u16; pub trait Pins {} // implement the `Pins` trait wherever PC1 implements CPin -impl Pins for PC1 where PC1: CPin {} +impl Pins for PC1 where PC1: CPin {} /// Represents a TIMer configured as a PWM input. /// This peripheral will emit an interrupt on CC2 events, which occurs at two times in this mode: diff --git a/src/qei.rs b/src/qei.rs index 85745fb5b..8328a0615 100644 --- a/src/qei.rs +++ b/src/qei.rs @@ -2,12 +2,12 @@ use crate::{pac::RCC, rcc, timer::General}; pub trait Pins {} -use crate::timer::{CPin, C1, C2}; +use crate::timer::CPin; impl Pins for (PC1, PC2) where - PC1: CPin, - PC2: CPin, + PC1: CPin, + PC2: CPin, { } @@ -19,8 +19,8 @@ pub struct Qei { impl Qei where - PC1: CPin, - PC2: CPin, + PC1: CPin, + PC2: CPin, { /// Configures a TIM peripheral as a quadrature encoder interface input pub fn new(mut tim: TIM, pins: (PC1, PC2)) -> Self { @@ -47,7 +47,7 @@ impl embedded_hal::Qei for Qei { type Count = TIM::Width; fn count(&self) -> Self::Count { - self.tim.read_count() as Self::Count + self.tim.read_count() } fn direction(&self) -> embedded_hal::Direction { diff --git a/src/timer.rs b/src/timer.rs index 78c3e1586..d7f3d8940 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -11,11 +11,13 @@ use void::Void; use crate::bb; use crate::pac::RCC; -use crate::pwm::{pwm_pin, PwmChannel}; use crate::rcc::{self, Clocks}; use crate::time::Hertz; +mod pins; +pub use pins::*; + /// Timer wrapper pub struct Timer { pub(crate) tim: TIM, @@ -225,7 +227,7 @@ mod sealed { type Width: Into + From; fn max_auto_reload() -> u32; fn set_auto_reload(&mut self, arr: u32) -> Result<(), super::Error>; - fn read_auto_reload(&self) -> Self::Width; + fn read_auto_reload() -> u32; fn enable_preload(&mut self, b: bool); fn enable_counter(&mut self); fn disable_counter(&mut self); @@ -244,11 +246,11 @@ mod sealed { pub trait WithPwm: General { const CH_NUMBER: u8; - fn read_cc_value(&self, channel: Channel) -> Self::Width; - fn set_cc_value(&mut self, channel: Channel, value: Self::Width); + fn read_cc_value(channel: u8) -> u32; + fn set_cc_value(channel: u8, value: u32); fn preload_output_channel_in_mode(&mut self, channel: Channel, mode: Ocm); fn start_pwm(&mut self); - fn enable_channel(&mut self, channel: Channel, b: bool); + fn enable_channel(channel: u8, b: bool); } } pub(crate) use sealed::{General, WithPwm}; @@ -302,8 +304,9 @@ macro_rules! hal { } } #[inline(always)] - fn read_auto_reload(&self) -> Self::Width { - self.arr.read().bits() as Self::Width + fn read_auto_reload() -> u32 { + let tim = unsafe { &*<$TIM>::ptr() }; + tim.arr.read().bits() } #[inline(always)] fn enable_preload(&mut self, b: bool) { @@ -379,21 +382,23 @@ macro_rules! with_pwm { const CH_NUMBER: u8 = 1; #[inline(always)] - fn read_cc_value(&self, channel: Channel) -> Self::Width { + fn read_cc_value(channel: u8) -> u32 { + let tim = unsafe { &*<$TIM>::ptr() }; match channel { - Channel::C1 => { - self.ccr1.read().ccr().bits() + 0 => { + tim.ccr1.read().bits() } _ => 0, } } #[inline(always)] - fn set_cc_value(&mut self, channel: Channel, value: Self::Width) { + fn set_cc_value(channel: u8, value: u32) { + let tim = unsafe { &*<$TIM>::ptr() }; #[allow(unused_unsafe)] match channel { - Channel::C1 => { - self.ccr1.write(|w| unsafe { w.ccr().bits(value) }) + 0 => { + tim.ccr1.write(|w| unsafe { w.bits(value) }) } _ => {}, } @@ -416,46 +421,46 @@ macro_rules! with_pwm { } #[inline(always)] - fn enable_channel(&mut self, channel: Channel, b: bool) { - let c = channel as u8; + fn enable_channel(c: u8, b: bool) { + let tim = unsafe { &*<$TIM>::ptr() }; if c < Self::CH_NUMBER { if b { - unsafe { bb::set(&self.ccer, c*4) } + unsafe { bb::set(&tim.ccer, c*4) } } else { - unsafe { bb::clear(&self.ccer, c*4) } + unsafe { bb::clear(&tim.ccer, c*4) } } } } } - - pwm_pin!($TIM, C1, ccr1, 0); }; ($TIM:ty: CH2) => { impl WithPwm for $TIM { const CH_NUMBER: u8 = 2; #[inline(always)] - fn read_cc_value(&self, channel: Channel) -> Self::Width { + fn read_cc_value(channel: u8) -> u32 { + let tim = unsafe { &*<$TIM>::ptr() }; match channel { - Channel::C1 => { - self.ccr1.read().ccr().bits() + 0 => { + tim.ccr1.read().bits() } - Channel::C2 => { - self.ccr2.read().ccr().bits() + 1 => { + tim.ccr2.read().bits() } _ => 0, } } #[inline(always)] - fn set_cc_value(&mut self, channel: Channel, value: Self::Width) { + fn set_cc_value(channel: u8, value: u32) { + let tim = unsafe { &*<$TIM>::ptr() }; #[allow(unused_unsafe)] match channel { - Channel::C1 => { - self.ccr1.write(|w| unsafe { w.ccr().bits(value) }) + 0 => { + tim.ccr1.write(|w| unsafe { w.bits(value) }) } - Channel::C2 => { - self.ccr2.write(|w| unsafe { w.ccr().bits(value) }) + 1 => { + tim.ccr2.write(|w| unsafe { w.bits(value) }) } _ => {}, } @@ -482,61 +487,60 @@ macro_rules! with_pwm { } #[inline(always)] - fn enable_channel(&mut self, channel: Channel, b: bool) { - let c = channel as u8; + fn enable_channel(c: u8, b: bool) { + let tim = unsafe { &*<$TIM>::ptr() }; if c < Self::CH_NUMBER { if b { - unsafe { bb::set(&self.ccer, c*4) } + unsafe { bb::set(&tim.ccer, c*4) } } else { - unsafe { bb::clear(&self.ccer, c*4) } + unsafe { bb::clear(&tim.ccer, c*4) } } } } } - - pwm_pin!($TIM, C1, ccr1, 0); - pwm_pin!($TIM, C2, ccr2, 4); }; ($TIM:ty: CH4 $(, $aoe:ident)?) => { impl WithPwm for $TIM { const CH_NUMBER: u8 = 4; #[inline(always)] - fn read_cc_value(&self, channel: Channel) -> Self::Width { + fn read_cc_value(channel: u8) -> u32 { + let tim = unsafe { &*<$TIM>::ptr() }; let ccr = match channel { - Channel::C1 => { - &self.ccr1 + 0 => { + &tim.ccr1 } - Channel::C2 => { - &self.ccr2 + 1 => { + &tim.ccr2 } - Channel::C3 => { - &self.ccr3 + 2 => { + &tim.ccr3 } - Channel::C4 => { - &self.ccr4 + _ => { + &tim.ccr4 } }; - ccr.read().bits() as Self::Width + ccr.read().bits() } #[inline(always)] - fn set_cc_value(&mut self, channel: Channel, value: Self::Width) { + fn set_cc_value(channel: u8, value: u32) { + let tim = unsafe { &*<$TIM>::ptr() }; let ccr = match channel { - Channel::C1 => { - &self.ccr1 + 0 => { + &tim.ccr1 } - Channel::C2 => { - &self.ccr2 + 1 => { + &tim.ccr2 } - Channel::C3 => { - &self.ccr3 + 2 => { + &tim.ccr3 } - Channel::C4 => { - &self.ccr4 + _ => { + &tim.ccr4 } }; - ccr.write(|w| unsafe { w.bits(value as u32) }) + ccr.write(|w| unsafe { w.bits(value) }) } #[inline(always)] @@ -568,22 +572,17 @@ macro_rules! with_pwm { } #[inline(always)] - fn enable_channel(&mut self, channel: Channel, b: bool) { - let c = channel as u8; + fn enable_channel(c: u8, b: bool) { + let tim = unsafe { &*<$TIM>::ptr() }; if c < Self::CH_NUMBER { if b { - unsafe { bb::set(&self.ccer, c*4) } + unsafe { bb::set(&tim.ccer, c*4) } } else { - unsafe { bb::clear(&self.ccer, c*4) } + unsafe { bb::clear(&tim.ccer, c*4) } } } } } - - pwm_pin!($TIM, C1, ccr1, 0); - pwm_pin!($TIM, C2, ccr2, 4); - pwm_pin!($TIM, C3, ccr3, 8); - pwm_pin!($TIM, C4, ccr4, 12); } } @@ -720,223 +719,3 @@ hal!( crate::pac::TIM13: [u16, CH1], crate::pac::TIM14: [u16, CH1], ); - -use crate::gpio::{self, Alternate}; - -// Output channels markers -pub trait CPin {} -pub struct C1; -pub struct C2; -pub struct C3; -pub struct C4; - -macro_rules! channel_impl { - ( $( $TIM:ident, $C:ident, $PINX:ident, $AF:literal; )+ ) => { - $( - impl CPin<$C, crate::pac::$TIM> for gpio::$PINX> { } - )+ - }; -} - -// The approach to PWM channel implementation is to group parts with -// common pins, starting with groupings of the largest number of parts -// and moving to smaller and smaller groupings. Last, we have individual -// parts to cover exceptions. - -// All parts have these PWM pins. -channel_impl!( - TIM1, C1, PA8, 1; - TIM1, C2, PA9, 1; - TIM1, C3, PA10, 1; - TIM1, C4, PA11, 1; - - TIM5, C1, PA0, 2; - TIM5, C2, PA1, 2; - TIM5, C3, PA2, 2; - TIM5, C4, PA3, 2; - - TIM9, C1, PA2, 3; - TIM9, C2, PA3, 3; - - TIM11, C1, PB9, 3; -); - -// All parts except F410. -#[cfg(any( - feature = "stm32f401", - feature = "stm32f405", - feature = "stm32f407", - feature = "stm32f411", - feature = "stm32f412", - feature = "stm32f413", - feature = "stm32f415", - feature = "stm32f417", - feature = "stm32f423", - feature = "stm32f427", - feature = "stm32f429", - feature = "stm32f437", - feature = "stm32f439", - feature = "stm32f446", - feature = "stm32f469", - feature = "stm32f479" -))] -channel_impl!( - TIM1, C1, PE9, 1; - TIM1, C2, PE11, 1; - TIM1, C3, PE13, 1; - TIM1, C4, PE14, 1; - - TIM2, C1, PA0, 1; - TIM2, C2, PA1, 1; - TIM2, C3, PA2, 1; - TIM2, C4, PA3, 1; - - TIM2, C2, PB3, 1; - TIM2, C3, PB10, 1; - TIM2, C4, PB11, 1; - - TIM2, C1, PA5, 1; - TIM2, C1, PA15, 1; - - TIM3, C1, PA6, 2; - TIM3, C2, PA7, 2; - TIM3, C3, PB0, 2; - TIM3, C4, PB1, 2; - - TIM3, C1, PB4, 2; - TIM3, C2, PB5, 2; - - TIM3, C1, PC6, 2; - TIM3, C2, PC7, 2; - TIM3, C3, PC8, 2; - TIM3, C4, PC9, 2; - - TIM4, C1, PB6, 2; - TIM4, C2, PB7, 2; - TIM4, C3, PB8, 2; - TIM4, C4, PB9, 2; - - TIM4, C1, PD12, 2; - TIM4, C2, PD13, 2; - TIM4, C3, PD14, 2; - TIM4, C4, PD15, 2; - - TIM10, C1, PB8, 3; -); - -// All parts except F401 and F410. -#[cfg(any( - feature = "stm32f405", - feature = "stm32f407", - feature = "stm32f411", - feature = "stm32f412", - feature = "stm32f413", - feature = "stm32f415", - feature = "stm32f417", - feature = "stm32f423", - feature = "stm32f427", - feature = "stm32f429", - feature = "stm32f437", - feature = "stm32f439", - feature = "stm32f446", - feature = "stm32f469", - feature = "stm32f479" -))] -channel_impl!( - TIM9, C1, PE5, 3; - TIM9, C2, PE6, 3; -); - -// All parts except F401, F410, and F411. -#[cfg(any( - feature = "stm32f405", - feature = "stm32f407", - feature = "stm32f412", - feature = "stm32f413", - feature = "stm32f415", - feature = "stm32f417", - feature = "stm32f423", - feature = "stm32f427", - feature = "stm32f429", - feature = "stm32f437", - feature = "stm32f439", - feature = "stm32f446", - feature = "stm32f469", - feature = "stm32f479" -))] -channel_impl!( - TIM8, C1, PC6, 3; - TIM8, C2, PC7, 3; - TIM8, C3, PC8, 3; - TIM8, C4, PC9, 3; - - TIM10, C1, PF6, 3; - - TIM11, C1, PF7, 3; - - TIM12, C1, PB14, 9; - TIM12, C2, PB15, 9; - - TIM13, C1, PA6, 9; - TIM13, C1, PF8, 9; // Not a mistake: TIM13 has only one channel. - - TIM14, C1, PA7, 9; - TIM14, C1, PF9, 9; // Not a mistake: TIM14 has only one channel. -); - -// STM's "advanced and foundation" lines except F446. -#[cfg(any( - feature = "stm32f405", - feature = "stm32f407", - feature = "stm32f415", - feature = "stm32f417", - feature = "stm32f427", - feature = "stm32f429", - feature = "stm32f437", - feature = "stm32f439", - feature = "stm32f469", - feature = "stm32f479" -))] -channel_impl!( - TIM5, C1, PH10, 2; - TIM5, C2, PH11, 2; - TIM5, C3, PH12, 2; - TIM5, C4, PI0, 2; - - TIM8, C1, PI5, 3; - TIM8, C2, PI6, 3; - TIM8, C3, PI7, 3; - TIM8, C4, PI2, 3; - - TIM12, C1, PH6, 9; - TIM12, C2, PH9, 9; -); - -#[cfg(any(feature = "stm32f412", feature = "stm32f413", feature = "stm32f423"))] -channel_impl!( - TIM5, C1, PF3, 2; - TIM5, C2, PF4, 2; - TIM5, C3, PF5, 2; - TIM5, C4, PF10, 2; -); - -#[cfg(feature = "stm32f410")] -channel_impl!( - TIM5, C1, PB12, 2; - TIM5, C2, PC10, 2; - TIM5, C3, PC11, 2; - TIM5, C4, PB11, 2; - - TIM9, C1, PC4, 3; - TIM9, C2, PC5, 3; - - TIM11, C1, PC13, 3; -); - -#[cfg(feature = "stm32f446")] -channel_impl!( - TIM2, C1, PB8, 1; - TIM2, C2, PB9, 1; - - TIM2, C4, PB2, 1; -); diff --git a/src/timer/pins.rs b/src/timer/pins.rs new file mode 100644 index 000000000..101cfef7c --- /dev/null +++ b/src/timer/pins.rs @@ -0,0 +1,220 @@ +use crate::gpio::{self, Alternate}; + +// Output channels markers +pub trait CPin {} +pub struct Ch; +pub const C1: u8 = 0; +pub const C2: u8 = 1; +pub const C3: u8 = 2; +pub const C4: u8 = 3; + +macro_rules! channel_impl { + ( $( $TIM:ident, $C:ident, $PINX:ident, $AF:literal; )+ ) => { + $( + impl CPin for gpio::$PINX> { } + )+ + }; +} + +// The approach to PWM channel implementation is to group parts with +// common pins, starting with groupings of the largest number of parts +// and moving to smaller and smaller groupings. Last, we have individual +// parts to cover exceptions. + +// All parts have these PWM pins. +channel_impl!( + TIM1, C1, PA8, 1; + TIM1, C2, PA9, 1; + TIM1, C3, PA10, 1; + TIM1, C4, PA11, 1; + + TIM5, C1, PA0, 2; + TIM5, C2, PA1, 2; + TIM5, C3, PA2, 2; + TIM5, C4, PA3, 2; + + TIM9, C1, PA2, 3; + TIM9, C2, PA3, 3; + + TIM11, C1, PB9, 3; +); + +// All parts except F410. +#[cfg(any( + feature = "stm32f401", + feature = "stm32f405", + feature = "stm32f407", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f415", + feature = "stm32f417", + feature = "stm32f423", + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f446", + feature = "stm32f469", + feature = "stm32f479" +))] +channel_impl!( + TIM1, C1, PE9, 1; + TIM1, C2, PE11, 1; + TIM1, C3, PE13, 1; + TIM1, C4, PE14, 1; + + TIM2, C1, PA0, 1; + TIM2, C2, PA1, 1; + TIM2, C3, PA2, 1; + TIM2, C4, PA3, 1; + + TIM2, C2, PB3, 1; + TIM2, C3, PB10, 1; + TIM2, C4, PB11, 1; + + TIM2, C1, PA5, 1; + TIM2, C1, PA15, 1; + + TIM3, C1, PA6, 2; + TIM3, C2, PA7, 2; + TIM3, C3, PB0, 2; + TIM3, C4, PB1, 2; + + TIM3, C1, PB4, 2; + TIM3, C2, PB5, 2; + + TIM3, C1, PC6, 2; + TIM3, C2, PC7, 2; + TIM3, C3, PC8, 2; + TIM3, C4, PC9, 2; + + TIM4, C1, PB6, 2; + TIM4, C2, PB7, 2; + TIM4, C3, PB8, 2; + TIM4, C4, PB9, 2; + + TIM4, C1, PD12, 2; + TIM4, C2, PD13, 2; + TIM4, C3, PD14, 2; + TIM4, C4, PD15, 2; + + TIM10, C1, PB8, 3; +); + +// All parts except F401 and F410. +#[cfg(any( + feature = "stm32f405", + feature = "stm32f407", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f415", + feature = "stm32f417", + feature = "stm32f423", + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f446", + feature = "stm32f469", + feature = "stm32f479" +))] +channel_impl!( + TIM9, C1, PE5, 3; + TIM9, C2, PE6, 3; +); + +// All parts except F401, F410, and F411. +#[cfg(any( + feature = "stm32f405", + feature = "stm32f407", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f415", + feature = "stm32f417", + feature = "stm32f423", + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f446", + feature = "stm32f469", + feature = "stm32f479" +))] +channel_impl!( + TIM8, C1, PC6, 3; + TIM8, C2, PC7, 3; + TIM8, C3, PC8, 3; + TIM8, C4, PC9, 3; + + TIM10, C1, PF6, 3; + + TIM11, C1, PF7, 3; + + TIM12, C1, PB14, 9; + TIM12, C2, PB15, 9; + + TIM13, C1, PA6, 9; + TIM13, C1, PF8, 9; // Not a mistake: TIM13 has only one channel. + + TIM14, C1, PA7, 9; + TIM14, C1, PF9, 9; // Not a mistake: TIM14 has only one channel. +); + +// STM's "advanced and foundation" lines except F446. +#[cfg(any( + feature = "stm32f405", + feature = "stm32f407", + feature = "stm32f415", + feature = "stm32f417", + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f469", + feature = "stm32f479" +))] +channel_impl!( + TIM5, C1, PH10, 2; + TIM5, C2, PH11, 2; + TIM5, C3, PH12, 2; + TIM5, C4, PI0, 2; + + TIM8, C1, PI5, 3; + TIM8, C2, PI6, 3; + TIM8, C3, PI7, 3; + TIM8, C4, PI2, 3; + + TIM12, C1, PH6, 9; + TIM12, C2, PH9, 9; +); + +#[cfg(any(feature = "stm32f412", feature = "stm32f413", feature = "stm32f423"))] +channel_impl!( + TIM5, C1, PF3, 2; + TIM5, C2, PF4, 2; + TIM5, C3, PF5, 2; + TIM5, C4, PF10, 2; +); + +#[cfg(feature = "stm32f410")] +channel_impl!( + TIM5, C1, PB12, 2; + TIM5, C2, PC10, 2; + TIM5, C3, PC11, 2; + TIM5, C4, PB11, 2; + + TIM9, C1, PC4, 3; + TIM9, C2, PC5, 3; + + TIM11, C1, PC13, 3; +); + +#[cfg(feature = "stm32f446")] +channel_impl!( + TIM2, C1, PB8, 1; + TIM2, C2, PB9, 1; + + TIM2, C4, PB2, 1; +);