From e2439a06247b9fb8627036696cb76141cd057b72 Mon Sep 17 00:00:00 2001 From: Christophe Augier Date: Tue, 3 Jun 2025 17:14:06 +0200 Subject: [PATCH 01/12] Add timer from stm32h7xx --- Cargo.toml | 7 + src/lib.rs | 6 + src/prelude.rs | 2 + src/timer.rs | 441 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 456 insertions(+) create mode 100644 src/timer.rs diff --git a/Cargo.toml b/Cargo.toml index 92f18eb..6ad41b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,6 +79,13 @@ log = { version = "0.4.20", optional = true} futures-util = { version = "0.3", default-features = false, features = ["async-await-macro"], optional = true} stm32-usbd = "0.8.0" +## +embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } +nb = "1.0.0" +void = { version = "1.0.2", default-features = false } +cast = { version = "0.3.0", default-features = false } +## + [dev-dependencies] log = { version = "0.4.20"} cortex-m-rt = "0.7.3" diff --git a/src/lib.rs b/src/lib.rs index cc3c317..de063a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,9 @@ #![cfg_attr(docsrs, feature(doc_cfg))] #![allow(non_camel_case_types)] +pub use nb; +pub use nb::block; + #[cfg(not(feature = "device-selected"))] compile_error!( "This crate requires one of the following device features enabled: @@ -85,6 +88,9 @@ pub mod usb; #[cfg(feature = "device-selected")] pub mod gpdma; +#[cfg(feature = "device-selected")] +pub mod timer; + #[cfg(feature = "device-selected")] mod sealed { pub trait Sealed {} diff --git a/src/prelude.rs b/src/prelude.rs index a73e785..15cf87d 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,4 +1,5 @@ //! Prelude +pub use embedded_hal_02::prelude::*; pub use crate::delay::DelayExt as _stm32h5xx_hal_delay_DelayExt; pub use crate::dwt::DwtExt as _stm32h5xx_hal_delay_DwtExt; @@ -10,6 +11,7 @@ pub use crate::pwr::PwrExt as _stm32h5xx_hal_pwr_PwrExt; pub use crate::rcc::RccExt as _stm32h5xx_hal_rcc_RccExt; pub use crate::spi::SpiExt as _stm32h5xx_hal_spi_SpiExt; pub use crate::usb::UsbExt as _stm32h5xx_hal_usb_UsbExt; +pub use crate::timer::TimerExt as _stm32h5xx_hal_timer_TimerExt; pub use crate::time::U32Ext as _; pub use fugit::{ExtU32 as _, RateExtU32 as _}; diff --git a/src/timer.rs b/src/timer.rs new file mode 100644 index 0000000..f56fe1e --- /dev/null +++ b/src/timer.rs @@ -0,0 +1,441 @@ +//! Timers +//! +//! # Examples +//! +//! - [Blinky using a Timer](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/blinky_timer.rs) +//! - [64 bit microsecond timer](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/tick_timer.rs) + +// TODO: on the h7x3 at least, only TIM2, TIM3, TIM4, TIM5 can support 32 bits. +// TIM1 is 16 bit. + +use core::marker::PhantomData; + +use crate::stm32::{TIM1, TIM2, TIM3, TIM6, TIM7}; +#[cfg(feature = "rm0481")] +use crate::stm32::{TIM12, TIM15, TIM4, TIM5, TIM8}; + +use cast::{u16, u32}; +use void::Void; + +use crate::rcc::{rec, CoreClocks, ResetEnable}; +use crate::time::Hertz; + +/// Associate clocks with timers +pub trait GetClk { + fn get_clk(clocks: &CoreClocks) -> Option; +} + +/// Timers with CK_INT derived from rcc_tim[xy]_ker_ck +macro_rules! impl_tim_ker_ck { + ($($ckX:ident: $($TIMX:ident),+)+) => { + $( + $( + impl GetClk for $TIMX { + fn get_clk(clocks: &CoreClocks) -> Option { + Some(clocks.$ckX()) + } + } + )+ + )+ + } +} +impl_tim_ker_ck! { + timx_ker_ck: TIM2, TIM3, TIM6, TIM7 + timy_ker_ck: TIM1 +} + +#[cfg(feature = "rm0481")] +impl_tim_ker_ck! { + timx_ker_ck: TIM4, TIM5, TIM12 + timy_ker_ck: TIM8, TIM15 +} + +/// External trait for hardware timers +pub trait TimerExt { + type Rec: ResetEnable; + + /// Configures a periodic timer + /// + /// Generates an overflow event at the `timeout` frequency. + fn timer(self, timeout: Hertz, prec: Self::Rec, clocks: &CoreClocks) + -> TIM; + + /// Configures the timer to count up at the given frequency + /// + /// Counts from 0 to the counter's maximum value, then repeats. + /// Because this only uses the timer prescaler, the frequency + /// is rounded to a multiple of the timer's kernel clock. + /// + /// For example, calling `.tick_timer(1.MHz(), ..)` for a 16-bit timer will + /// result in a timers that increments every microsecond and overflows every + /// ~65 milliseconds + fn tick_timer( + self, + frequency: Hertz, + prec: Self::Rec, + clocks: &CoreClocks, + ) -> TIM; +} + +/// Hardware timers +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Timer { + clk: u32, + tim: TIM, +} + +/// Timer Events +/// +/// Each event is a possible interrupt source, if enabled +pub enum Event { + /// Timer timed out / count down ended + TimeOut, +} + +macro_rules! hal { + ($($TIMX:ident: ($timX:ident, $Rec:ident, $cntType:ty),)+) => { + $( + impl embedded_hal_02::timer::Periodic for Timer<$TIMX> {} + + impl embedded_hal_02::timer::CountDown for Timer<$TIMX> { + type Time = Hertz; + + fn start(&mut self, timeout: T) + where + T: Into, + { + // Pause + self.pause(); + + // Reset counter + self.reset_counter(); + + // UEV event occours on next overflow + self.urs_counter_only(); + self.clear_irq(); + + // Set PSC and ARR + self.set_freq(timeout.into()); + + // Generate an update event to force an update of the ARR register. This ensures + // the first timer cycle is of the specified duration. + self.apply_freq(); + + // Start counter + self.resume() + } + + fn wait(&mut self) -> nb::Result<(), Void> { + if self.is_irq_clear() { + Err(nb::Error::WouldBlock) + } else { + self.clear_irq(); + Ok(()) + } + } + } + + impl TimerExt> for $TIMX { + type Rec = rec::$Rec; + + fn timer(self, timeout: Hertz, + prec: Self::Rec, clocks: &CoreClocks + ) -> Timer<$TIMX> { + use embedded_hal_02::timer::CountDown; + + let mut timer = Timer::$timX(self, prec, clocks); + timer.start(timeout); + timer + } + + fn tick_timer(self, frequency: Hertz, + prec: Self::Rec, clocks: &CoreClocks + ) -> Timer<$TIMX> { + let mut timer = Timer::$timX(self, prec, clocks); + + timer.pause(); + + // UEV event occours on next overflow + timer.urs_counter_only(); + timer.clear_irq(); + + // Set PSC and ARR + timer.set_tick_freq(frequency); + + // Generate an update event to force an update of the ARR + // register. This ensures the first timer cycle is of the + // specified duration. + timer.apply_freq(); + + // Start counter + timer.resume(); + + timer + } + } + + impl Timer<$TIMX> { + /// Configures a TIM peripheral as a periodic count down timer, + /// without starting it + pub fn $timX(tim: $TIMX, prec: rec::$Rec, clocks: &CoreClocks) -> Self + { + // enable and reset peripheral to a clean state + let _ = prec.enable().reset(); // drop, can be recreated by free method + + let clk = $TIMX::get_clk(clocks) + .expect(concat!(stringify!($TIMX), ": Input clock not running!")).raw(); + + Timer { + clk, + tim, + } + } + + /// Configures the timer's frequency and counter reload value + /// so that it underflows at the timeout's frequency + pub fn set_freq(&mut self, timeout: Hertz) { + let ticks = self.clk / timeout.raw(); + + self.set_timeout_ticks(ticks); + } + + /// Sets the timer period from a time duration + /// + /// ``` + /// use stm32h7xx_hal::time::MilliSeconds; + /// + /// // Set timeout to 100ms + /// let timeout = MilliSeconds::from_ticks(100).into_rate(); + /// timer.set_timeout(timeout); + /// ``` + /// + /// Alternatively, the duration can be set using the + /// core::time::Duration type + /// + /// ``` + /// let duration = core::time::Duration::from_nanos(2_500); + /// + /// // Set timeout to 2.5µs + /// timer.set_timeout(duration); + /// ``` + pub fn set_timeout(&mut self, timeout: T) + where + T: Into + { + const NANOS_PER_SECOND: u64 = 1_000_000_000; + let timeout = timeout.into(); + + let clk = self.clk as u64; + let ticks = u32::try_from( + clk * timeout.as_secs() + + clk * u64::from(timeout.subsec_nanos()) / NANOS_PER_SECOND, + ) + .unwrap_or(u32::MAX); + + self.set_timeout_ticks(ticks.max(1)); + } + + /// Sets the timer's prescaler and auto reload register so that the timer will reach + /// the ARR after `ticks - 1` amount of timer clock ticks. + /// + /// ``` + /// // Set auto reload register to 50000 and prescaler to divide by 2. + /// timer.set_timeout_ticks(100000); + /// ``` + /// + /// This function will round down if the prescaler is used to extend the range: + /// ``` + /// // Set auto reload register to 50000 and prescaler to divide by 2. + /// timer.set_timeout_ticks(100001); + /// ``` + fn set_timeout_ticks(&mut self, ticks: u32) { + let (psc, arr) = calculate_timeout_ticks_register_values(ticks); + unsafe { + self.tim.psc().write(|w| w.psc().bits(psc)); + } + #[allow(unused_unsafe)] // method is safe for some timers + self.tim.arr().write(|w| unsafe { w.bits(u32(arr)) }); + } + + /// Configures the timer to count up at the given frequency + /// + /// Counts from 0 to the counter's maximum value, then repeats. + /// Because this only uses the timer prescaler, the frequency + /// is rounded to a multiple of the timer's kernel clock. + pub fn set_tick_freq(&mut self, frequency: Hertz) { + let div = self.clk / frequency.raw(); + + let psc = u16(div - 1).unwrap(); + unsafe { + self.tim.psc().write(|w| w.psc().bits(psc)); + } + + let counter_max = u32(<$cntType>::MAX); + #[allow(unused_unsafe)] // method is safe for some timers + self.tim.arr().write(|w| unsafe { w.bits(counter_max) }); + } + + /// Applies frequency/timeout changes immediately + /// + /// The timer will normally update its prescaler and auto-reload + /// value when its counter overflows. This function causes + /// those changes to happen immediately. Also clears the counter. + pub fn apply_freq(&mut self) { + self.tim.egr().write(|w| w.ug().set_bit()); + } + + /// Pauses the TIM peripheral + pub fn pause(&mut self) { + self.tim.cr1().modify(|_, w| w.cen().clear_bit()); + } + + /// Resume (unpause) the TIM peripheral + pub fn resume(&mut self) { + self.tim.cr1().modify(|_, w| w.cen().set_bit()); + } + + /// Set Update Request Source to counter overflow/underflow only + pub fn urs_counter_only(&mut self) { + self.tim.cr1().modify(|_, w| w.urs().counter_only()); + } + + /// Reset the counter of the TIM peripheral + pub fn reset_counter(&mut self) { + self.tim.cnt().reset(); + } + + /// Read the counter of the TIM peripheral + pub fn counter(&self) -> u32 { + self.tim.cnt().read().cnt().bits().into() + } + + /// Start listening for `event` + pub fn listen(&mut self, event: Event) { + match event { + Event::TimeOut => { + // Enable update event interrupt + self.tim.dier().write(|w| w.uie().set_bit()); + } + } + } + + /// Stop listening for `event` + pub fn unlisten(&mut self, event: Event) { + match event { + Event::TimeOut => { + // Disable update event interrupt + self.tim.dier().write(|w| w.uie().clear_bit()); + let _ = self.tim.dier().read(); + let _ = self.tim.dier().read(); // Delay 2 peripheral clocks + } + } + } + + /// Check if Update Interrupt flag is cleared + pub fn is_irq_clear(&mut self) -> bool { + self.tim.sr().read().uif().bit_is_clear() + } + + /// Clears interrupt flag + pub fn clear_irq(&mut self) { + self.tim.sr().modify(|_, w| { + // Clears timeout event + w.uif().clear_bit() + }); + let _ = self.tim.sr().read(); + let _ = self.tim.sr().read(); // Delay 2 peripheral clocks + } + + /// Releases the TIM peripheral + pub fn free(mut self) -> ($TIMX, rec::$Rec) { + // pause counter + self.pause(); + + (self.tim, rec::$Rec { _marker: PhantomData }) + } + + /// Returns a reference to the inner peripheral + pub fn inner(&self) -> &$TIMX { + &self.tim + } + + /// Returns a mutable reference to the inner peripheral + pub fn inner_mut(&mut self) -> &mut $TIMX { + &mut self.tim + } + } + )+ + } +} + +/// We want to have `ticks` amount of timer ticks before it reloads. +/// But `ticks` may have a higher value than what the timer can hold directly. +/// So we'll use the prescaler to extend the range. +/// +/// To know how many times we would overflow with a prescaler of 1, we divide `ticks` by 2^16 (the max amount of ticks per overflow). +/// If the result is e.g. 3, then we need to increase our range by 4 times to fit all the ticks. +/// We can increase the range enough by setting the prescaler to 3 (which will divide the clock freq by 4). +/// Because every tick is now 4x as long, we need to divide `ticks` by 4 to keep the same timeout. +/// +/// This function returns the prescaler register value and auto reload register value. +fn calculate_timeout_ticks_register_values(ticks: u32) -> (u16, u16) { + // Note (unwrap): Never panics because 32-bit value is shifted right by 16 bits, + // resulting in a value that always fits in 16 bits. + let psc = u16(ticks / (1 << 16)).unwrap(); + // Note (unwrap): Never panics because the divisor is always such that the result fits in 16 bits. + // Also note that the timer counts `0..=arr`, so subtract 1 to get the correct period. + let arr = u16(ticks / (u32(psc) + 1)).unwrap().saturating_sub(1); + (psc, arr) +} + +hal! { + // Advanced-control + TIM1: (tim1, Tim1, u16), + + // General-purpose + TIM2: (tim2, Tim2, u32), + TIM3: (tim3, Tim3, u16), + + // Basic + TIM6: (tim6, Tim6, u16), + TIM7: (tim7, Tim7, u16), +} + +#[cfg(feature = "rm0481")] +hal! { + // Advanced-control + TIM8: (tim8, Tim8, u16), + + // General-purpose + TIM4: (tim4, Tim4, u16), + TIM5: (tim5, Tim5, u32), + + // General-purpose + TIM12: (tim12, Tim12, u16), + + // General-purpose + TIM15: (tim15, Tim15, u16), +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn timeout_ticks_register_values() { + assert_eq!(calculate_timeout_ticks_register_values(0), (0, 0)); + assert_eq!(calculate_timeout_ticks_register_values(50000), (0, 49999)); + assert_eq!(calculate_timeout_ticks_register_values(100000), (1, 49999)); + assert_eq!(calculate_timeout_ticks_register_values(65535), (0, 65534)); + assert_eq!(calculate_timeout_ticks_register_values(65536), (1, 32767)); + assert_eq!( + calculate_timeout_ticks_register_values(1000000), + (15, 62499) + ); + assert_eq!( + calculate_timeout_ticks_register_values(u32::MAX), + (u16::MAX, u16::MAX - 1) + ); + } +} From f4ef9d39b5a0582d2be88eee5c790dd102978996 Mon Sep 17 00:00:00 2001 From: Christophe Augier Date: Thu, 12 Jun 2025 10:26:57 +0200 Subject: [PATCH 02/12] Add blinky_timer example --- Cargo.toml | 4 ++ examples/blinky_timer.rs | 84 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 examples/blinky_timer.rs diff --git a/Cargo.toml b/Cargo.toml index 6ad41b2..bf2c27e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -112,6 +112,10 @@ opt-level = "s" # optimize for binary size [[example]] name = "blinky" +[[example]] +name = "blinky_timer" +required-features = ["stm32h533"] + [[example]] name = "i2c" required-features = ["stm32h503"] diff --git a/examples/blinky_timer.rs b/examples/blinky_timer.rs new file mode 100644 index 0000000..dd00db9 --- /dev/null +++ b/examples/blinky_timer.rs @@ -0,0 +1,84 @@ +#![deny(warnings)] +#![no_main] +#![no_std] + +mod utilities; + +use core::{ + cell::RefCell, + sync::atomic::{AtomicBool, Ordering}, +}; + +use cortex_m::interrupt::Mutex; +use cortex_m::peripheral::NVIC; +use cortex_m_rt::entry; + +use stm32h5xx_hal::gpio::gpioa::PA5; // LED pin +use stm32h5xx_hal::gpio::{Output, PushPull}; +use stm32h5xx_hal::{pac, pac::interrupt, prelude::*, timer}; +use utilities::logger::info; + +static LED_IS_ON: AtomicBool = AtomicBool::new(false); +static LED: Mutex>>>> = + Mutex::new(RefCell::new(None)); +static TIMER: Mutex>>> = + Mutex::new(RefCell::new(None)); + +#[entry] +fn main() -> ! { + utilities::logger::init(); + + let mut cp = cortex_m::Peripherals::take().unwrap(); + let dp = pac::Peripherals::take().unwrap(); + + let pwr = dp.PWR.constrain(); + let pwrcfg = pwr.vos0().freeze(); + + // Constrain and Freeze clock + let rcc = dp.RCC.constrain(); + let ccdr = rcc.sys_ck(250.MHz()).freeze(pwrcfg, &dp.SBS); + + let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA); + let mut led = gpioa.pa5.into_push_pull_output(); + led.set_low(); + + let mut timer = dp.TIM2.timer(2.Hz(), ccdr.peripheral.TIM2, &ccdr.clocks); + timer.listen(timer::Event::TimeOut); + + cortex_m::interrupt::free(|cs| { + LED.borrow(cs).replace(Some(led)); + TIMER.borrow(cs).replace(Some(timer)); + }); + + info!("Start blinking with timer..."); + // Enable TIM2 interrupt + unsafe { + cp.NVIC.set_priority(interrupt::TIM2, 1); + NVIC::unmask::(interrupt::TIM2); + } + + loop { + // do_nothing + } +} + +/// Handle timer overflow +/// +/// The interrupt should be configured at maximum priority, it won't take very long. +#[interrupt] +fn TIM2() { + cortex_m::interrupt::free(|cs| { + if let Some(timer) = TIMER.borrow(cs).borrow_mut().as_mut() { + timer.clear_irq(); + } + // Signal that the interrupt fired + let led_is_on = LED_IS_ON.fetch_not(Ordering::Relaxed); + if let Some(led) = LED.borrow(cs).borrow_mut().as_mut() { + if led_is_on { + led.set_low(); + } else { + led.set_high(); + } + } + }) +} From da8c2a34bee95025ff466994077cf3059c9b8d1e Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Tue, 26 Aug 2025 21:52:17 +0200 Subject: [PATCH 03/12] Remove TIM12 for now due to it missing for h523 pac --- src/timer.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/timer.rs b/src/timer.rs index f56fe1e..988c59b 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -12,7 +12,7 @@ use core::marker::PhantomData; use crate::stm32::{TIM1, TIM2, TIM3, TIM6, TIM7}; #[cfg(feature = "rm0481")] -use crate::stm32::{TIM12, TIM15, TIM4, TIM5, TIM8}; +use crate::stm32::{/*TIM12, */TIM15, TIM4, TIM5, TIM8}; // TODO: TIM12 seems to be missing for 523's pac, re add once fixed use cast::{u16, u32}; use void::Void; @@ -46,7 +46,7 @@ impl_tim_ker_ck! { #[cfg(feature = "rm0481")] impl_tim_ker_ck! { - timx_ker_ck: TIM4, TIM5, TIM12 + timx_ker_ck: TIM4, TIM5 //TIM12 // TODO: TIM12 seems to be missing for 523's pac, re add once fixed timy_ker_ck: TIM8, TIM15 } @@ -412,7 +412,7 @@ hal! { TIM5: (tim5, Tim5, u32), // General-purpose - TIM12: (tim12, Tim12, u16), + //TIM12: (tim12, Tim12, u16), // TODO: TIM12 seems to be missing for 523's pac, re add once fixed // General-purpose TIM15: (tim15, Tim15, u16), From 90b41a1eeedbcc9abe1de6ea4f741999cacaef00 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Mon, 1 Sep 2025 19:00:42 +0200 Subject: [PATCH 04/12] Add pwm from h7 hal --- src/pwm.rs | 1816 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1816 insertions(+) create mode 100644 src/pwm.rs diff --git a/src/pwm.rs b/src/pwm.rs new file mode 100644 index 0000000..e08d8a8 --- /dev/null +++ b/src/pwm.rs @@ -0,0 +1,1816 @@ +//! Pulse Width Modulation (PWM) +//! +//! PWM output is avaliable for the advanced control timers (`TIM1`, `TIM8`), +//! the general purpose timers (`TIM[2-5]`, `TIM[12-17]`) and the Low-power +//! timers (`LPTIM[1-5]`). +//! +//! Timers support up to 4 simultaneous PWM output channels +//! +//! ## Examples +//! +//! - [Simple example](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/pwm.rs) +//! - [Advanced example](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/pwm_advanced.rs) +//! - [LPTIM peripheral example](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/pwm_lptim.rs) +//! +//! ## Usage +//! +//! ```rust +//! let gpioa = ..; // Set up and split GPIOA +//! let pins = ( +//! gpioa.pa8.into_alternate_af1(), +//! gpioa.pa9.into_alternate_af1(), +//! gpioa.pa10.into_alternate_af1(), +//! gpioa.pa11.into_alternate_af1(), +//! ); +//! ``` +//! +//! To see which pins can be used with which timers, see your device datasheet or see which pins implement the [Pins](trait.Pins.html) trait. +//! +//! Then call the `pwm` function on the corresponding timer: +//! +//! ``` +//! let device: pac::Peripherals = ..; +//! +//! // Put the timer in PWM mode using the specified pins +//! // with a frequency of 100 Hz. +//! let (c0, c1, c2, c3) = device.TIM1.pwm( +//! pins, +//! 100.Hz(), +//! prec, +//! &clocks +//! ); +//! +//! // Set the duty cycle of channel 0 to 50% +//! c0.set_duty(c0.get_max_duty() / 2); +//! // PWM outputs are disabled by default +//! c0.enable() +//! ``` +//! +//! ## Advanced features +//! +//! Some timers support various advanced features. These features are +//! accessed by calling TIMx.[pwm_advanced](trait.PwmAdvExt.html#tymethod.pwm_advanced) to get a [PwmBuilder](struct.PwmBuilder.html) +//! and calling appropriate methods of the PwmBuilder before calling [PwmBuilder::finalize](struct.PwmBuilder.html#method.finalize) +//! to create the PWM channels and a [PwmControl](struct.PwmControl.html) struct exposing things like [FaultMonitor](trait.FaultMonitor.html) functionality. +//! +//! ```rust +//! let gpioa = ..; // Set up and split GPIOA +//! let pins = ( +//! gpioa.pa8.into_alternate_af1(), +//! gpioa.pa9.into_alternate_af1(), +//! gpioa.pa10.into_alternate_af1(), +//! gpioa.pa11.into_alternate_af1(), +//! ); +//! ``` +//! +//! Then call the `pwm_advanced` function on the corresponding timer: +//! +//! ``` +//! let device: pac::Peripherals = ..; +//! +//! // Put the timer in PWM mode using the specified pins +//! // with a frequency of 100 Hz, 2us deadtime between complementary edges, +//! // center-aligned PWM, and an active-low fault input +//! let (mut control, (c1, c2, c3, c4)) = device.TIM1 +//! .pwm_advanced( +//! pins, +//! prec, +//! &clocks +//! ) +//! .frequency(100.Hz()) +//! .center_aligned() +//! .with_break_pin(gpioe.pe15.into_alternate_af1(), Polarity::ActiveLow) +//! .finalize(); +//! ``` +//! +//! Then change some PWM channels to active-low (reversing pin polarity relative to logic polarity) +//! or enable a complementary PWM output (both only on some timer channels). +//! +//! ``` +//! // Set channel 1 to complementary with both the regular and complementary output active low +//! let mut c1 = c1 +//! .into_complementary(gpioe.pe8.into_alternate_af1()) +//! .into_active_low() +//! .into_comp_active_low(); +//! +//! // Set the duty cycle of channel 1 to 50% +//! c1.set_duty(c1.get_max_duty() / 2); +//! +//! // PWM outputs are disabled by default +//! c1.enable() +//! +//! // If a PWM fault happened, you can clear it through the control structure +//! if control.is_fault_active() { +//! control.clear_fault(); +//! } +//! ``` +//! +//! ## Fault (Break) inputs +//! +//! The [PwmBuilder::with_break_pin](struct.PwmBuilder.html#method.with_break_pin) method emables break/fault functionality as described in the reference manual. +//! +//! The [PwmControl](struct.PwmControl.html) will then implement [FaultMonitor](trait.FaultMonitor.html) which can be used to monitor and control the fault status. +//! +//! If the break input becomes active, all PWM will be stopped. +//! +//! The BKIN hardware respects deadtimes when going into the fault state while the BKIN2 hardware acts immediately. +//! +//! The fault state puts all PWM pins into high-impedance mode, so pull-ups or pull-downs should be used to set the pins to a safe state. +//! +//! Currently only one break input (BKIN or BKIN2) can be enabled, this could be changed to allow two break inputs at the same time. +//! +//! ## Complementary outputs +//! +//! Once a PWM channel has been created through TIMx.pwm(...) or TIMx.pwm_advanced(...).finalize(), it can be put into complementary mode or have its polarity changed. +//! +//! [Pwm::into_complementary](struct.Pwm.html#method.into_complementary) takes a pin that can be used as a complementary output +//! +//! For allowed pins, see the device datasheet or see which pins implement the [NPins](trait.NPins.html) trait. +//! +//! ## PWM alignment +//! +//! A timer with multiple PWM channels can have different alignments between PWM channels. +//! +//! All PWM-capable timers support left aligned PWM. In left aligned PWM, all channels go active at the start of a PWM cycle then go inactive when their duty cycles expire. +//! +//! Some timers also support right aligned and center aligned PWM. In right aligned PWM, all channels go inactive at the end of a PWM cycle and go active when their duty cycle remains until the end of the PWM cycle. +//! +//! In center aligned PWM, all channels start inactive, then go active when half their duty cycle remains until the center of the PWM period, then go inactive again once their duty cycle expires and remain inactive for the rest of the PWM cycle. +//! This produces a symmetrical PWM waveform, with increasing duty cycle moving both the inactive and active edge equally. +//! When a component is placed across multiple PWM channels with different duty cycles in center aligned mode, the component will see twice the ripple frequency as the PWM switching frequency. +//! +//! ## PWM channel polarity +//! +//! A PWM channel is active or inactive based on the duty cycle, alignment, etc. However, the actual GPIO signal level that represents active vs inactive is configurable. +//! +//! The [into_active_low](struct.Pwm.html#method.into_active_low) and [into_active_high](struct.Pwm.html#method.into_active_high) methods set the active signal level to low (VSS) or high (VDD). +//! +//! The complementary output is active when the regular output is inactive. The active signal level of the complementary output is set by the [into_comp_active_low](struct.Pwm.html#method.into_comp_active_low), and [into_comp_active_high](struct.Pwm.html#method.into_comp_active_high) methods. +//! +//! ## Deadtime +//! +//! All channels on a given timer share the same deadtime setting as set by [PwmBuilder::with_deadtime](struct.PwmBuilder.html#method.with_deadtime) +//! +//! PWM channels with complementary outputs can have deadtime added to the signal. Dead time is used to prevent cross-conduction in some power electronics topologies. +//! +//! With complementary outputs and dead time enabled on a PWM channel, when the regular output goes inactive (high or low based on into_active_high/into_active_low), the complementary output remains inactive until the deadtime passes. +//! Similarily, when the complementary output goes inactive, the regular output waits until the deadtime passes before it goes active. +//! +//! Deadtime is applied based on the logical active/inactive levels. Depending on the PWM polarity and complementary polarity, both pins can be high or low during deadtime; they will both be in the inactive state. +//! +//! The deadtime must be 4032 counts of the timer clock or less or the builder will assert/panic. For a 200MHz timer this is 20 microseconds; slower timers can have even longer deadtimes. +//! +//! ## Disabled or faulted state +//! +//! At initialization, when a PWM channel is disabled, or while a fault is active, the PWM outputs will be in a high impedance state. +//! +//! If needed, pull-up or pull-down resistors should be used to ensure that all power electronics are in a safe state while the GPIO pins are high impedance. +//! +//! Although the timers allow quite a bit of configuration here, that would require configuring the PWM pins before configuring other parts of the timer, which would be a challenge with how type states and traits are used for timer configuration. +//! +//! Additionally, the GPIO will always be high-impedance during power-up or in reset, so pull-ups or pull-downs to ensure safe state are always a good idea. + +use core::marker::PhantomData; + +use crate::pac; + +use crate::rcc::{rec, CoreClocks, ResetEnable}; +use crate::time::{Hertz, NanoSeconds}; +use crate::timer::GetClk; +use fugit::ExtU32; + +use crate::gpio::{self, Alternate}; + +// This trait marks that a GPIO pin can be used with a specific timer channel +// TIM is the timer being used +// CHANNEL is a marker struct for the channel (or multi channels for tuples) +// Example: impl Pins for PA8> { type Channel = Pwm; } +/// Pins is a trait that marks which GPIO pins may be used as PWM channels; it should not be directly used. +/// See the device datasheet 'Pin descriptions' chapter for which pins can be used with which timer PWM channels (or look at Implementors) +pub trait Pins { + type Channel; + fn split() -> Self::Channel; +} + +/// NPins is a trait that marks which GPIO pins may be used as complementary PWM channels; it should not be directly used. +/// See the device datasheet 'Pin descriptions' chapter for which pins can be used with which timer PWM channels (or look at Implementors) +pub trait NPins {} + +/// FaultPins is a trait that marks which GPIO pins may be used as PWM fault inputs; it should not be directly used. +/// See the device datasheet 'Pin descriptions' chapter for which pins can be used with which timer PWM channels (or look at Implementors) +pub trait FaultPins { + const INPUT: BreakInput; +} + +/// Channel wrapper +pub struct Ch; +impl Ch { + const EN: u32 = 1 << (C * 4); + const POL: u32 = 1 << (C * 4 + 1); + const N_EN: u32 = 1 << (C * 4 + 2); + const N_POL: u32 = 1 << (C * 4 + 3); +} + +/// Marker struct for PWM channel 1 on Pins trait and Pwm struct +pub const C1: u8 = 0; +/// Marker struct for PWM channel 2 on Pins trait and Pwm struct +pub const C2: u8 = 1; +/// Marker struct for PWM channel 3 on Pins trait and Pwm struct +pub const C3: u8 = 2; +/// Marker struct for PWM channel 4 on Pins trait and Pwm struct +pub const C4: u8 = 3; + +/// Marker struct for pins and PWM channels that do not support complementary output +pub struct ComplementaryImpossible; +/// Marker struct for pins and PWM channels that support complementary output but are not using it +pub struct ComplementaryDisabled; +/// Marker struct for PWM channels that have complementary outputs enabled +pub struct ComplementaryEnabled; + +/// Enum for IO polarity +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Polarity { + ActiveHigh, + ActiveLow, +} + +/// Configuration enum to keep track of which break input corresponds with which FaultPins +#[derive(PartialEq, Eq)] +pub enum BreakInput { + BreakIn, + BreakIn2, +} + +/// Internal enum that keeps track of the count settings before PWM is finalized +enum CountSettings { + Frequency(Hertz), + Explicit { period: WIDTH, prescaler: u16 }, +} + +/// Marker struct for active high IO polarity +pub struct ActiveHigh; +/// Marker struct for active low IO polarity +pub struct ActiveLow; + +/// Whether a PWM signal is left-aligned, right-aligned, or center-aligned +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Alignment { + Left, + Right, + Center, +} + +/// Pwm represents one PWM channel; it is created by calling TIM?.pwm(...) and lets you control the channel through the PwmPin trait +pub struct Pwm { + _markers: PhantomData<(TIM, COMP)>, +} + +impl Pwm { + fn new() -> Self { + Self { + _markers: PhantomData, + } + } +} + +/// PwmBuilder is used to configure advanced PWM features +pub struct PwmBuilder { + _markers: PhantomData<(TIM, PINS, CHANNEL, FAULT, COMP)>, + alignment: Alignment, + base_freq: Hertz, + count: CountSettings, + bkin_enabled: bool, // If the FAULT type parameter is FaultEnabled, either bkin or bkin2 must be enabled + bkin2_enabled: bool, + fault_polarity: Polarity, + deadtime: NanoSeconds, +} + +/// Allows a PwmControl to monitor and control faults (break inputs) of a timer's PWM channels +pub trait FaultMonitor { + /// Returns true if a fault is preventing PWM output + fn is_fault_active(&self) -> bool; + + /// Enables PWM output, clearing fault state and immediately resuming PWM; if the break pin is still active, this can't clear the fault. + fn clear_fault(&mut self); + + /// Disables PWM output, setting fault state; this can be used to stop all PWM from a timer in software detected faults + fn set_fault(&mut self); +} + +/// Exposes timer wide advanced features, such as [FaultMonitor](trait.FaultMonitor.html) +/// or future features like trigger outputs for synchronization with ADCs and other peripherals +pub struct PwmControl { + _tim: PhantomData, + _fault: PhantomData, +} + +impl PwmControl { + fn new() -> Self { + Self { + _tim: PhantomData, + _fault: PhantomData, + } + } +} + +/// Marker struct indicating that a PwmControl is in charge of fault monitoring +pub struct FaultEnabled; +/// Marker struct indicating that a PwmControl does not handle fault monitoring +pub struct FaultDisabled; + +// automatically implement Pins trait for tuples of individual pins +macro_rules! pins_tuples { + // Tuple of two pins + ($(($CHA:ident, $CHB:ident)),*) => { + $( + impl Pins, Ch<$CHB>), (TA, TB)> for (CHA, CHB) + where + CHA: Pins, TA>, + CHB: Pins, TB>, + { + type Channel = (Pwm, Pwm); + fn split() -> Self::Channel { + (Pwm::new(), Pwm::new()) + } + } + )* + }; + // Tuple of three pins + ($(($CHA:ident, $CHB:ident, $CHC:ident)),*) => { + $( + pins_tuples! { + PERM3: ($CHA, $CHB, $CHC), + PERM3: ($CHA, $CHC, $CHB), + PERM3: ($CHB, $CHA, $CHC), + PERM3: ($CHB, $CHC, $CHA), + PERM3: ($CHC, $CHA, $CHB), + PERM3: ($CHC, $CHB, $CHA) + } + )* + }; + // Permutate tuple of three pins + ($(PERM3: ($CHA:ident, $CHB:ident, $CHC:ident)),*) => { + $( + impl Pins, Ch<$CHB>, Ch<$CHC>), (TA, TB, TC)> for (CHA, CHB, CHC) + where + CHA: Pins, TA>, + CHB: Pins, TB>, + CHC: Pins, TC>, + { + type Channel = (Pwm, Pwm, Pwm); + fn split() -> Self::Channel { + (Pwm::new(), Pwm::new(), Pwm::new()) + } + } + )* + }; + // Tuple of four pins (permutates the last 3, leaves 4th in place) + ($(($CHD:ident, $CHA:ident, $CHB:ident, $CHC:ident)),*) => { + $( + pins_tuples! { + PERM4: ($CHD, $CHA, $CHB, $CHC), + PERM4: ($CHD, $CHA, $CHC, $CHB), + PERM4: ($CHD, $CHB, $CHA, $CHC), + PERM4: ($CHD, $CHB, $CHC, $CHA), + PERM4: ($CHD, $CHC, $CHA, $CHB), + PERM4: ($CHD, $CHC, $CHB, $CHA) + } + )* + }; + // Tuple of four pins (permutates the last 3, leaves 1st in place) + ($(PERM4: ($CHA:ident, $CHB:ident, $CHC:ident, $CHD:ident)),*) => { + $( + impl Pins, Ch<$CHB>, Ch<$CHC>, Ch<$CHD>), (TA, TB, TC, TD)> for (CHA, CHB, CHC, CHD) + where + CHA: Pins, TA>, + CHB: Pins, TB>, + CHC: Pins, TC>, + CHD: Pins, TD>, + { + type Channel = (Pwm, Pwm, Pwm, Pwm); + fn split() -> Self::Channel { + (Pwm::new(), Pwm::new(), Pwm::new(), Pwm::new()) + } + } + )* + } +} + +pins_tuples! { + (C1, C2), + (C2, C1), + (C1, C3), + (C3, C1), + (C1, C4), + (C4, C1), + (C2, C3), + (C3, C2), + (C2, C4), + (C4, C2), + (C3, C4), + (C4, C3) +} + +pins_tuples! { + (C1, C2, C3), + (C1, C2, C4), + (C1, C3, C4), + (C2, C3, C4) +} + +pins_tuples! { + (C1, C2, C3, C4), + (C2, C1, C3, C4), + (C3, C1, C2, C4), + (C4, C1, C2, C3) +} + +// Pin definitions, mark which pins can be used with which timers and channels +macro_rules! pins { + // Single channel timer + ($($TIMX:ty: OUT: [$($OUT:ty),*])+) => { + $( + $( + impl Pins<$TIMX, Ch, ComplementaryImpossible> for $OUT { + type Channel = Pwm<$TIMX, C1, ComplementaryImpossible>; + fn split() -> Self::Channel { + Pwm::new() + } + } + )* + )+ + }; + // Dual channel timer $pm + ($($TIMX:ty: + CH1($COMP1:ty): [$($( #[ $pmeta1:meta ] )* $CH1:ty),*] + CH2($COMP2:ty): [$($( #[ $pmeta2:meta ] )* $CH2:ty),*] + CH1N: [$($( #[ $pmeta3:meta ] )* $CH1N:ty),*] + CH2N: [$($( #[ $pmeta4:meta ] )* $CH2N:ty),*] + BRK: [$($( #[ $pmeta5:meta ] )* $BRK:ty),*] + BRK2: [$($( #[ $pmeta6:meta ] )* $BRK2:ty),*] + )+) => { + $( + $( + $( #[ $pmeta1 ] )* + impl Pins<$TIMX, Ch, $COMP1> for $CH1 { + type Channel = Pwm<$TIMX, C1, $COMP1>; + fn split() -> Self::Channel { + Pwm::new() + } + } + )* + $( + $( #[ $pmeta2 ] )* + impl Pins<$TIMX, Ch, $COMP2> for $CH2 { + type Channel = Pwm<$TIMX, C2, $COMP2>; + fn split() -> Self::Channel { + Pwm::new() + } + } + )* + $( + $( #[ $pmeta3 ] )* + impl NPins<$TIMX, Ch> for $CH1N {} + )* + $( + $( #[ $pmeta4 ] )* + impl NPins<$TIMX, Ch> for $CH2N {} + )* + $( + $( #[ $pmeta5 ] )* + impl FaultPins<$TIMX,> for $BRK { + const INPUT: BreakInput = BreakInput::BreakIn; + } + )* + $( + $( #[ $pmeta6 ] )* + impl FaultPins<$TIMX> for $BRK2 { + const INPUT: BreakInput = BreakInput::BreakIn2; + } + )* + )+ + }; + // Quad channel timers + ($($TIMX:ty: + CH1($COMP1:ty): [$($( #[ $pmeta1:meta ] )* $CH1:ty),*] + CH2($COMP2:ty): [$($( #[ $pmeta2:meta ] )* $CH2:ty),*] + CH3($COMP3:ty): [$($( #[ $pmeta3:meta ] )* $CH3:ty),*] + CH4($COMP4:ty): [$($( #[ $pmeta4:meta ] )* $CH4:ty),*] + CH1N: [$($( #[ $pmeta5:meta ] )* $CH1N:ty),*] + CH2N: [$($( #[ $pmeta6:meta ] )* $CH2N:ty),*] + CH3N: [$($( #[ $pmeta7:meta ] )* $CH3N:ty),*] + CH4N: [$($( #[ $pmeta8:meta ] )* $CH4N:ty),*] + BRK: [$($( #[ $pmeta9:meta ] )* $BRK:ty),*] + BRK2: [$($( #[ $pmeta10:meta ] )* $BRK2:ty),*] + )+) => { + $( + $( + $( #[ $pmeta1 ] )* + impl Pins<$TIMX, Ch, $COMP1> for $CH1 { + type Channel = Pwm<$TIMX, C1, $COMP1>; + fn split() -> Self::Channel { + Pwm::new() + } + } + )* + $( + $( #[ $pmeta2 ] )* + impl Pins<$TIMX, Ch, $COMP2> for $CH2 { + type Channel = Pwm<$TIMX, C2, $COMP2>; + fn split() -> Self::Channel { + Pwm::new() + } + } + )* + $( + $( #[ $pmeta3 ] )* + impl Pins<$TIMX, Ch, $COMP3> for $CH3 { + type Channel = Pwm<$TIMX, C3, $COMP3>; + fn split() -> Self::Channel { + Pwm::new() + } + } + )* + $( + $( #[ $pmeta4 ] )* + impl Pins<$TIMX, Ch, $COMP4> for $CH4 { + type Channel = Pwm<$TIMX, C4, $COMP4>; + fn split() -> Self::Channel { + Pwm::new() + } + } + )* + $( + $( #[ $pmeta5 ] )* + impl NPins<$TIMX, Ch> for $CH1N {} + )* + $( + $( #[ $pmeta6 ] )* + impl NPins<$TIMX, Ch> for $CH2N {} + )* + $( + $( #[ $pmeta7 ] )* + impl NPins<$TIMX, Ch> for $CH3N {} + )* + $( + $( #[ $pmeta8 ] )* + impl NPins<$TIMX, Ch> for $CH4N {} + )* + $( + $( #[ $pmeta9 ] )* + impl FaultPins<$TIMX> for $BRK { + const INPUT: BreakInput = BreakInput::BreakIn; + } + )* + $( + $( #[ $pmeta10 ] )* + impl FaultPins<$TIMX> for $BRK2 { + const INPUT: BreakInput = BreakInput::BreakIn2; + } + )* + )+ + } +} +// Single channel timers +pins! { + pac::LPTIM1: + OUT: [ + gpio::PD13>, + gpio::PG13> + ] + pac::LPTIM2: + OUT: [ + gpio::PB13> + ] + pac::LPTIM3: + OUT: [ + gpio::PA1> + ] +} +#[cfg(not(feature = "rm0455"))] +pins! { + pac::LPTIM4: + OUT: [ + gpio::PA2> + ] + pac::LPTIM5: + OUT: [ + gpio::PA3> + ] +} +// Dual channel timers +pins! { + pac::TIM12: + CH1(ComplementaryImpossible): [ + gpio::PB14>, + gpio::PH6> + ] + CH2(ComplementaryImpossible): [ + gpio::PB15>, + gpio::PH9> + ] + CH1N: [] + CH2N: [] + BRK: [] + BRK2: [] + pac::TIM13: + CH1(ComplementaryImpossible): [ + gpio::PA6>, + gpio::PF8> + ] + CH2(ComplementaryImpossible): [] + CH1N: [] + CH2N: [] + BRK: [] + BRK2: [] + pac::TIM14: + CH1(ComplementaryImpossible): [ + gpio::PA7>, + gpio::PF9> + ] + CH2(ComplementaryImpossible): [] + CH1N: [] + CH2N: [] + BRK: [] + BRK2: [] + pac::TIM15: + CH1(ComplementaryDisabled): [ + gpio::PA2>, + gpio::PE5>, + #[cfg(any(feature = "rm0455", feature = "rm0468"))] + gpio::PC12> + ] + CH2(ComplementaryImpossible): [ + gpio::PA3>, + gpio::PE6> + ] + CH1N: [ + gpio::PA1>, + gpio::PE4> + ] + CH2N: [] + BRK: [ + gpio::PA0>, + #[cfg(any(feature = "rm0455", feature = "rm0468"))] + gpio::PD2>, + gpio::PE3> + ] + BRK2: [] + pac::TIM16: + CH1(ComplementaryDisabled): [ + gpio::PB8>, + gpio::PF6> + ] + CH2(ComplementaryImpossible): [] + CH1N: [ + gpio::PB6>, + gpio::PF8> + ] + CH2N: [] + BRK: [ + gpio::PB4>, + gpio::PF10> + ] + BRK2: [] + pac::TIM17: + CH1(ComplementaryDisabled): [ + gpio::PB9>, + gpio::PF7> + ] + CH2(ComplementaryImpossible): [] + CH1N: [ + gpio::PB7>, + gpio::PF9> + ] + CH2N: [] + BRK: [ + gpio::PB5>, + gpio::PG6> + ] + BRK2: [] +} +// Quad channel timers +pins! { + pac::TIM1: + CH1(ComplementaryDisabled): [ + gpio::PA8>, + gpio::PE9>, + #[cfg(not(feature = "stm32h7b0"))] + gpio::PK1> + ] + CH2(ComplementaryDisabled): [ + gpio::PA9>, + gpio::PE11>, + #[cfg(not(feature = "stm32h7b0"))] + gpio::PJ11> + ] + CH3(ComplementaryDisabled): [ + gpio::PA10>, + gpio::PE13>, + #[cfg(not(feature = "stm32h7b0"))] + gpio::PJ9> + ] + CH4(ComplementaryImpossible): [ + gpio::PA11>, + gpio::PE14> + ] + CH1N: [ + gpio::PA7>, + gpio::PB13>, + gpio::PE8>, + #[cfg(not(feature = "stm32h7b0"))] + gpio::PK0> + ] + CH2N: [ + gpio::PB0>, + gpio::PB14>, + gpio::PE10>, + #[cfg(not(feature = "stm32h7b0"))] + gpio::PJ10> + ] + CH3N: [ + gpio::PB1>, + gpio::PB15>, + gpio::PE12>, + #[cfg(not(feature = "stm32h7b0"))] + gpio::PJ8> + ] + CH4N: [] + BRK: [ + gpio::PA6>, + gpio::PB12>, + gpio::PE15>, + #[cfg(not(feature = "stm32h7b0"))] + gpio::PK2> + ] + BRK2: [ + gpio::PE6>, + gpio::PG4> + ] + pac::TIM2: + CH1(ComplementaryImpossible): [ + gpio::PA0>, + gpio::PA5>, + gpio::PA15> + ] + CH2(ComplementaryImpossible): [ + gpio::PA1>, + gpio::PB3> + ] + CH3(ComplementaryImpossible): [ + gpio::PA2>, + gpio::PB10> + ] + CH4(ComplementaryImpossible): [ + gpio::PA3>, + gpio::PB11> + ] + CH1N: [] + CH2N: [] + CH3N: [] + CH4N: [] + BRK: [] + BRK2: [] + pac::TIM3: + CH1(ComplementaryImpossible): [ + gpio::PA6>, + gpio::PB4>, + gpio::PC6> + ] + CH2(ComplementaryImpossible): [ + gpio::PA7>, + gpio::PB5>, + gpio::PC7> + ] + CH3(ComplementaryImpossible): [ + gpio::PB0>, + gpio::PC8> + ] + CH4(ComplementaryImpossible): [ + gpio::PB1>, + gpio::PC9> + ] + CH1N: [] + CH2N: [] + CH3N: [] + CH4N: [] + BRK: [] + BRK2: [] + pac::TIM4: + CH1(ComplementaryImpossible): [ + gpio::PB6>, + gpio::PD12> + ] + CH2(ComplementaryImpossible): [ + gpio::PB7>, + gpio::PD13> + ] + CH3(ComplementaryImpossible): [ + gpio::PB8>, + gpio::PD14> + ] + CH4(ComplementaryImpossible): [ + gpio::PB9>, + gpio::PD15> + ] + CH1N: [] + CH2N: [] + CH3N: [] + CH4N: [] + BRK: [] + BRK2: [] + pac::TIM5: + CH1(ComplementaryImpossible): [ + gpio::PA0>, + gpio::PH10> + ] + CH2(ComplementaryImpossible): [ + gpio::PA1>, + gpio::PH11> + ] + CH3(ComplementaryImpossible): [ + gpio::PA2>, + gpio::PH12> + ] + CH4(ComplementaryImpossible): [ + gpio::PA3>, + #[cfg(not(feature = "rm0468"))] + gpio::PI0> + ] + CH1N: [] + CH2N: [] + CH3N: [] + CH4N: [] + BRK: [] + BRK2: [] + pac::TIM8: + CH1(ComplementaryDisabled): [ + gpio::PC6>, + #[cfg(not(feature = "rm0468"))] + gpio::PI5>, + #[cfg(not(feature = "stm32h7b0"))] + gpio::PJ8> + ] + CH2(ComplementaryDisabled): [ + gpio::PC7>, + #[cfg(not(feature = "rm0468"))] + gpio::PI6>, + #[cfg(not(any(feature = "stm32h7b0", feature = "rm0468")))] + gpio::PJ6>, + #[cfg(not(feature = "stm32h7b0"))] + gpio::PJ10> + ] + CH3(ComplementaryDisabled): [ + gpio::PC8>, + #[cfg(not(feature = "rm0468"))] + gpio::PI7>, + #[cfg(not(feature = "stm32h7b0"))] + gpio::PK0> + ] + CH4(ComplementaryImpossible): [ + gpio::PC9>, + #[cfg(not(feature = "rm0468"))] + gpio::PI2> + ] + CH1N: [ + gpio::PA5>, + gpio::PA7>, + gpio::PH13>, + #[cfg(not(feature = "stm32h7b0"))] + gpio::PJ9> + ] + CH2N: [ + gpio::PB0>, + gpio::PB14>, + gpio::PH14>, + #[cfg(not(any(feature = "stm32h7b0", feature = "rm0468")))] + gpio::PJ7>, + #[cfg(not(feature = "stm32h7b0"))] + gpio::PJ11> + ] + CH3N: [ + gpio::PB1>, + gpio::PB15>, + gpio::PH15>, + #[cfg(not(feature = "stm32h7b0"))] + gpio::PK1> + ] + CH4N: [] + BRK: [ + gpio::PA6>, + gpio::PG2>, + #[cfg(not(feature = "rm0468"))] + gpio::PI4>, + #[cfg(not(feature = "stm32h7b0"))] + gpio::PK2> + ] + BRK2: [ + gpio::PA8>, + gpio::PG3>, + #[cfg(not(feature = "rm0468"))] + gpio::PI1> + ] +} + +// Quad channel timers (RM0468) +#[cfg(feature = "rm0468")] +pins! { + pac::TIM23: + CH1(ComplementaryImpossible): [ + gpio::PG12>, + gpio::PF0>, + gpio::PF6> + ] + CH2(ComplementaryImpossible): [ + gpio::PG13>, + gpio::PF1>, + gpio::PF7> + ] + CH3(ComplementaryImpossible): [ + gpio::PG14>, + gpio::PF2>, + gpio::PF8> + ] + CH4(ComplementaryImpossible): [ + gpio::PF3>, + gpio::PF9> + ] + CH1N: [] + CH2N: [] + CH3N: [] + CH4N: [] + BRK: [] + BRK2: [] + pac::TIM24: + CH1(ComplementaryImpossible): [ + gpio::PF11> + ] + CH2(ComplementaryImpossible): [ + gpio::PF12> + ] + CH3(ComplementaryImpossible): [ + gpio::PF13> + ] + CH4(ComplementaryImpossible): [ + gpio::PF14> + ] + CH1N: [] + CH2N: [] + CH3N: [] + CH4N: [] + BRK: [] + BRK2: [] +} + +// Period and prescaler calculator for 32-bit timers +// Returns (arr, psc) +fn calculate_frequency_32bit( + base_freq: Hertz, + freq: Hertz, + alignment: Alignment, +) -> (u32, u16) { + let divisor = if let Alignment::Center = alignment { + freq.raw() * 2 + } else { + freq.raw() + }; + + // Round to the nearest period + let arr = (base_freq.raw() + (divisor >> 1)) / divisor - 1; + + (arr, 0) +} + +// Period and prescaler calculator for 16-bit timers +// Returns (arr, psc) +// Returns as (u32, u16) to be compatible but arr will always be a valid u16 +fn calculate_frequency_16bit( + base_freq: Hertz, + freq: Hertz, + alignment: Alignment, +) -> (u32, u16) { + let ideal_period = + calculate_frequency_32bit(base_freq, freq, alignment).0 + 1; + + // Division factor is (PSC + 1) + let prescale = (ideal_period - 1) / (1 << 16); + + // This will always fit in a 16-bit value because u32::MAX / (1 << 16) fits in a 16 bit + + // Round to the nearest period + let period = (ideal_period + (prescale >> 1)) / (prescale + 1) - 1; + + // It should be impossible to fail these asserts + assert!(period <= 0xFFFF); + assert!(prescale <= 0xFFFF); + + (period, prescale as u16) +} + +// Deadtime calculator helper function +// Returns (BDTR.DTG, CR1.CKD) +fn calculate_deadtime(base_freq: Hertz, deadtime: NanoSeconds) -> (u8, u8) { + // tDTS is based on tCK_INT which is before the prescaler + // It uses its own separate prescaler CR1.CKD + + // ticks = ns * GHz = ns * Hz / 1e9 + // Cortex-M7 has 32x32->64 multiply but no 64-bit divide + // Divide by 100000 then 10000 by multiplying and shifting + // This can't overflow because both values being multiplied are u32 + let deadtime_ticks = deadtime.ticks() as u64 * base_freq.raw() as u64; + // Make sure we won't overflow when multiplying; DTG is max 1008 ticks and CKD is max prescaler of 4 + // so deadtimes over 4032 ticks are impossible (4032*10^9 before dividing) + assert!(deadtime_ticks <= 4_032_000_000_000u64); + let deadtime_ticks = deadtime_ticks * 42950; + let deadtime_ticks = (deadtime_ticks >> 32) as u32; + let deadtime_ticks = deadtime_ticks as u64 * 429497; + let deadtime_ticks = (deadtime_ticks >> 32) as u32; + + // Choose CR1 CKD divider of 1, 2, or 4 to determine tDTS + let (deadtime_ticks, ckd) = match deadtime_ticks { + t if t <= 1008 => (deadtime_ticks, 1), + t if t <= 2016 => (deadtime_ticks / 2, 2), + t if t <= 4032 => (deadtime_ticks / 4, 4), + _ => { + panic!("Deadtime must be less than 4032 ticks of timer base clock.") + } + }; + + // Choose BDTR DTG bits to match deadtime_ticks + // We want the smallest value of DTG that gives a deadtime >= the requested deadtime + for dtg in 0..=255 { + let actual_deadtime: u32 = match dtg { + d if d < 128 => d, + d if d < 192 => 2 * (64 + (d & 0x3F)), + d if d < 224 => 8 * (32 + (d & 0x1F)), + _ => 16 * (32 + (dtg & 0x1F)), + }; + + if actual_deadtime >= deadtime_ticks { + return (dtg as u8, ckd); + } + } + + panic!("This should be unreachable."); +} + +// PwmExt trait +/// Allows the pwm() method to be added to the peripheral register structs from the device crate +pub trait PwmExt: Sized { + type Rec: ResetEnable; + + /// The requested frequency will be rounded to the nearest achievable frequency; the actual frequency may be higher or lower than requested. + fn pwm( + self, + _pins: PINS, + frequency: Hertz, + prec: Self::Rec, + clocks: &CoreClocks, + ) -> PINS::Channel + where + PINS: Pins; +} + +pub trait PwmAdvExt: Sized { + type Rec: ResetEnable; + + fn pwm_advanced( + self, + _pins: PINS, + prec: Self::Rec, + clocks: &CoreClocks, + ) -> PwmBuilder + where + PINS: Pins; +} + +// Implement PwmExt trait for timer +macro_rules! pwm_ext_hal { + ($TIMX:ty: $timX:ident, $Rec:ident) => { + impl PwmExt for $TIMX { + type Rec = rec::$Rec; + + fn pwm( + self, + pins: PINS, + frequency: Hertz, + prec: rec::$Rec, + clocks: &CoreClocks, + ) -> PINS::Channel + where + PINS: Pins, + { + $timX(self, pins, frequency, prec, clocks) + } + } + }; +} + +// Implement PWM configuration for timer +macro_rules! tim_hal { + ($($TIMX:ty: ($timX:ident, $Rec:ident, $typ:ty, $bits:expr + $(, DIR: $cms:ident)? + $(, BDTR: $bdtr:ident, $moe_set:ident, $af1:ident, $bkinp_setting:ident + $(, $bk2inp_setting:ident)? + )? + ),)+) => { + $( + pwm_ext_hal!($TIMX: $timX, $Rec); + + /// Configures PWM + fn $timX( + tim: $TIMX, + _pins: PINS, + freq: Hertz, + prec: rec::$Rec, + clocks: &CoreClocks, + ) -> PINS::Channel + where + PINS: Pins<$TIMX, T, U>, + { + let _ = prec.enable().reset(); // drop + + let clk = <$TIMX>::get_clk(clocks) + .expect(concat!(stringify!($TIMX), ": Input clock not running!")); + + let (period, prescale) = match $bits { + 16 => calculate_frequency_16bit(clk, freq, Alignment::Left), + _ => calculate_frequency_32bit(clk, freq, Alignment::Left), + }; + + // Write prescale + tim.psc.write(|w| { w.psc().bits(prescale as u16) }); + + // Write period + tim.arr.write(|w| { w.arr().bits(period as $typ) }); + + // BDTR: Advanced-control timers + $( + // Set CCxP = OCxREF / CCxNP = !OCxREF + // Refer to RM0433 Rev 6 - Table 324. + tim.$bdtr.write(|w| w.moe().$moe_set()); + )? + + tim.cr1.write(|w| w.cen().enabled()); + + PINS::split() + } + + impl PwmAdvExt<$typ> for $TIMX { + type Rec = rec::$Rec; + + fn pwm_advanced( + self, + _pins: PINS, + prec: Self::Rec, + clocks: &CoreClocks, + ) -> PwmBuilder + where + PINS: Pins + { + let _ = prec.enable().reset(); // drop + + let clk = <$TIMX>::get_clk(clocks) + .expect(concat!(stringify!($TIMX), ": Input clock not running!")); + + PwmBuilder { + _markers: PhantomData, + alignment: Alignment::Left, + base_freq: clk, + count: CountSettings::Explicit { period: 65535, prescaler: 0, }, + bkin_enabled: false, + bkin2_enabled: false, + fault_polarity: Polarity::ActiveLow, + deadtime: 0.nanos(), + } + } + } + + impl + PwmBuilder<$TIMX, PINS, CHANNEL, FAULT, COMP, $typ> + where + PINS: Pins<$TIMX, CHANNEL, COMP>, + { + pub fn finalize(self) -> (PwmControl<$TIMX, FAULT>, PINS::Channel) { + let tim = unsafe { &*<$TIMX>::ptr() }; + + let (period, prescaler) = match self.count { + CountSettings::Explicit { period, prescaler } => (period as u32, prescaler), + CountSettings::Frequency( freq ) => { + match $bits { + 16 => calculate_frequency_16bit(self.base_freq, freq, self.alignment), + _ => calculate_frequency_32bit(self.base_freq, freq, self.alignment), + } + }, + }; + + // Write prescaler + tim.psc.write(|w| w.psc().bits(prescaler as u16)); + + // Write period + tim.arr.write(|w| w.arr().bits(period as $typ)); + + $( + let (dtg, ckd) = calculate_deadtime(self.base_freq, self.deadtime); + + match ckd { + 1 => tim.cr1.modify(|_, w| w.ckd().div1()), + 2 => tim.cr1.modify(|_, w| w.ckd().div2()), + 4 => tim.cr1.modify(|_, w| w.ckd().div4()), + _ => panic!("Should be unreachable, invalid deadtime prescaler"), + } + + let bkp = match self.fault_polarity { + Polarity::ActiveLow => false, + Polarity::ActiveHigh => true, + }; + + if self.bkin_enabled { + // BDTR: + // BKF = 1 -> break pin filtering of 2 cycles of CK_INT (peripheral source clock) + // AOE = 0 -> after a fault, master output enable MOE can only be set by software, not automatically + // BKE = 1 -> break is enabled + // BKP = 0 for active low, 1 for active high + // Safety: bkf is set to a constant value (1) that is a valid value for the field per the reference manual + unsafe { tim.$bdtr.write(|w| w.dtg().bits(dtg).bkf().bits(1).aoe().clear_bit().bke().set_bit().bkp().bit(bkp).moe().$moe_set()); } + + // AF1: + // BKINE = 1 -> break input enabled + // BKINP should make input active high (BDTR BKP will set polarity), bit value varies timer to timer + tim.$af1.write(|w| w.bkine().set_bit().bkinp().$bkinp_setting()); + } + $( + // Not all timers that have break inputs have break2 inputs + else if self.bkin2_enabled { + // BDTR: + // BK2F = 1 -> break pin filtering of 2 cycles of CK_INT (peripheral source clock) + // AOE = 0 -> after a fault, master output enable MOE can only be set by software, not automatically + // BK2E = 1 -> break is enabled + // BK2P = 0 for active low, 1 for active high + // Safety: bkf is set to a constant value (1) that is a valid value for the field per the reference manual + unsafe { tim.$bdtr.write(|w| w.dtg().bits(dtg).bk2f().bits(1).aoe().clear_bit().bk2e().set_bit().bk2p().bit(bkp).moe().$moe_set()); } + + // AF1: + // BKINE = 1 -> break input enabled + // BKINP should make input active high (BDTR BKP will set polarity), bit value varies timer to timer + tim.af2.write(|w| w.bk2ine().set_bit().bk2inp().$bk2inp_setting()); + } + )? + else { + // Safety: the DTG field of BDTR allows any 8-bit deadtime value and the dtg variable is u8 + unsafe { + tim.$bdtr.write(|w| w.dtg().bits(dtg).aoe().clear_bit().moe().$moe_set()); + } + } + + // BDTR: Advanced-control timers + // Set CCxP = OCxREF / CCxNP = !OCxREF + // Refer to RM0433 Rev 6 - Table 324. + tim.$bdtr.modify(|_, w| w.moe().$moe_set()); + )? + + + $( + match self.alignment { + Alignment::Left => { }, + Alignment::Right => { tim.cr1.modify(|_, w| w.dir().down()); }, + Alignment::Center => { tim.cr1.modify(|_, w| w.$cms().center_aligned3()); } + } + )? + + tim.cr1.modify(|_, w| w.cen().enabled()); + + (PwmControl::new(), PINS::split()) + } + + /// Set the PWM frequency; will overwrite the previous prescaler + /// and period The requested frequency will be rounded to the + /// nearest achievable frequency; the actual frequency may be + /// higher or lower than requested. + #[must_use] + pub fn frequency(mut self, freq: Hertz) -> Self { + self.count = CountSettings::Frequency( freq ); + + self + } + + /// Set the prescaler; PWM count runs at base_frequency/(prescaler+1) + #[must_use] + pub fn prescaler(mut self, prescaler: u16) -> Self { + let period = match self.count { + CountSettings::Frequency(_) => 65535, + CountSettings::Explicit { period, prescaler: _ } => period, + }; + + self.count = CountSettings::Explicit { period, prescaler }; + + self + } + + /// Set the period; PWM count runs from 0 to period, repeating every (period+1) counts + #[must_use] + pub fn period(mut self, period: $typ) -> Self { + let prescaler = match self.count { + CountSettings::Frequency(_) => 0, + CountSettings::Explicit { period: _, prescaler } => prescaler, + }; + + self.count = CountSettings::Explicit { period, prescaler }; + + self + } + + + // Timers with complementary and deadtime and faults + $( + /// Set the deadtime for complementary PWM channels of this timer + #[must_use] + pub fn with_deadtime>(mut self, deadtime: T) -> Self { + // $bdtr is an Ident that only exists for timers with deadtime, so we can use it as a variable name to + // only implement this method for timers that support deadtime. + let $bdtr = deadtime.into(); + + self.deadtime = $bdtr; + + self + } + )? + + #[must_use] + pub fn left_aligned(mut self) -> Self { + self.alignment = Alignment::Left; + + self + } + + // Timers with advanced counting options, including center aligned and right aligned PWM + $( + #[must_use] + pub fn center_aligned(mut self) -> Self { + // $cms is an Ident that only exists for timers with center/right aligned PWM, so we can use it as a variable name to + // only implement this method for timers that support center/right aligned PWM. + let $cms = Alignment::Center; + + self.alignment = $cms; + + self + } + + #[must_use] + pub fn right_aligned(mut self) -> Self { + self.alignment = Alignment::Right; + + self + } + )? + } + + // Timers with break/fault, dead time, and complimentary capabilities + $( + impl PwmBuilder<$TIMX, PINS, CHANNEL, FaultDisabled, COMP, $typ> { + /// Configure a break pin that will disable PWM when activated (active level based on polarity argument) + /// Note: not all timers have fault inputs; `FaultPins` is only implemented for valid pins/timers. + pub fn with_break_pin>(self, _pin: P, polarity: Polarity) -> PwmBuilder<$TIMX, PINS, CHANNEL, FaultEnabled, COMP, $typ> { + PwmBuilder { + _markers: PhantomData, + alignment: self.alignment, + base_freq: self.base_freq, + count: self.count, + bkin_enabled: self.bkin_enabled || P::INPUT == BreakInput::BreakIn, + bkin2_enabled: self.bkin2_enabled || P::INPUT == BreakInput::BreakIn2, + fault_polarity: polarity, + deadtime: self.deadtime, + } + } + } + + impl FaultMonitor for PwmControl<$TIMX, FaultEnabled> { + fn is_fault_active(&self) -> bool { + let tim = unsafe { &*<$TIMX>::ptr() }; + + !tim.$bdtr.read().moe().bit() + } + + fn clear_fault(&mut self) { + let tim = unsafe { &*<$TIMX>::ptr() }; + + tim.$bdtr.modify(|_, w| w.moe().set_bit()); + } + + fn set_fault(&mut self) { + let tim = unsafe { &*<$TIMX>::ptr() }; + + tim.$bdtr.modify(|_, w| w.moe().clear_bit()); + } + } + )? + )+ + } +} + +tim_hal! { + pac::TIM1: (tim1, Tim1, u16, 16, DIR: cms, BDTR: bdtr, enabled, af1, clear_bit, clear_bit), + pac::TIM2: (tim2, Tim2, u32, 32, DIR: cms), + pac::TIM3: (tim3, Tim3, u16, 16, DIR: cms), + pac::TIM4: (tim4, Tim4, u16, 16, DIR: cms), + pac::TIM5: (tim5, Tim5, u32, 32, DIR: cms), + pac::TIM8: (tim8, Tim8, u16, 16, DIR: cms, BDTR: bdtr, enabled, af1, clear_bit, clear_bit), +} +#[cfg(feature = "rm0468")] +tim_hal! { + pac::TIM23: (tim23, Tim23, u32, 32, DIR: cms), + pac::TIM24: (tim24, Tim24, u32, 32, DIR: cms), +} +tim_hal! { + pac::TIM12: (tim12, Tim12, u16, 16), + pac::TIM13: (tim13, Tim13, u16, 16), + pac::TIM14: (tim14, Tim14, u16, 16), +} +tim_hal! { + pac::TIM15: (tim15, Tim15, u16, 16, BDTR: bdtr, set_bit, af1, set_bit), + pac::TIM16: (tim16, Tim16, u16, 16, BDTR: bdtr, set_bit, tim16_af1, set_bit), + pac::TIM17: (tim17, Tim17, u16, 16, BDTR: bdtr, set_bit, tim17_af1, set_bit), +} + +pub trait PwmPinEnable { + fn ccer_enable(&mut self); + fn ccer_disable(&mut self); +} + +// Implement PwmPin for timer channels +macro_rules! tim_pin_hal { + // Standard pins (no complementary functionality) + ($TIMX:ty, $typ:ty: $( + ($CH:ident, $ccmrx_output:ident, $ocxpe:ident, $ocxm:ident),)+ + ) => { + $( + impl embedded_hal_02::PwmPin for Pwm<$TIMX, $CH, COMP> + where Pwm<$TIMX, $CH, COMP>: PwmPinEnable { + type Duty = $typ; + + // You may not access self in the following methods! + // See unsafe above + + fn disable(&mut self) { + self.ccer_disable(); + } + + fn enable(&mut self) { + let tim = unsafe { &*<$TIMX>::ptr() }; + + tim.$ccmrx_output().modify(|_, w| + w.$ocxpe() + .enabled() // Enable preload + .$ocxm() + .pwm_mode1() // PWM Mode + ); + + self.ccer_enable(); + } + + fn get_duty(&self) -> Self::Duty { + let tim = unsafe { &*<$TIMX>::ptr() }; + + tim.ccr[$CH as usize].read().ccr().bits() + } + + fn get_max_duty(&self) -> Self::Duty { + let tim = unsafe { &*<$TIMX>::ptr() }; + + let arr = tim.arr.read().arr().bits(); + + // One PWM cycle is ARR+1 counts long + // Valid PWM duty cycles are 0 to ARR+1 + // However, if ARR is 65535 on a 16-bit timer, we can't add 1 + // In that case, 100% duty cycle is not possible, only 65535/65536 + if arr == Self::Duty::MAX { + arr + } + else { + arr + 1 + } + } + + fn set_duty(&mut self, duty: Self::Duty) { + let tim = unsafe { &*<$TIMX>::ptr() }; + + tim.ccr[$CH as usize].write(|w| w.ccr().bits(duty)); + } + } + + )+ + + // Enable implementation for ComplementaryImpossible + impl PwmPinEnable for Pwm<$TIMX, C, ComplementaryImpossible> { + fn ccer_enable(&mut self) { + let tim = unsafe { &*<$TIMX>::ptr() }; + + tim.ccer.modify(|r, w| unsafe { w.bits(r.bits() | Ch::::EN) }); + } + fn ccer_disable(&mut self) { + let tim = unsafe { &*<$TIMX>::ptr() }; + + tim.ccer.modify(|r, w| unsafe { w.bits(r.bits() & !Ch::::EN) }); + } + } + + + impl Pwm<$TIMX, C, COMP> { + pub fn set_polarity(&mut self, pol: Polarity) { + let tim = unsafe { &*<$TIMX>::ptr() }; + + tim.ccer.modify(|r, w| unsafe { w.bits(match pol { + Polarity::ActiveLow => r.bits() | Ch::::POL, + Polarity::ActiveHigh => r.bits() & !Ch::::POL, + })}); + } + } + + impl Pwm<$TIMX, C, COMP> { + pub fn into_active_low(mut self) -> Pwm<$TIMX, C, COMP> { + self.set_polarity(Polarity::ActiveLow); + self + } + } + + impl Pwm<$TIMX, C, COMP> { + pub fn into_active_high(mut self) -> Pwm<$TIMX, C, COMP> { + self.set_polarity(Polarity::ActiveHigh); + self + } + } + + // Complementary channels + + // Enable implementation for ComplementaryDisabled + impl PwmPinEnable for Pwm<$TIMX, C, ComplementaryDisabled> { + fn ccer_enable(&mut self) { + let tim = unsafe { &*<$TIMX>::ptr() }; + + tim.ccer.modify(|r, w| unsafe { w.bits(r.bits() | Ch::::EN) }); + } + fn ccer_disable(&mut self) { + let tim = unsafe { &*<$TIMX>::ptr() }; + + tim.ccer.modify(|r, w| unsafe { w.bits(r.bits() & !Ch::::EN) }); + } + } + + // Enable implementation for ComplementaryEnabled + impl PwmPinEnable for Pwm<$TIMX, C, ComplementaryEnabled> { + fn ccer_enable(&mut self) { + let tim = unsafe { &*<$TIMX>::ptr() }; + + tim.ccer.modify(|r, w| unsafe { w.bits(r.bits() | Ch::::EN | Ch::::N_EN) }); + } + fn ccer_disable(&mut self) { + let tim = unsafe { &*<$TIMX>::ptr() }; + + tim.ccer.modify(|r, w| unsafe { w.bits(r.bits() & !Ch::::EN & !Ch::::N_EN) }); + } + } + + impl Pwm<$TIMX, C, ComplementaryDisabled> { + pub fn into_complementary(self, _npin: NPIN) -> Pwm<$TIMX, C, ComplementaryEnabled> + where NPIN: NPins<$TIMX, Ch> { + // Make sure we aren't switching to complementary after we enable the channel + let tim = unsafe { &*<$TIMX>::ptr() }; + + let enabled = (tim.ccer.read().bits() & Ch::::EN) != 0; + + assert!(!enabled); + + Pwm::new() + } + } + + impl Pwm<$TIMX, C, ComplementaryEnabled> { + pub fn set_comp_polarity(&mut self, pol: Polarity) { + let tim = unsafe { &*<$TIMX>::ptr() }; + + tim.ccer.modify(|r, w| unsafe { w.bits(match pol { + Polarity::ActiveLow => r.bits() | Ch::::N_POL, + Polarity::ActiveHigh => r.bits() & !Ch::::N_POL, + })}); + } + } + + impl Pwm<$TIMX, C, ComplementaryEnabled> { + pub fn into_comp_active_low(mut self) -> Pwm<$TIMX, C, ComplementaryEnabled> { + self.set_comp_polarity(Polarity::ActiveLow); + self + } + } + + impl Pwm<$TIMX, C, ComplementaryEnabled> { + pub fn into_comp_active_high(mut self) -> Pwm<$TIMX, C, ComplementaryEnabled> { + self.set_comp_polarity(Polarity::ActiveHigh); + self + } + } + }; +} + +// Dual channel timers +tim_pin_hal! { + pac::TIM12, u16: + (C1, ccmr1_output, oc1pe, oc1m), + (C2, ccmr1_output, oc2pe, oc2m), +} +tim_pin_hal! { + pac::TIM15, u16: + (C1, ccmr1_output, oc1pe, oc1m), + (C2, ccmr1_output, oc2pe, oc2m), +} + +// Single channel timers +tim_pin_hal! { + pac::TIM13, u16: (C1, ccmr1_output, oc1pe, oc1m), +} +tim_pin_hal! { + pac::TIM14, u16: (C1, ccmr1_output, oc1pe, oc1m), +} +tim_pin_hal! { + pac::TIM16, u16: (C1, ccmr1_output, oc1pe, oc1m), +} +tim_pin_hal! { + pac::TIM17, u16: (C1, ccmr1_output, oc1pe, oc1m), +} + +// Quad channel timers +tim_pin_hal! { + pac::TIM1, u16: + (C1, ccmr1_output, oc1pe, oc1m), + (C2, ccmr1_output, oc2pe, oc2m), + (C3, ccmr2_output, oc3pe, oc3m), + (C4, ccmr2_output, oc4pe, oc4m), +} +tim_pin_hal! { + pac::TIM2, u32: + (C1, ccmr1_output, oc1pe, oc1m), + (C2, ccmr1_output, oc2pe, oc2m), + (C3, ccmr2_output, oc3pe, oc3m), + (C4, ccmr2_output, oc4pe, oc4m), +} +tim_pin_hal! { + pac::TIM3, u16: + (C1, ccmr1_output, oc1pe, oc1m), + (C2, ccmr1_output, oc2pe, oc2m), + (C3, ccmr2_output, oc3pe, oc3m), + (C4, ccmr2_output, oc4pe, oc4m), +} +tim_pin_hal! { + pac::TIM4, u16: + (C1, ccmr1_output, oc1pe, oc1m), + (C2, ccmr1_output, oc2pe, oc2m), + (C3, ccmr2_output, oc3pe, oc3m), + (C4, ccmr2_output, oc4pe, oc4m), +} +tim_pin_hal! { + pac::TIM5, u32: + (C1, ccmr1_output, oc1pe, oc1m), + (C2, ccmr1_output, oc2pe, oc2m), + (C3, ccmr2_output, oc3pe, oc3m), + (C4, ccmr2_output, oc4pe, oc4m), +} +tim_pin_hal! { + pac::TIM8, u16: + (C1, ccmr1_output, oc1pe, oc1m), + (C2, ccmr1_output, oc2pe, oc2m), + (C3, ccmr2_output, oc3pe, oc3m), + (C4, ccmr2_output, oc4pe, oc4m), +} +#[cfg(feature = "rm0468")] +tim_pin_hal! { + pac::TIM23, u32: + (C1, ccmr1_output, oc1pe, oc1m), + (C2, ccmr1_output, oc2pe, oc2m), + (C3, ccmr2_output, oc3pe, oc3m), + (C4, ccmr2_output, oc4pe, oc4m), +} +#[cfg(feature = "rm0468")] +tim_pin_hal! { + pac::TIM24, u32: + (C1, ccmr1_output, oc1pe, oc1m), + (C2, ccmr1_output, oc2pe, oc2m), + (C3, ccmr2_output, oc3pe, oc3m), + (C4, ccmr2_output, oc4pe, oc4m), +} + +// Low-power timers +macro_rules! lptim_hal { + ($($TIMX:ty: ($timX:ident, $Rec:ident),)+) => { + $( + pwm_ext_hal!($TIMX: $timX, $Rec); + + /// Configures PWM signal on the LPTIM OUT pin. + fn $timX( + tim: $TIMX, + _pins: PINS, + freq: Hertz, + prec: rec::$Rec, + clocks: &CoreClocks, + ) -> PINS::Channel + where + PINS: Pins<$TIMX, T, U>, + { + let _ = prec.enable().reset(); // drop + + let clk = <$TIMX>::get_clk(clocks) + .expect(concat!(stringify!($TIMX), ": Input clock not running!")); + let reload = clk / freq; + assert!(reload < 128 * (1 << 16)); + + // Calculate prescaler + use pac::$timX::cfgr::PRESC_A; + let (prescale, prescale_div) = match reload / (1 << 16) { + 0 => (PRESC_A::Div1, 1), + 1 => (PRESC_A::Div2, 2), + 2..=3 => (PRESC_A::Div4, 4), + 4..=7 => (PRESC_A::Div8, 8), + 8..=15 => (PRESC_A::Div16, 16), + 16..=31 => (PRESC_A::Div32, 32), + 32..=63 => (PRESC_A::Div64, 64), + _ => (PRESC_A::Div128, 128), + }; + + // Calcuate reload + let arr = reload / prescale_div; + assert!(arr <= 0xFFFF); + assert!(arr > 0); + + // CFGR + tim.cfgr.modify(|_, w| w.presc().variant(prescale)); + + // Enable + tim.cr.modify(|_, w| w.enable().enabled()); + + // Write ARR: LPTIM must be enabled + tim.arr.write(|w| w.arr().bits(arr as u16)); + while !tim.isr.read().arrok().is_set() {} + tim.icr.write(|w| w.arrokcf().clear()); + + // PWM output is disabled by default, disable the + // entire timer + tim.cr.modify(|_, w| w.enable().disabled()); + + PINS::split() + } + + impl embedded_hal_02::PwmPin for Pwm<$TIMX, C1, ComplementaryImpossible> { + type Duty = u16; + + // You may not access self in the following methods! + // See unsafe above + + fn disable(&mut self) { + let tim = unsafe { &*<$TIMX>::ptr() }; + + // LPTIM only has one output, so we disable the + // entire timer + tim.cr.modify(|_, w| w.enable().disabled()); + } + + fn enable(&mut self) { + let tim = unsafe { &*<$TIMX>::ptr() }; + + tim.cr.modify(|_, w| w.enable().enabled()); + tim.cr.modify(|_, w| w.cntstrt().start()); + } + + fn get_duty(&self) -> u16 { + let tim = unsafe { &*<$TIMX>::ptr() }; + + tim.cmp.read().cmp().bits() + } + + fn get_max_duty(&self) -> u16 { + let tim = unsafe { &*<$TIMX>::ptr() }; + + tim.arr.read().arr().bits() + } + + fn set_duty(&mut self, duty: u16) { + let tim = unsafe { &*<$TIMX>::ptr() }; + + tim.cmp.write(|w| w.cmp().bits(duty)); + while !tim.isr.read().cmpok().is_set() {} + tim.icr.write(|w| w.cmpokcf().clear()); + } + } + )+ + } +} + +lptim_hal! { + pac::LPTIM1: (lptim1, Lptim1), + pac::LPTIM2: (lptim2, Lptim2), + pac::LPTIM3: (lptim3, Lptim3), +} +#[cfg(not(feature = "rm0455"))] +lptim_hal! { + pac::LPTIM4: (lptim4, Lptim4), + pac::LPTIM5: (lptim5, Lptim5), +} \ No newline at end of file From 76b4801f557113387e66db3f33f4567238eee22c Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Tue, 2 Sep 2025 00:16:58 +0200 Subject: [PATCH 05/12] pwm compiles --- src/lib.rs | 1 + src/prelude.rs | 2 +- src/pwm/h5.rs | 1 + src/{pwm.rs => pwm/mod.rs} | 565 ++++++------------------------------- src/timer.rs | 8 +- 5 files changed, 90 insertions(+), 487 deletions(-) create mode 100644 src/pwm/h5.rs rename src/{pwm.rs => pwm/mod.rs} (75%) diff --git a/src/lib.rs b/src/lib.rs index de063a5..f732620 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -87,6 +87,7 @@ pub mod usb; #[cfg(feature = "device-selected")] pub mod gpdma; +pub mod pwm; #[cfg(feature = "device-selected")] pub mod timer; diff --git a/src/prelude.rs b/src/prelude.rs index 15cf87d..339b1ef 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -10,8 +10,8 @@ pub use crate::icache::ICacheExt as _stm32h5xx_hal_icache_ICacheExt; pub use crate::pwr::PwrExt as _stm32h5xx_hal_pwr_PwrExt; pub use crate::rcc::RccExt as _stm32h5xx_hal_rcc_RccExt; pub use crate::spi::SpiExt as _stm32h5xx_hal_spi_SpiExt; -pub use crate::usb::UsbExt as _stm32h5xx_hal_usb_UsbExt; pub use crate::timer::TimerExt as _stm32h5xx_hal_timer_TimerExt; +pub use crate::usb::UsbExt as _stm32h5xx_hal_usb_UsbExt; pub use crate::time::U32Ext as _; pub use fugit::{ExtU32 as _, RateExtU32 as _}; diff --git a/src/pwm/h5.rs b/src/pwm/h5.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/pwm/h5.rs @@ -0,0 +1 @@ + diff --git a/src/pwm.rs b/src/pwm/mod.rs similarity index 75% rename from src/pwm.rs rename to src/pwm/mod.rs index e08d8a8..b3caa23 100644 --- a/src/pwm.rs +++ b/src/pwm/mod.rs @@ -1,9 +1,5 @@ //! Pulse Width Modulation (PWM) //! -//! PWM output is avaliable for the advanced control timers (`TIM1`, `TIM8`), -//! the general purpose timers (`TIM[2-5]`, `TIM[12-17]`) and the Low-power -//! timers (`LPTIM[1-5]`). -//! //! Timers support up to 4 simultaneous PWM output channels //! //! ## Examples @@ -170,6 +166,8 @@ //! //! Additionally, the GPIO will always be high-impedance during power-up or in reset, so pull-ups or pull-downs to ensure safe state are always a good idea. +mod h5; + use core::marker::PhantomData; use crate::pac; @@ -179,8 +177,6 @@ use crate::time::{Hertz, NanoSeconds}; use crate::timer::GetClk; use fugit::ExtU32; -use crate::gpio::{self, Alternate}; - // This trait marks that a GPIO pin can be used with a specific timer channel // TIM is the timer being used // CHANNEL is a marker struct for the channel (or multi channels for tuples) @@ -573,397 +569,6 @@ macro_rules! pins { )+ } } -// Single channel timers -pins! { - pac::LPTIM1: - OUT: [ - gpio::PD13>, - gpio::PG13> - ] - pac::LPTIM2: - OUT: [ - gpio::PB13> - ] - pac::LPTIM3: - OUT: [ - gpio::PA1> - ] -} -#[cfg(not(feature = "rm0455"))] -pins! { - pac::LPTIM4: - OUT: [ - gpio::PA2> - ] - pac::LPTIM5: - OUT: [ - gpio::PA3> - ] -} -// Dual channel timers -pins! { - pac::TIM12: - CH1(ComplementaryImpossible): [ - gpio::PB14>, - gpio::PH6> - ] - CH2(ComplementaryImpossible): [ - gpio::PB15>, - gpio::PH9> - ] - CH1N: [] - CH2N: [] - BRK: [] - BRK2: [] - pac::TIM13: - CH1(ComplementaryImpossible): [ - gpio::PA6>, - gpio::PF8> - ] - CH2(ComplementaryImpossible): [] - CH1N: [] - CH2N: [] - BRK: [] - BRK2: [] - pac::TIM14: - CH1(ComplementaryImpossible): [ - gpio::PA7>, - gpio::PF9> - ] - CH2(ComplementaryImpossible): [] - CH1N: [] - CH2N: [] - BRK: [] - BRK2: [] - pac::TIM15: - CH1(ComplementaryDisabled): [ - gpio::PA2>, - gpio::PE5>, - #[cfg(any(feature = "rm0455", feature = "rm0468"))] - gpio::PC12> - ] - CH2(ComplementaryImpossible): [ - gpio::PA3>, - gpio::PE6> - ] - CH1N: [ - gpio::PA1>, - gpio::PE4> - ] - CH2N: [] - BRK: [ - gpio::PA0>, - #[cfg(any(feature = "rm0455", feature = "rm0468"))] - gpio::PD2>, - gpio::PE3> - ] - BRK2: [] - pac::TIM16: - CH1(ComplementaryDisabled): [ - gpio::PB8>, - gpio::PF6> - ] - CH2(ComplementaryImpossible): [] - CH1N: [ - gpio::PB6>, - gpio::PF8> - ] - CH2N: [] - BRK: [ - gpio::PB4>, - gpio::PF10> - ] - BRK2: [] - pac::TIM17: - CH1(ComplementaryDisabled): [ - gpio::PB9>, - gpio::PF7> - ] - CH2(ComplementaryImpossible): [] - CH1N: [ - gpio::PB7>, - gpio::PF9> - ] - CH2N: [] - BRK: [ - gpio::PB5>, - gpio::PG6> - ] - BRK2: [] -} -// Quad channel timers -pins! { - pac::TIM1: - CH1(ComplementaryDisabled): [ - gpio::PA8>, - gpio::PE9>, - #[cfg(not(feature = "stm32h7b0"))] - gpio::PK1> - ] - CH2(ComplementaryDisabled): [ - gpio::PA9>, - gpio::PE11>, - #[cfg(not(feature = "stm32h7b0"))] - gpio::PJ11> - ] - CH3(ComplementaryDisabled): [ - gpio::PA10>, - gpio::PE13>, - #[cfg(not(feature = "stm32h7b0"))] - gpio::PJ9> - ] - CH4(ComplementaryImpossible): [ - gpio::PA11>, - gpio::PE14> - ] - CH1N: [ - gpio::PA7>, - gpio::PB13>, - gpio::PE8>, - #[cfg(not(feature = "stm32h7b0"))] - gpio::PK0> - ] - CH2N: [ - gpio::PB0>, - gpio::PB14>, - gpio::PE10>, - #[cfg(not(feature = "stm32h7b0"))] - gpio::PJ10> - ] - CH3N: [ - gpio::PB1>, - gpio::PB15>, - gpio::PE12>, - #[cfg(not(feature = "stm32h7b0"))] - gpio::PJ8> - ] - CH4N: [] - BRK: [ - gpio::PA6>, - gpio::PB12>, - gpio::PE15>, - #[cfg(not(feature = "stm32h7b0"))] - gpio::PK2> - ] - BRK2: [ - gpio::PE6>, - gpio::PG4> - ] - pac::TIM2: - CH1(ComplementaryImpossible): [ - gpio::PA0>, - gpio::PA5>, - gpio::PA15> - ] - CH2(ComplementaryImpossible): [ - gpio::PA1>, - gpio::PB3> - ] - CH3(ComplementaryImpossible): [ - gpio::PA2>, - gpio::PB10> - ] - CH4(ComplementaryImpossible): [ - gpio::PA3>, - gpio::PB11> - ] - CH1N: [] - CH2N: [] - CH3N: [] - CH4N: [] - BRK: [] - BRK2: [] - pac::TIM3: - CH1(ComplementaryImpossible): [ - gpio::PA6>, - gpio::PB4>, - gpio::PC6> - ] - CH2(ComplementaryImpossible): [ - gpio::PA7>, - gpio::PB5>, - gpio::PC7> - ] - CH3(ComplementaryImpossible): [ - gpio::PB0>, - gpio::PC8> - ] - CH4(ComplementaryImpossible): [ - gpio::PB1>, - gpio::PC9> - ] - CH1N: [] - CH2N: [] - CH3N: [] - CH4N: [] - BRK: [] - BRK2: [] - pac::TIM4: - CH1(ComplementaryImpossible): [ - gpio::PB6>, - gpio::PD12> - ] - CH2(ComplementaryImpossible): [ - gpio::PB7>, - gpio::PD13> - ] - CH3(ComplementaryImpossible): [ - gpio::PB8>, - gpio::PD14> - ] - CH4(ComplementaryImpossible): [ - gpio::PB9>, - gpio::PD15> - ] - CH1N: [] - CH2N: [] - CH3N: [] - CH4N: [] - BRK: [] - BRK2: [] - pac::TIM5: - CH1(ComplementaryImpossible): [ - gpio::PA0>, - gpio::PH10> - ] - CH2(ComplementaryImpossible): [ - gpio::PA1>, - gpio::PH11> - ] - CH3(ComplementaryImpossible): [ - gpio::PA2>, - gpio::PH12> - ] - CH4(ComplementaryImpossible): [ - gpio::PA3>, - #[cfg(not(feature = "rm0468"))] - gpio::PI0> - ] - CH1N: [] - CH2N: [] - CH3N: [] - CH4N: [] - BRK: [] - BRK2: [] - pac::TIM8: - CH1(ComplementaryDisabled): [ - gpio::PC6>, - #[cfg(not(feature = "rm0468"))] - gpio::PI5>, - #[cfg(not(feature = "stm32h7b0"))] - gpio::PJ8> - ] - CH2(ComplementaryDisabled): [ - gpio::PC7>, - #[cfg(not(feature = "rm0468"))] - gpio::PI6>, - #[cfg(not(any(feature = "stm32h7b0", feature = "rm0468")))] - gpio::PJ6>, - #[cfg(not(feature = "stm32h7b0"))] - gpio::PJ10> - ] - CH3(ComplementaryDisabled): [ - gpio::PC8>, - #[cfg(not(feature = "rm0468"))] - gpio::PI7>, - #[cfg(not(feature = "stm32h7b0"))] - gpio::PK0> - ] - CH4(ComplementaryImpossible): [ - gpio::PC9>, - #[cfg(not(feature = "rm0468"))] - gpio::PI2> - ] - CH1N: [ - gpio::PA5>, - gpio::PA7>, - gpio::PH13>, - #[cfg(not(feature = "stm32h7b0"))] - gpio::PJ9> - ] - CH2N: [ - gpio::PB0>, - gpio::PB14>, - gpio::PH14>, - #[cfg(not(any(feature = "stm32h7b0", feature = "rm0468")))] - gpio::PJ7>, - #[cfg(not(feature = "stm32h7b0"))] - gpio::PJ11> - ] - CH3N: [ - gpio::PB1>, - gpio::PB15>, - gpio::PH15>, - #[cfg(not(feature = "stm32h7b0"))] - gpio::PK1> - ] - CH4N: [] - BRK: [ - gpio::PA6>, - gpio::PG2>, - #[cfg(not(feature = "rm0468"))] - gpio::PI4>, - #[cfg(not(feature = "stm32h7b0"))] - gpio::PK2> - ] - BRK2: [ - gpio::PA8>, - gpio::PG3>, - #[cfg(not(feature = "rm0468"))] - gpio::PI1> - ] -} - -// Quad channel timers (RM0468) -#[cfg(feature = "rm0468")] -pins! { - pac::TIM23: - CH1(ComplementaryImpossible): [ - gpio::PG12>, - gpio::PF0>, - gpio::PF6> - ] - CH2(ComplementaryImpossible): [ - gpio::PG13>, - gpio::PF1>, - gpio::PF7> - ] - CH3(ComplementaryImpossible): [ - gpio::PG14>, - gpio::PF2>, - gpio::PF8> - ] - CH4(ComplementaryImpossible): [ - gpio::PF3>, - gpio::PF9> - ] - CH1N: [] - CH2N: [] - CH3N: [] - CH4N: [] - BRK: [] - BRK2: [] - pac::TIM24: - CH1(ComplementaryImpossible): [ - gpio::PF11> - ] - CH2(ComplementaryImpossible): [ - gpio::PF12> - ] - CH3(ComplementaryImpossible): [ - gpio::PF13> - ] - CH4(ComplementaryImpossible): [ - gpio::PF14> - ] - CH1N: [] - CH2N: [] - CH3N: [] - CH4N: [] - BRK: [] - BRK2: [] -} - // Period and prescaler calculator for 32-bit timers // Returns (arr, psc) fn calculate_frequency_32bit( @@ -1141,19 +746,19 @@ macro_rules! tim_hal { }; // Write prescale - tim.psc.write(|w| { w.psc().bits(prescale as u16) }); + tim.psc().write(|w| { w.psc().set(prescale as u16) }); // Write period - tim.arr.write(|w| { w.arr().bits(period as $typ) }); + tim.arr().write(|w| { w.arr().set(period as u32) }); // TODO Some timers are supposed to have 16 bit register fields here // BDTR: Advanced-control timers $( // Set CCxP = OCxREF / CCxNP = !OCxREF // Refer to RM0433 Rev 6 - Table 324. - tim.$bdtr.write(|w| w.moe().$moe_set()); + tim.$bdtr().write(|w| w.moe().$moe_set()); )? - tim.cr1.write(|w| w.cen().enabled()); + tim.cr1().write(|w| w.cen().enabled()); PINS::split() } @@ -1207,20 +812,20 @@ macro_rules! tim_hal { }; // Write prescaler - tim.psc.write(|w| w.psc().bits(prescaler as u16)); + tim.psc().write(|w| w.psc().set(prescaler as u16)); // Write period - tim.arr.write(|w| w.arr().bits(period as $typ)); + tim.arr().write(|w| w.arr().set(period as u32)); // TODO: Supposed to be 16 bit for some timers $( let (dtg, ckd) = calculate_deadtime(self.base_freq, self.deadtime); match ckd { - 1 => tim.cr1.modify(|_, w| w.ckd().div1()), - 2 => tim.cr1.modify(|_, w| w.ckd().div2()), - 4 => tim.cr1.modify(|_, w| w.ckd().div4()), + 1 => tim.cr1().modify(|_, w| w.ckd().div1()), + 2 => tim.cr1().modify(|_, w| w.ckd().div2()), + 4 => tim.cr1().modify(|_, w| w.ckd().div4()), _ => panic!("Should be unreachable, invalid deadtime prescaler"), - } + }; let bkp = match self.fault_polarity { Polarity::ActiveLow => false, @@ -1234,12 +839,12 @@ macro_rules! tim_hal { // BKE = 1 -> break is enabled // BKP = 0 for active low, 1 for active high // Safety: bkf is set to a constant value (1) that is a valid value for the field per the reference manual - unsafe { tim.$bdtr.write(|w| w.dtg().bits(dtg).bkf().bits(1).aoe().clear_bit().bke().set_bit().bkp().bit(bkp).moe().$moe_set()); } + unsafe { tim.$bdtr().write(|w| w.dtg().bits(dtg).bkf().bits(1).aoe().clear_bit().bke().set_bit().bkp().bit(bkp).moe().$moe_set()); } // AF1: // BKINE = 1 -> break input enabled // BKINP should make input active high (BDTR BKP will set polarity), bit value varies timer to timer - tim.$af1.write(|w| w.bkine().set_bit().bkinp().$bkinp_setting()); + tim.$af1().write(|w| w.bkine().set_bit().bkinp().$bkinp_setting()); } $( // Not all timers that have break inputs have break2 inputs @@ -1250,37 +855,37 @@ macro_rules! tim_hal { // BK2E = 1 -> break is enabled // BK2P = 0 for active low, 1 for active high // Safety: bkf is set to a constant value (1) that is a valid value for the field per the reference manual - unsafe { tim.$bdtr.write(|w| w.dtg().bits(dtg).bk2f().bits(1).aoe().clear_bit().bk2e().set_bit().bk2p().bit(bkp).moe().$moe_set()); } + unsafe { tim.$bdtr().write(|w| w.dtg().bits(dtg).bk2f().bits(1).aoe().clear_bit().bk2e().set_bit().bk2p().bit(bkp).moe().$moe_set()); } // AF1: // BKINE = 1 -> break input enabled // BKINP should make input active high (BDTR BKP will set polarity), bit value varies timer to timer - tim.af2.write(|w| w.bk2ine().set_bit().bk2inp().$bk2inp_setting()); + tim.af2().write(|w| w.bk2ine().set_bit().bk2inp().$bk2inp_setting()); } )? else { // Safety: the DTG field of BDTR allows any 8-bit deadtime value and the dtg variable is u8 unsafe { - tim.$bdtr.write(|w| w.dtg().bits(dtg).aoe().clear_bit().moe().$moe_set()); + tim.$bdtr().write(|w| w.dtg().bits(dtg).aoe().clear_bit().moe().$moe_set()); } } // BDTR: Advanced-control timers // Set CCxP = OCxREF / CCxNP = !OCxREF // Refer to RM0433 Rev 6 - Table 324. - tim.$bdtr.modify(|_, w| w.moe().$moe_set()); + tim.$bdtr().modify(|_, w| w.moe().$moe_set()); )? $( match self.alignment { Alignment::Left => { }, - Alignment::Right => { tim.cr1.modify(|_, w| w.dir().down()); }, - Alignment::Center => { tim.cr1.modify(|_, w| w.$cms().center_aligned3()); } + Alignment::Right => { tim.cr1().modify(|_, w| w.dir().down()); }, + Alignment::Center => { tim.cr1().modify(|_, w| w.$cms().center_aligned3()); } } )? - tim.cr1.modify(|_, w| w.cen().enabled()); + tim.cr1().modify(|_, w| w.cen().enabled()); (PwmControl::new(), PINS::split()) } @@ -1390,19 +995,19 @@ macro_rules! tim_hal { fn is_fault_active(&self) -> bool { let tim = unsafe { &*<$TIMX>::ptr() }; - !tim.$bdtr.read().moe().bit() + !tim.$bdtr().read().moe().bit() } fn clear_fault(&mut self) { let tim = unsafe { &*<$TIMX>::ptr() }; - tim.$bdtr.modify(|_, w| w.moe().set_bit()); + tim.$bdtr().modify(|_, w| w.moe().set_bit()); } fn set_fault(&mut self) { let tim = unsafe { &*<$TIMX>::ptr() }; - tim.$bdtr.modify(|_, w| w.moe().clear_bit()); + tim.$bdtr().modify(|_, w| w.moe().clear_bit()); } } )? @@ -1430,8 +1035,8 @@ tim_hal! { } tim_hal! { pac::TIM15: (tim15, Tim15, u16, 16, BDTR: bdtr, set_bit, af1, set_bit), - pac::TIM16: (tim16, Tim16, u16, 16, BDTR: bdtr, set_bit, tim16_af1, set_bit), - pac::TIM17: (tim17, Tim17, u16, 16, BDTR: bdtr, set_bit, tim17_af1, set_bit), + pac::TIM16: (tim16, Tim16, u16, 16, BDTR: bdtr, set_bit, af1, set_bit), + pac::TIM17: (tim17, Tim17, u16, 16, BDTR: bdtr, set_bit, af1, set_bit), } pub trait PwmPinEnable { @@ -1442,7 +1047,7 @@ pub trait PwmPinEnable { // Implement PwmPin for timer channels macro_rules! tim_pin_hal { // Standard pins (no complementary functionality) - ($TIMX:ty, $typ:ty: $( + ($TIMX:ty, $typ:ty $(, $ccne:ident)*: $( ($CH:ident, $ccmrx_output:ident, $ocxpe:ident, $ocxm:ident),)+ ) => { $( @@ -1473,13 +1078,13 @@ macro_rules! tim_pin_hal { fn get_duty(&self) -> Self::Duty { let tim = unsafe { &*<$TIMX>::ptr() }; - tim.ccr[$CH as usize].read().ccr().bits() + tim.ccr($CH as usize).read().ccr().bits() as $typ } fn get_max_duty(&self) -> Self::Duty { let tim = unsafe { &*<$TIMX>::ptr() }; - let arr = tim.arr.read().arr().bits(); + let arr = tim.arr().read().arr().bits() as $typ; // One PWM cycle is ARR+1 counts long // Valid PWM duty cycles are 0 to ARR+1 @@ -1496,7 +1101,7 @@ macro_rules! tim_pin_hal { fn set_duty(&mut self, duty: Self::Duty) { let tim = unsafe { &*<$TIMX>::ptr() }; - tim.ccr[$CH as usize].write(|w| w.ccr().bits(duty)); + tim.ccr($CH as usize).write(|w| w.ccr().set(duty as u32)); } } @@ -1507,12 +1112,12 @@ macro_rules! tim_pin_hal { fn ccer_enable(&mut self) { let tim = unsafe { &*<$TIMX>::ptr() }; - tim.ccer.modify(|r, w| unsafe { w.bits(r.bits() | Ch::::EN) }); + tim.ccer().modify(|_, w| w.cce(C).enabled()); } fn ccer_disable(&mut self) { let tim = unsafe { &*<$TIMX>::ptr() }; - tim.ccer.modify(|r, w| unsafe { w.bits(r.bits() & !Ch::::EN) }); + tim.ccer().modify(|_, w| w.cce(C).disabled()); } } @@ -1521,10 +1126,10 @@ macro_rules! tim_pin_hal { pub fn set_polarity(&mut self, pol: Polarity) { let tim = unsafe { &*<$TIMX>::ptr() }; - tim.ccer.modify(|r, w| unsafe { w.bits(match pol { - Polarity::ActiveLow => r.bits() | Ch::::POL, - Polarity::ActiveHigh => r.bits() & !Ch::::POL, - })}); + tim.ccer().modify(|_, w| match pol { + Polarity::ActiveLow => w.ccp(C).set_bit(), + Polarity::ActiveHigh => w.ccp(C).clear_bit(), + }); } } @@ -1549,28 +1154,30 @@ macro_rules! tim_pin_hal { fn ccer_enable(&mut self) { let tim = unsafe { &*<$TIMX>::ptr() }; - tim.ccer.modify(|r, w| unsafe { w.bits(r.bits() | Ch::::EN) }); + tim.ccer().modify(|_, w| w.cce(C).enabled()); } fn ccer_disable(&mut self) { let tim = unsafe { &*<$TIMX>::ptr() }; - tim.ccer.modify(|r, w| unsafe { w.bits(r.bits() & !Ch::::EN) }); + tim.ccer().modify(|_, w| w.cce(C).disabled()); } } - // Enable implementation for ComplementaryEnabled - impl PwmPinEnable for Pwm<$TIMX, C, ComplementaryEnabled> { - fn ccer_enable(&mut self) { - let tim = unsafe { &*<$TIMX>::ptr() }; + $( + // Enable implementation for ComplementaryEnabled + impl PwmPinEnable for Pwm<$TIMX, C, ComplementaryEnabled> { + fn ccer_enable(&mut self) { + let tim = unsafe { &*<$TIMX>::ptr() }; - tim.ccer.modify(|r, w| unsafe { w.bits(r.bits() | Ch::::EN | Ch::::N_EN) }); - } - fn ccer_disable(&mut self) { - let tim = unsafe { &*<$TIMX>::ptr() }; + tim.ccer().modify(|_, w| w.cce(C).enabled().$ccne(C).enabled()); + } + fn ccer_disable(&mut self) { + let tim = unsafe { &*<$TIMX>::ptr() }; - tim.ccer.modify(|r, w| unsafe { w.bits(r.bits() & !Ch::::EN & !Ch::::N_EN) }); + tim.ccer().modify(|_, w| w.cce(C).disabled().$ccne(C).disabled()); + } } - } + )* impl Pwm<$TIMX, C, ComplementaryDisabled> { pub fn into_complementary(self, _npin: NPIN) -> Pwm<$TIMX, C, ComplementaryEnabled> @@ -1578,7 +1185,7 @@ macro_rules! tim_pin_hal { // Make sure we aren't switching to complementary after we enable the channel let tim = unsafe { &*<$TIMX>::ptr() }; - let enabled = (tim.ccer.read().bits() & Ch::::EN) != 0; + let enabled = tim.ccer().read().cce(C).is_enabled(); assert!(!enabled); @@ -1590,10 +1197,10 @@ macro_rules! tim_pin_hal { pub fn set_comp_polarity(&mut self, pol: Polarity) { let tim = unsafe { &*<$TIMX>::ptr() }; - tim.ccer.modify(|r, w| unsafe { w.bits(match pol { - Polarity::ActiveLow => r.bits() | Ch::::N_POL, - Polarity::ActiveHigh => r.bits() & !Ch::::N_POL, - })}); + tim.ccer().modify(|_, w| match pol { + Polarity::ActiveLow => w.ccnp(C).set_bit(), + Polarity::ActiveHigh => w.ccnp(C).clear_bit(), + }); } } @@ -1613,6 +1220,14 @@ macro_rules! tim_pin_hal { }; } +fn foo(tim: pac::TIM12) { + const C: u8 = 0; + let value = 3; + tim.psc().modify(|_, w| w.psc().set(value)); + + tim.ccer().modify(|_, w| w.ccp(C).falling_edge()); +} + // Dual channel timers tim_pin_hal! { pac::TIM12, u16: @@ -1620,7 +1235,7 @@ tim_pin_hal! { (C2, ccmr1_output, oc2pe, oc2m), } tim_pin_hal! { - pac::TIM15, u16: + pac::TIM15, u16, ccne: (C1, ccmr1_output, oc1pe, oc1m), (C2, ccmr1_output, oc2pe, oc2m), } @@ -1641,7 +1256,7 @@ tim_pin_hal! { // Quad channel timers tim_pin_hal! { - pac::TIM1, u16: + pac::TIM1, u16, ccne: (C1, ccmr1_output, oc1pe, oc1m), (C2, ccmr1_output, oc2pe, oc2m), (C3, ccmr2_output, oc3pe, oc3m), @@ -1676,29 +1291,13 @@ tim_pin_hal! { (C4, ccmr2_output, oc4pe, oc4m), } tim_pin_hal! { - pac::TIM8, u16: + pac::TIM8, u16, ccne: (C1, ccmr1_output, oc1pe, oc1m), (C2, ccmr1_output, oc2pe, oc2m), (C3, ccmr2_output, oc3pe, oc3m), (C4, ccmr2_output, oc4pe, oc4m), } -#[cfg(feature = "rm0468")] -tim_pin_hal! { - pac::TIM23, u32: - (C1, ccmr1_output, oc1pe, oc1m), - (C2, ccmr1_output, oc2pe, oc2m), - (C3, ccmr2_output, oc3pe, oc3m), - (C4, ccmr2_output, oc4pe, oc4m), -} -#[cfg(feature = "rm0468")] -tim_pin_hal! { - pac::TIM24, u32: - (C1, ccmr1_output, oc1pe, oc1m), - (C2, ccmr1_output, oc2pe, oc2m), - (C3, ccmr2_output, oc3pe, oc3m), - (C4, ccmr2_output, oc4pe, oc4m), -} - +/* // Low-power timers macro_rules! lptim_hal { ($($TIMX:ty: ($timX:ident, $Rec:ident),)+) => { @@ -1742,19 +1341,19 @@ macro_rules! lptim_hal { assert!(arr > 0); // CFGR - tim.cfgr.modify(|_, w| w.presc().variant(prescale)); + tim.cfgr().modify(|_, w| w.presc().variant(prescale)); // Enable - tim.cr.modify(|_, w| w.enable().enabled()); + tim.cr().modify(|_, w| w.enable().enabled()); // Write ARR: LPTIM must be enabled - tim.arr.write(|w| w.arr().bits(arr as u16)); - while !tim.isr.read().arrok().is_set() {} - tim.icr.write(|w| w.arrokcf().clear()); + tim.arr().write(|w| w.arr().bits(arr as u16)); + while !tim.isr().read().arrok().is_set() {} + tim.icr().write(|w| w.arrokcf().clear()); // PWM output is disabled by default, disable the // entire timer - tim.cr.modify(|_, w| w.enable().disabled()); + tim.cr().modify(|_, w| w.enable().disabled()); PINS::split() } @@ -1770,34 +1369,34 @@ macro_rules! lptim_hal { // LPTIM only has one output, so we disable the // entire timer - tim.cr.modify(|_, w| w.enable().disabled()); + tim.cr().modify(|_, w| w.enable().disabled()); } fn enable(&mut self) { let tim = unsafe { &*<$TIMX>::ptr() }; - tim.cr.modify(|_, w| w.enable().enabled()); - tim.cr.modify(|_, w| w.cntstrt().start()); + tim.cr().modify(|_, w| w.enable().enabled()); + tim.cr().modify(|_, w| w.cntstrt().start()); } fn get_duty(&self) -> u16 { let tim = unsafe { &*<$TIMX>::ptr() }; - tim.cmp.read().cmp().bits() + tim.cmp().read().cmp().bits() } fn get_max_duty(&self) -> u16 { let tim = unsafe { &*<$TIMX>::ptr() }; - tim.arr.read().arr().bits() + tim.arr().read().arr().bits() } fn set_duty(&mut self, duty: u16) { let tim = unsafe { &*<$TIMX>::ptr() }; - tim.cmp.write(|w| w.cmp().bits(duty)); - while !tim.isr.read().cmpok().is_set() {} - tim.icr.write(|w| w.cmpokcf().clear()); + tim.cmp().write(|w| w.cmp().bits(duty)); + while !tim.isr().read().cmpok().is_set() {} + tim.icr().write(|w| w.cmpokcf().clear()); } } )+ @@ -1813,4 +1412,4 @@ lptim_hal! { lptim_hal! { pac::LPTIM4: (lptim4, Lptim4), pac::LPTIM5: (lptim5, Lptim5), -} \ No newline at end of file +}*/ diff --git a/src/timer.rs b/src/timer.rs index 988c59b..f06b02b 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -12,7 +12,9 @@ use core::marker::PhantomData; use crate::stm32::{TIM1, TIM2, TIM3, TIM6, TIM7}; #[cfg(feature = "rm0481")] -use crate::stm32::{/*TIM12, */TIM15, TIM4, TIM5, TIM8}; // TODO: TIM12 seems to be missing for 523's pac, re add once fixed +use crate::stm32::{ + TIM12, TIM13, TIM14, TIM15, TIM16, TIM17, TIM4, TIM5, TIM8, +}; // TODO: TIM12 seems to be missing for 523's pac, re add once fixed use cast::{u16, u32}; use void::Void; @@ -46,8 +48,8 @@ impl_tim_ker_ck! { #[cfg(feature = "rm0481")] impl_tim_ker_ck! { - timx_ker_ck: TIM4, TIM5 //TIM12 // TODO: TIM12 seems to be missing for 523's pac, re add once fixed - timy_ker_ck: TIM8, TIM15 + timx_ker_ck: TIM4, TIM5, TIM12, TIM13, TIM14 // TODO: TIM12 seems to be missing for 523's pac, re add once fixed + timy_ker_ck: TIM8, TIM15, TIM16, TIM17 } /// External trait for hardware timers From 0156c1f7c0392e872d060d999f231ef3aa45e169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Sn=C3=B6man?= Date: Wed, 3 Sep 2025 13:50:21 +0200 Subject: [PATCH 06/12] Fixed compile issues --- .cargo/config.toml | 2 +- src/pwm/mod.rs | 36 ++++++++++++++++++++++++------------ src/timer.rs | 16 ++++++++++++---- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index d2012bd..db670e2 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,5 +1,5 @@ [target.thumbv8m.main-none-eabihf] -runner = 'probe-rs run --connect-under-reset' +runner = 'probe-rs run --chip STM32H523RETx' rustflags = [ # LLD (shipped with the Rust toolchain) is used as the default linker "-C", "link-arg=-Tlink.x", diff --git a/src/pwm/mod.rs b/src/pwm/mod.rs index b3caa23..6860568 100644 --- a/src/pwm/mod.rs +++ b/src/pwm/mod.rs @@ -1019,22 +1019,23 @@ tim_hal! { pac::TIM1: (tim1, Tim1, u16, 16, DIR: cms, BDTR: bdtr, enabled, af1, clear_bit, clear_bit), pac::TIM2: (tim2, Tim2, u32, 32, DIR: cms), pac::TIM3: (tim3, Tim3, u16, 16, DIR: cms), + pac::TIM6: (tim6, Tim6, u16, 16), + pac::TIM7: (tim7, Tim7, u16, 16), +} + +#[cfg(feature="rm0481")] +tim_hal! { pac::TIM4: (tim4, Tim4, u16, 16, DIR: cms), pac::TIM5: (tim5, Tim5, u32, 32, DIR: cms), pac::TIM8: (tim8, Tim8, u16, 16, DIR: cms, BDTR: bdtr, enabled, af1, clear_bit, clear_bit), -} -#[cfg(feature = "rm0468")] -tim_hal! { - pac::TIM23: (tim23, Tim23, u32, 32, DIR: cms), - pac::TIM24: (tim24, Tim24, u32, 32, DIR: cms), -} + //pac::TIM12: (tim12, Tim12, u16, 16), + pac::TIM15: (tim15, Tim15, u16, 16, BDTR: bdtr, set_bit, af1, set_bit), +} // TODO: TIM12 seems to be missing for 523's pac, re add once fixed + +#[cfg(feature="h56x_h573")] tim_hal! { - pac::TIM12: (tim12, Tim12, u16, 16), pac::TIM13: (tim13, Tim13, u16, 16), pac::TIM14: (tim14, Tim14, u16, 16), -} -tim_hal! { - pac::TIM15: (tim15, Tim15, u16, 16, BDTR: bdtr, set_bit, af1, set_bit), pac::TIM16: (tim16, Tim16, u16, 16, BDTR: bdtr, set_bit, af1, set_bit), pac::TIM17: (tim17, Tim17, u16, 16, BDTR: bdtr, set_bit, af1, set_bit), } @@ -1220,20 +1221,24 @@ macro_rules! tim_pin_hal { }; } -fn foo(tim: pac::TIM12) { +fn foo(tim: pac::TIM1) { const C: u8 = 0; let value = 3; tim.psc().modify(|_, w| w.psc().set(value)); tim.ccer().modify(|_, w| w.ccp(C).falling_edge()); + tim.cr1().modify(|_, w| w.dir().down()); + tim.cr1().modify(|_, w| w.cms().center_aligned3()); } // Dual channel timers +/*#[cfg(feature="rm0481")] tim_pin_hal! { pac::TIM12, u16: (C1, ccmr1_output, oc1pe, oc1m), (C2, ccmr1_output, oc2pe, oc2m), -} +}*/ // TODO: TIM12 seems to be missing for 523's pac, re add once fixed +#[cfg(feature="rm0481")] tim_pin_hal! { pac::TIM15, u16, ccne: (C1, ccmr1_output, oc1pe, oc1m), @@ -1241,15 +1246,19 @@ tim_pin_hal! { } // Single channel timers +#[cfg(feature="h56x_h573")] tim_pin_hal! { pac::TIM13, u16: (C1, ccmr1_output, oc1pe, oc1m), } +#[cfg(feature="h56x_h573")] tim_pin_hal! { pac::TIM14, u16: (C1, ccmr1_output, oc1pe, oc1m), } +#[cfg(feature="h56x_h573")] tim_pin_hal! { pac::TIM16, u16: (C1, ccmr1_output, oc1pe, oc1m), } +#[cfg(feature="h56x_h573")] tim_pin_hal! { pac::TIM17, u16: (C1, ccmr1_output, oc1pe, oc1m), } @@ -1276,6 +1285,7 @@ tim_pin_hal! { (C3, ccmr2_output, oc3pe, oc3m), (C4, ccmr2_output, oc4pe, oc4m), } +#[cfg(feature="rm0481")] tim_pin_hal! { pac::TIM4, u16: (C1, ccmr1_output, oc1pe, oc1m), @@ -1283,6 +1293,7 @@ tim_pin_hal! { (C3, ccmr2_output, oc3pe, oc3m), (C4, ccmr2_output, oc4pe, oc4m), } +#[cfg(feature="rm0481")] tim_pin_hal! { pac::TIM5, u32: (C1, ccmr1_output, oc1pe, oc1m), @@ -1290,6 +1301,7 @@ tim_pin_hal! { (C3, ccmr2_output, oc3pe, oc3m), (C4, ccmr2_output, oc4pe, oc4m), } +#[cfg(feature="rm0481")] tim_pin_hal! { pac::TIM8, u16, ccne: (C1, ccmr1_output, oc1pe, oc1m), diff --git a/src/timer.rs b/src/timer.rs index f06b02b..b548ab7 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -13,9 +13,12 @@ use core::marker::PhantomData; use crate::stm32::{TIM1, TIM2, TIM3, TIM6, TIM7}; #[cfg(feature = "rm0481")] use crate::stm32::{ - TIM12, TIM13, TIM14, TIM15, TIM16, TIM17, TIM4, TIM5, TIM8, + TIM4, TIM5, TIM8, /*TIM12,*/ TIM15, }; // TODO: TIM12 seems to be missing for 523's pac, re add once fixed - +#[cfg(feature = "h56x_h573")] +use crate::stm32::{ + TIM13, TIM14, TIM16, TIM17, +}; use cast::{u16, u32}; use void::Void; @@ -48,8 +51,13 @@ impl_tim_ker_ck! { #[cfg(feature = "rm0481")] impl_tim_ker_ck! { - timx_ker_ck: TIM4, TIM5, TIM12, TIM13, TIM14 // TODO: TIM12 seems to be missing for 523's pac, re add once fixed - timy_ker_ck: TIM8, TIM15, TIM16, TIM17 + timx_ker_ck: TIM4, TIM5 /*TIM12,*/ // TODO: TIM12 seems to be missing for 523's pac, re add once fixed + timy_ker_ck: TIM8, TIM15 +} + +#[cfg(feature = "h56x_h573")] +impl_tim_ker_ck! { + timx_ker_ck: TIM13, TIM14 } /// External trait for hardware timers From a4d5ac252fd11de91cf1c08e098b0e1dd39a7e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Sn=C3=B6man?= Date: Thu, 4 Sep 2025 14:40:29 +0200 Subject: [PATCH 07/12] Added most pins --- src/pwm/h5.rs | 472 +++++++++++++++++++++++++++++++++++++++++++++++++ src/pwm/mod.rs | 3 + 2 files changed, 475 insertions(+) diff --git a/src/pwm/h5.rs b/src/pwm/h5.rs index 8b13789..f5e4dca 100644 --- a/src/pwm/h5.rs +++ b/src/pwm/h5.rs @@ -1 +1,473 @@ +// Pin definitions, mark which pins can be used with which timers and channels +macro_rules! pins { + // Single channel timer + ($($TIMX:ty: OUT: [$($OUT:ty),*])+) => { + $( + $( + impl Pins<$TIMX, Ch, ComplementaryImpossible> for $OUT { + type Channel = Pwm<$TIMX, C1, ComplementaryImpossible>; + fn split() -> Self::Channel { + Pwm::new() + } + } + )* + )+ + }; + // Dual channel timer $pm + ($($TIMX:ty: + CH1($COMP1:ty): [$($( #[ $pmeta1:meta ] )* $CH1:ty),*] + CH2($COMP2:ty): [$($( #[ $pmeta2:meta ] )* $CH2:ty),*] + CH1N: [$($( #[ $pmeta3:meta ] )* $CH1N:ty),*] + CH2N: [$($( #[ $pmeta4:meta ] )* $CH2N:ty),*] + BRK: [$($( #[ $pmeta5:meta ] )* $BRK:ty),*] + BRK2: [$($( #[ $pmeta6:meta ] )* $BRK2:ty),*] + ETR: [$($( #[ $pmeta7:meta ] )* $ETR:ty),*] + )+) => { + $( + $( + $( #[ $pmeta1 ] )* + impl Pins<$TIMX, Ch, $COMP1> for $CH1 { + type Channel = Pwm<$TIMX, C1, $COMP1>; + fn split() -> Self::Channel { + Pwm::new() + } + } + )* + $( + $( #[ $pmeta2 ] )* + impl Pins<$TIMX, Ch, $COMP2> for $CH2 { + type Channel = Pwm<$TIMX, C2, $COMP2>; + fn split() -> Self::Channel { + Pwm::new() + } + } + )* + $( + $( #[ $pmeta3 ] )* + impl NPins<$TIMX, Ch> for $CH1N {} + )* + $( + $( #[ $pmeta4 ] )* + impl NPins<$TIMX, Ch> for $CH2N {} + )* + $( + $( #[ $pmeta5 ] )* + impl FaultPins<$TIMX,> for $BRK { + const INPUT: BreakInput = BreakInput::BreakIn; + } + )* + $( + $( #[ $pmeta6 ] )* + impl FaultPins<$TIMX> for $BRK2 { + const INPUT: BreakInput = BreakInput::BreakIn2; + } + )* + $( + $( #[ $pmeta7 ] )* + impl ExternalTriggerPins<$TIMX> for $ETR {} + )* + )+ + }; + // Quad channel timers + ($($TIMX:ty: + CH1($COMP1:ty): [$($( #[ $pmeta1:meta ] )* $CH1:ty),*] + CH2($COMP2:ty): [$($( #[ $pmeta2:meta ] )* $CH2:ty),*] + CH3($COMP3:ty): [$($( #[ $pmeta3:meta ] )* $CH3:ty),*] + CH4($COMP4:ty): [$($( #[ $pmeta4:meta ] )* $CH4:ty),*] + CH1N: [$($( #[ $pmeta5:meta ] )* $CH1N:ty),*] + CH2N: [$($( #[ $pmeta6:meta ] )* $CH2N:ty),*] + CH3N: [$($( #[ $pmeta7:meta ] )* $CH3N:ty),*] + CH4N: [$($( #[ $pmeta8:meta ] )* $CH4N:ty),*] + BRK: [$($( #[ $pmeta9:meta ] )* $BRK:ty),*] + BRK2: [$($( #[ $pmeta10:meta ] )* $BRK2:ty),*] + ETR: [$($( #[ $pmeta11:meta ] )* $ETR:ty),*] + )+) => { + $( + $( + $( #[ $pmeta1 ] )* + impl Pins<$TIMX, Ch, $COMP1> for $CH1 { + type Channel = Pwm<$TIMX, C1, $COMP1>; + fn split() -> Self::Channel { + Pwm::new() + } + } + )* + $( + $( #[ $pmeta2 ] )* + impl Pins<$TIMX, Ch, $COMP2> for $CH2 { + type Channel = Pwm<$TIMX, C2, $COMP2>; + fn split() -> Self::Channel { + Pwm::new() + } + } + )* + $( + $( #[ $pmeta3 ] )* + impl Pins<$TIMX, Ch, $COMP3> for $CH3 { + type Channel = Pwm<$TIMX, C3, $COMP3>; + fn split() -> Self::Channel { + Pwm::new() + } + } + )* + $( + $( #[ $pmeta4 ] )* + impl Pins<$TIMX, Ch, $COMP4> for $CH4 { + type Channel = Pwm<$TIMX, C4, $COMP4>; + fn split() -> Self::Channel { + Pwm::new() + } + } + )* + $( + $( #[ $pmeta5 ] )* + impl NPins<$TIMX, Ch> for $CH1N {} + )* + $( + $( #[ $pmeta6 ] )* + impl NPins<$TIMX, Ch> for $CH2N {} + )* + $( + $( #[ $pmeta7 ] )* + impl NPins<$TIMX, Ch> for $CH3N {} + )* + $( + $( #[ $pmeta8 ] )* + impl NPins<$TIMX, Ch> for $CH4N {} + )* + $( + $( #[ $pmeta9 ] )* + impl FaultPins<$TIMX> for $BRK { + const INPUT: BreakInput = BreakInput::BreakIn; + } + )* + $( + $( #[ $pmeta10 ] )* + impl FaultPins<$TIMX> for $BRK2 { + const INPUT: BreakInput = BreakInput::BreakIn2; + } + )* + $( + $( #[ $pmeta11 ] )* + impl ExternalTriggerPins<$TIMX> for $ETR {} + )* + )+ + } +} +pins!( + pac::TIM1: //523,533,563,573 + CH1(ComplementaryImpossible): [ + gpio::PA8>, //523,533,563,573 + gpio::PE9>, //523,533,563,573 + gpio::PH11>, //563,573 + ] + CH2(ComplementaryImpossible): [ + gpio::PA9>, //523,533,563,573 + gpio::PE11>, //523,533,563,573 + gpio::PH9>, //563,573 + ] + CH3(ComplementaryImpossible): [ + gpio::PA10>, //523,533,563,573 + gpio::PE13>, //523,533,563,573 + gpio::PH7>, //563,573 + ] + CH4(ComplementaryImpossible): [ + gpio::PA11>, //523,533,563,573 + gpio::PE14>, //523,533,563,573 + ] + CH1N: [ + gpio::PA7>, //523,533,563,573 + gpio::PB13>, //523,533,563,573 + gpio::PE8>, //523,533,563,573 + gpio::PH10>, //563,573 + ] + CH2N: [ + gpio::PB0>, //523,533,563,573 + gpio::PB14>, //523,533,563,573 + gpio::PE10>, //523,533,563,573 + gpio::PH8>, //563,573 + ] + CH3N: [ + gpio::PB1>, //523,533,563,573 + gpio::PB15>, //523,533,563,573 + gpio::PE12>, //523,533,563,573 + gpio::PH6>, //563,573 + ] + CH4N: [ + gpio::PC5>, //523,533,563,573 + gpio::PD5>, //523,533,563,573 + gpio::PE15>, //523,533,563,573 + ] + BRK: [ + gpio::PA6>, //523,533,563,573 + gpio::PB12>, //523,533,563,573 + gpio::PE15>, //523,533,563,573 + gpio::PH12>, //563,573 + ] + BRK2: [ + gpio::PE6>, //523,533,563,573 + gpio::PG4>, //523,533,563,573 + ] + ETR: [ + gpio::PA12>, //523,533,563,573 + gpio::PE7>, //523,533,563,573 + gpio::PG5>, //523,533,563,573 + ] + pac::TIM2: //523,533,563,573 + CH1(ComplementaryImpossible): [ + gpio::PA0>, //523,533,563,573 + gpio::PA5>, //523,533,563,573 + gpio::PA15>, //523,533,563,573 + ] + CH2(ComplementaryImpossible): [ + gpio::PA1>, //523,533,563,573 + gpio::PB3>, //523,533,563,573 + ] + CH3(ComplementaryImpossible): [ + gpio::PA2>, //523,533,563,573 + gpio::PB10>, //523,533,563,573 + ] + CH4(ComplementaryImpossible): [ + gpio::PA3>, //523,533,563,573 + gpio::PC4>, //523,533,563,573 + gpio::PB11>, //563,573 + ] + CH1N: [] + CH2N: [] + BRK: [] + BRK2: [] + ETR: [ + gpio::PA0>, //523,533,563,573 + gpio::PA5>, //523,533,563,573 + gpio::PA15>, //523,533,563,573 + ] + pac::TIM3: //523,533,563,573 + CH1(ComplementaryImpossible): [ + gpio::PA6>, //523,533,563,573 + gpio::PB4>, //523,533,563,573 + gpio::PC6>, //523,533,563,573 + ] + CH2(ComplementaryImpossible): [ + gpio::PA7>, //523,533,563,573 + gpio::PB5>, //523,533,563,573 + gpio::PC7>, //523,533,563,573 + ] + CH3(ComplementaryImpossible): [ + gpio::PB0>, //523,533,563,573 + gpio::PC8>, //523,533,563,573 + ] + CH4(ComplementaryImpossible): [ + gpio::PB1>, //523,533,563,573 + gpio::PC9>, //523,533,563,573 + ] + CH1N: [] + CH2N: [] + BRK: [] + BRK2: [] + ETR: [ + gpio::PD2>, //523,533,563,573 + ] + pac::TIM4: //523,533,563,573 + CH1(ComplementaryImpossible): [ + gpio::PB6>, //523,533,563,573 + gpio::PD12>, //523,533,563,573 + ] + CH2(ComplementaryImpossible): [ + gpio::PB7>, //523,533,563,573 + gpio::PD13>, //523,533,563,573 + ] + CH3(ComplementaryImpossible): [ + gpio::PB8>, //523,533,563,573 + gpio::PD14>, //523,533,563,573 + ] + CH4(ComplementaryImpossible): [ + gpio::PB9>, //523,533,563,573 + gpio::PC2>, //523,533,563,573 + gpio::PD15>, //523,533,563,573 + ] + CH1N: [] + CH2N: [] + BRK: [] + BRK2: [] + ETR: [ + gpio::PE0>, //523,533,563,573 + ] + pac::TIM5: //523,533,563,573 + CH1(ComplementaryImpossible): [ + gpio::PA0>, //523,533,563,573 + gpio::PH10>, //563,573 + ] + CH2(ComplementaryImpossible): [ + gpio::PA1>, //523,533,563,573 + gpio::PH11>, //563,573 + ] + CH3(ComplementaryImpossible): [ + gpio::PA2>, //523,533,563,573 + gpio::PH12>, //563,573 + ] + CH4(ComplementaryImpossible): [ + gpio::PA3>, //523,533,563,573 + gpio::PI0>, //563,573 + ] + CH1N: [] + CH2N: [] + BRK: [] + BRK2: [] + ETR: [ + gpio::PA4>, //523,533,563,573 + gpio::PH8>, //563,573 + ] + pac::TIM8: //523,533,563,573 + CH1(ComplementaryImpossible): [ + gpio::PB10>, //523,533 + gpio::PC6>, //523,533,563,573 + gpio::PH6>, //563,573 + gpio::PI5>, //563,573 + ] + CH2(ComplementaryImpossible): [ + gpio::PB13>, //523,533 + gpio::PC7>, //523,533,563,573 + gpio::PH8>, //563,573 + gpio::PI6>, //563,573 + ] + CH3(ComplementaryImpossible): [ + gpio::PB12>, //523,533 + gpio::PC8>, //523,533,563,573 + gpio::PH10>, //563,573 + gpio::PI7>, //563,573 + ] + CH4(ComplementaryImpossible): [ + gpio::PC9>, //523,533,563,573 + gpio::PI2>, //563,573 + ] + CH1N: [ + gpio::PA5>, //523,533,563,573 + gpio::PA7>, //523,533,563,573 + gpio::PH7>, //563,573 + gpio::PH13>, //563,573 + ] + CH2N: [ + gpio::PB0>, //523,533,563,573 + gpio::PB14>, //523,533,563,573 + gpio::PH9>, //563,573 + gpio::PH14>, //563,573 + ] + CH3N: [ + gpio::PB1>, //523,533,563,573 + gpio::PB15>, //523,533,563,573 + gpio::PH11>, //563,573 + gpio::PH15>, //563,573 + ] + CH4N: [ + gpio::PB2>, //523,533,563,573 + gpio::PD0>, //523,533,563,573 + gpio::PH12>, //563,573 + ] + BRK: [ + gpio::PA6>, //523,533,563,573 + gpio::PG2>, //523,533,563,573 + gpio::PH12>, //563,573 + gpio::PI4>, //563,573 + ] + BRK2: [ + gpio::PA8>, //523,533,563,573 + gpio::PG3>, //523,533,563,573 + gpio::PI1>, //563,573 + ] + ETR: [ + gpio::PA0>, //523,533,563,573 + gpio::PG8>, //523,533,563,573 + gpio::PI3>, //563,573 + ] + pac::TIM12: //523,533,563,573 + CH1(ComplementaryImpossible): [ + gpio::PB14>, //523,533,563,573 + gpio::PH6>, //563,573 + ] + CH2(ComplementaryImpossible): [ + gpio::PB15>, //523,533,563,573 + gpio::PH9>, //563,573 + ] + CH1N: [] + CH2N: [] + BRK: [] + BRK2: [] + ETR: [] + pac::TIM13: //563,573 + CH1(ComplementaryImpossible): [ + gpio::PA6>, //563,573 + gpio::PF8>, //563,573 + ] + CH1N: [] + CH2N: [] + BRK: [] + BRK2: [] + ETR: [] + pac::TIM14: //563,573 + CH1(ComplementaryImpossible): [ + gpio::PA7>, //563,573 + gpio::PF9>, //563,573 + ] + CH1N: [] + CH2N: [] + BRK: [] + BRK2: [] + ETR: [] + pac::TIM15: //523,533,563,573 + CH1(ComplementaryImpossible): [ + gpio::PA2>, //523,533,563,573 + gpio::PC12>, //523,533,563,573 + gpio::PE5>, //523,533,563,573 + ] + CH2(ComplementaryImpossible): [ + gpio::PA3>, //523,533,563,573 + gpio::PE6>, //523,533,563,573 + ] + CH1N: [ + gpio::PA1>, //523,533,563,573 + gpio::PE4>, //523,533,563 + ] + CH2N: [] + BRK: [ + gpio::PA0>, //523,533,563,573 + gpio::PD2>, //523,533,563,573 + gpio::PE3>, //523,533,563,573 + ] + BRK2: [] + ETR: [] + pac::TIM16: //563,573 + CH1(ComplementaryImpossible): [ + gpio::PD8>, //563,573 + gpio::PF6>, //563,573 + ] + CH1N: [ + gpio::PB6>, //563,573 + gpio::PF8>, //563,573 + ] + CH2N: [] + BRK: [ + gpio::PB4>, //563,573 + gpio::PC0>, //563,573 + gpio::PF10>, //563,573 + ] + BRK2: [] + ETR: [] + pac::TIM17: //563,573 + CH1(ComplementaryImpossible): [ + gpio::PB9>, //563,573 + gpio::PC2>, //563,573 + gpio::PF7>, //563,573 + ] + CH1N: [ + gpio::PB7>, //563,573 + gpio::PF9>, //563,573 + ] + CH2N: [] + BRK: [ + gpio::PB5>, //563,573 + gpio::PG6>, //563,573 + ] + BRK2: [] + ETR: [] +); \ No newline at end of file diff --git a/src/pwm/mod.rs b/src/pwm/mod.rs index 6860568..4c6f6fe 100644 --- a/src/pwm/mod.rs +++ b/src/pwm/mod.rs @@ -198,6 +198,9 @@ pub trait FaultPins { const INPUT: BreakInput; } +/// ExternalTriggerPins is a trait that marks which GPIO pins may be used as external input trigger; it should not be used directly. +pub trait ExternalTriggerPins {} + /// Channel wrapper pub struct Ch; impl Ch { From e4d18302750928c0bc5bb5b4a4e67f2dd0acc477 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Sn=C3=B6man?= Date: Mon, 8 Sep 2025 12:06:00 +0200 Subject: [PATCH 08/12] Added 503 pins --- src/pwm/h5.rs | 127 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 87 insertions(+), 40 deletions(-) diff --git a/src/pwm/h5.rs b/src/pwm/h5.rs index f5e4dca..6e83d42 100644 --- a/src/pwm/h5.rs +++ b/src/pwm/h5.rs @@ -156,117 +156,164 @@ macro_rules! pins { } pins!( - pac::TIM1: //523,533,563,573 + pac::TIM1: //523,533,563,573,503 CH1(ComplementaryImpossible): [ - gpio::PA8>, //523,533,563,573 + gpio::PA8>, //523,533,563,573,503 gpio::PE9>, //523,533,563,573 gpio::PH11>, //563,573 + gpio::PA13>, //503 + gpio::PB1>, //503 + gpio::PB7>, //503 + gpio::PC6>, //503 ] CH2(ComplementaryImpossible): [ - gpio::PA9>, //523,533,563,573 + gpio::PA9>, //523,533,563,573,503 gpio::PE11>, //523,533,563,573 gpio::PH9>, //563,573 + gpio::PA14>, //503 + gpio::PC7>, //503 + gpio::PB4>, //503 + gpio::PB6>, //503 ] CH3(ComplementaryImpossible): [ - gpio::PA10>, //523,533,563,573 + gpio::PA10>, //523,533,563,573,503 gpio::PE13>, //523,533,563,573 gpio::PH7>, //563,573 + gpio::PB5>, //503 + gpio::PC8>, //503 + gpio::PA1>, //503 ] CH4(ComplementaryImpossible): [ - gpio::PA11>, //523,533,563,573 + gpio::PA11>, //523,533,563,573,503 gpio::PE14>, //523,533,563,573 + gpio::PC9>, //503 + gpio::PA2>, //503 + gpio::PC12>, //503 ] CH1N: [ - gpio::PA7>, //523,533,563,573 - gpio::PB13>, //523,533,563,573 + gpio::PA7>, //523,533,563,573,503 + gpio::PB13>, //523,533,563,573,503 gpio::PE8>, //523,533,563,573 gpio::PH10>, //563,573 + gpio::PA3>, //503 ] CH2N: [ - gpio::PB0>, //523,533,563,573 - gpio::PB14>, //523,533,563,573 + gpio::PB0>, //523,533,563,573,503 + gpio::PB14>, //523,533,563,573,503 gpio::PE10>, //523,533,563,573 gpio::PH8>, //563,573 + gpio::PA4>, //503 + gpio::PB2>, //503 + gpio::PB7>, //503 ] CH3N: [ - gpio::PB1>, //523,533,563,573 - gpio::PB15>, //523,533,563,573 + gpio::PB1>, //523,533,563,573,503 + gpio::PB15>, //523,533,563,573,503 gpio::PE12>, //523,533,563,573 gpio::PH6>, //563,573 + gpio::PB6>, //503 ] CH4N: [ - gpio::PC5>, //523,533,563,573 + gpio::PC5>, //523,533,563,573,503 gpio::PD5>, //523,533,563,573 gpio::PE15>, //523,533,563,573 + gpio::PB4>, //503 + gpio::PA8>, //503 + gpio::PA14>, //503 ] BRK: [ - gpio::PA6>, //523,533,563,573 - gpio::PB12>, //523,533,563,573 + gpio::PA6>, //523,533,563,573,503 + gpio::PB12>, //523,533,563,573,503 gpio::PE15>, //523,533,563,573 gpio::PH12>, //563,573 + gpio::PA4>, //503 + gpio::PB3>, //503 ] BRK2: [ gpio::PE6>, //523,533,563,573 gpio::PG4>, //523,533,563,573 + gpio::PB8>, //503 + gpio::PC10>, //503 + gpio::PC11>, //503 ] ETR: [ - gpio::PA12>, //523,533,563,573 + gpio::PA12>, //523,533,563,573,503 gpio::PE7>, //523,533,563,573 gpio::PG5>, //523,533,563,573 + gpio::PC0>, //503 + gpio::PA13>, //503 + gpio::PB0>, //503 ] - pac::TIM2: //523,533,563,573 + pac::TIM2: //523,533,563,573,503 CH1(ComplementaryImpossible): [ - gpio::PA0>, //523,533,563,573 - gpio::PA5>, //523,533,563,573 - gpio::PA15>, //523,533,563,573 + gpio::PA0>, //523,533,563,573,503 + gpio::PA5>, //523,533,563,573,503 + gpio::PA15>, //523,533,563,573,503 + gpio::PB2>, //503 ] CH2(ComplementaryImpossible): [ - gpio::PA1>, //523,533,563,573 - gpio::PB3>, //523,533,563,573 + gpio::PA1>, //523,533,563,573,503 + gpio::PB3>, //523,533,563,573,503 + gpio::PC11>, //503 ] CH3(ComplementaryImpossible): [ - gpio::PA2>, //523,533,563,573 - gpio::PB10>, //523,533,563,573 + gpio::PA2>, //523,533,563,573,503 + gpio::PB10>, //523,533,563,573,503 + gpio::PD2>, //503 + gpio::PA7>, //503 ] CH4(ComplementaryImpossible): [ - gpio::PA3>, //523,533,563,573 - gpio::PC4>, //523,533,563,573 + gpio::PA3>, //523,533,563,573,503 + gpio::PC4>, //523,533,563,573,503 gpio::PB11>, //563,573 + gpio::PC12>, //503 + gpio::PA12>, //503 ] CH1N: [] CH2N: [] BRK: [] BRK2: [] ETR: [ - gpio::PA0>, //523,533,563,573 - gpio::PA5>, //523,533,563,573 - gpio::PA15>, //523,533,563,573 + gpio::PA0>, //523,533,563,573,503 + gpio::PA5>, //523,533,563,573,503 + gpio::PA15>, //523,533,563,573,503 + gpio::PD2>, //503 ] - pac::TIM3: //523,533,563,573 + pac::TIM3: //523,533,563,573,503 CH1(ComplementaryImpossible): [ - gpio::PA6>, //523,533,563,573 - gpio::PB4>, //523,533,563,573 - gpio::PC6>, //523,533,563,573 + gpio::PA6>, //523,533,563,573,503 + gpio::PB4>, //523,533,563,573,503 + gpio::PC6>, //523,533,563,573,503 + gpio::PA0>, //503 + gpio::PA14>, //503 ] CH2(ComplementaryImpossible): [ - gpio::PA7>, //523,533,563,573 - gpio::PB5>, //523,533,563,573 - gpio::PC7>, //523,533,563,573 + gpio::PA7>, //523,533,563,573,503 + gpio::PB5>, //523,533,563,573,503 + gpio::PC7>, //523,533,563,573,503 + gpio::PA11>, //503 ] CH3(ComplementaryImpossible): [ - gpio::PB0>, //523,533,563,573 - gpio::PC8>, //523,533,563,573 + gpio::PB0>, //523,533,563,573,503 + gpio::PC8>, //523,533,563,573,503 + gpio::PA8>, //503 + gpio::PB6>, //503 ] CH4(ComplementaryImpossible): [ - gpio::PB1>, //523,533,563,573 - gpio::PC9>, //523,533,563,573 + gpio::PB1>, //523,533,563,573,503 + gpio::PC9>, //523,533,563,573,503 + gpio::PA12>, //503 + gpio::PB15>, //503 ] CH1N: [] CH2N: [] BRK: [] BRK2: [] ETR: [ - gpio::PD2>, //523,533,563,573 + gpio::PD2>, //523,533,563,573,503 + gpio::PA2>, //503 + gpio::PB7>, //503 + gpio::PC1>, //503 ] pac::TIM4: //523,533,563,573 CH1(ComplementaryImpossible): [ From b065f859594af7fc89c6794803b3a43c0cdc362a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Sn=C3=B6man?= Date: Mon, 8 Sep 2025 14:42:25 +0200 Subject: [PATCH 09/12] Sorted pins and set complementary outputs --- src/pwm/h5.rs | 650 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 492 insertions(+), 158 deletions(-) diff --git a/src/pwm/h5.rs b/src/pwm/h5.rs index 6e83d42..22ca9fb 100644 --- a/src/pwm/h5.rs +++ b/src/pwm/h5.rs @@ -155,117 +155,95 @@ macro_rules! pins { } } +#[cfg(feature = "rm0492")] pins!( - pac::TIM1: //523,533,563,573,503 - CH1(ComplementaryImpossible): [ - gpio::PA8>, //523,533,563,573,503 - gpio::PE9>, //523,533,563,573 - gpio::PH11>, //563,573 + pac::TIM1: //503 + CH1(ComplementaryDisabled): [ + gpio::PA8>, //503 gpio::PA13>, //503 gpio::PB1>, //503 gpio::PB7>, //503 gpio::PC6>, //503 ] - CH2(ComplementaryImpossible): [ - gpio::PA9>, //523,533,563,573,503 - gpio::PE11>, //523,533,563,573 - gpio::PH9>, //563,573 + CH2(ComplementaryDisabled): [ + gpio::PA9>, //503 gpio::PA14>, //503 gpio::PC7>, //503 gpio::PB4>, //503 gpio::PB6>, //503 ] - CH3(ComplementaryImpossible): [ - gpio::PA10>, //523,533,563,573,503 - gpio::PE13>, //523,533,563,573 - gpio::PH7>, //563,573 + CH3(ComplementaryDisabled): [ + gpio::PA10>, //503 gpio::PB5>, //503 gpio::PC8>, //503 gpio::PA1>, //503 ] - CH4(ComplementaryImpossible): [ - gpio::PA11>, //523,533,563,573,503 - gpio::PE14>, //523,533,563,573 + CH4(ComplementaryDisabled): [ + gpio::PA11>, //503 gpio::PC9>, //503 gpio::PA2>, //503 gpio::PC12>, //503 ] CH1N: [ - gpio::PA7>, //523,533,563,573,503 - gpio::PB13>, //523,533,563,573,503 - gpio::PE8>, //523,533,563,573 - gpio::PH10>, //563,573 + gpio::PA7>, //503 + gpio::PB13>, //503 gpio::PA3>, //503 ] CH2N: [ - gpio::PB0>, //523,533,563,573,503 - gpio::PB14>, //523,533,563,573,503 - gpio::PE10>, //523,533,563,573 - gpio::PH8>, //563,573 + gpio::PB0>, //503 + gpio::PB14>, //503 gpio::PA4>, //503 gpio::PB2>, //503 gpio::PB7>, //503 ] CH3N: [ - gpio::PB1>, //523,533,563,573,503 - gpio::PB15>, //523,533,563,573,503 - gpio::PE12>, //523,533,563,573 - gpio::PH6>, //563,573 + gpio::PB1>, //503 + gpio::PB15>, //503 gpio::PB6>, //503 ] CH4N: [ - gpio::PC5>, //523,533,563,573,503 - gpio::PD5>, //523,533,563,573 - gpio::PE15>, //523,533,563,573 - gpio::PB4>, //503 + gpio::PC5>, //503 gpio::PA8>, //503 gpio::PA14>, //503 ] BRK: [ - gpio::PA6>, //523,533,563,573,503 - gpio::PB12>, //523,533,563,573,503 - gpio::PE15>, //523,533,563,573 - gpio::PH12>, //563,573 + gpio::PA6>, //503 + gpio::PB12>, //503 gpio::PA4>, //503 gpio::PB3>, //503 ] BRK2: [ - gpio::PE6>, //523,533,563,573 - gpio::PG4>, //523,533,563,573 gpio::PB8>, //503 gpio::PC10>, //503 gpio::PC11>, //503 ] ETR: [ - gpio::PA12>, //523,533,563,573,503 - gpio::PE7>, //523,533,563,573 - gpio::PG5>, //523,533,563,573 + gpio::PA12>, //503 gpio::PC0>, //503 gpio::PA13>, //503 gpio::PB0>, //503 ] - pac::TIM2: //523,533,563,573,503 + pac::TIM2: //503 CH1(ComplementaryImpossible): [ - gpio::PA0>, //523,533,563,573,503 - gpio::PA5>, //523,533,563,573,503 - gpio::PA15>, //523,533,563,573,503 + gpio::PA0>, //503 + gpio::PA5>, //503 + gpio::PA15>, //503 gpio::PB2>, //503 ] CH2(ComplementaryImpossible): [ - gpio::PA1>, //523,533,563,573,503 - gpio::PB3>, //523,533,563,573,503 + gpio::PA1>, //503 + gpio::PB3>, //503 gpio::PC11>, //503 ] CH3(ComplementaryImpossible): [ - gpio::PA2>, //523,533,563,573,503 - gpio::PB10>, //523,533,563,573,503 + gpio::PA2>, //503 + gpio::PB10>, //503 gpio::PD2>, //503 gpio::PA7>, //503 ] CH4(ComplementaryImpossible): [ - gpio::PA3>, //523,533,563,573,503 - gpio::PC4>, //523,533,563,573,503 - gpio::PB11>, //563,573 + gpio::PA3>, //503 + gpio::PC4>, //503 gpio::PC12>, //503 gpio::PA12>, //503 ] @@ -274,34 +252,34 @@ pins!( BRK: [] BRK2: [] ETR: [ - gpio::PA0>, //523,533,563,573,503 - gpio::PA5>, //523,533,563,573,503 - gpio::PA15>, //523,533,563,573,503 + gpio::PA0>, //503 + gpio::PA5>, //503 + gpio::PA15>, //503 gpio::PD2>, //503 ] - pac::TIM3: //523,533,563,573,503 + pac::TIM3: //503 CH1(ComplementaryImpossible): [ - gpio::PA6>, //523,533,563,573,503 - gpio::PB4>, //523,533,563,573,503 - gpio::PC6>, //523,533,563,573,503 + gpio::PA6>, //503 + gpio::PB4>, //503 + gpio::PC6>, //503 gpio::PA0>, //503 gpio::PA14>, //503 ] CH2(ComplementaryImpossible): [ - gpio::PA7>, //523,533,563,573,503 - gpio::PB5>, //523,533,563,573,503 - gpio::PC7>, //523,533,563,573,503 + gpio::PA7>, //503 + gpio::PB5>, //503 + gpio::PC7>, //503 gpio::PA11>, //503 ] CH3(ComplementaryImpossible): [ - gpio::PB0>, //523,533,563,573,503 - gpio::PC8>, //523,533,563,573,503 + gpio::PB0>, //503 + gpio::PC8>, //503 gpio::PA8>, //503 gpio::PB6>, //503 ] CH4(ComplementaryImpossible): [ - gpio::PB1>, //523,533,563,573,503 - gpio::PC9>, //523,533,563,573,503 + gpio::PB1>, //503 + gpio::PC9>, //503 gpio::PA12>, //503 gpio::PB15>, //503 ] @@ -310,51 +288,404 @@ pins!( BRK: [] BRK2: [] ETR: [ - gpio::PD2>, //523,533,563,573,503 + gpio::PD2>, //503 gpio::PA2>, //503 gpio::PB7>, //503 gpio::PC1>, //503 ] - pac::TIM4: //523,533,563,573 +); + +#[cfg(feature = "h523_h533")] +pins!( + pac::TIM1: //523,533 + // According to Table 7. Timer features in the DS14540 Rev 2 and DS14539 Rev 2 datasheets TIM8 has 3 complementary outputs + // but according to Table 16. Alternate functions there are 4 such outputs + CH1(ComplementaryDisabled): [ + gpio::PA8>, //523,533 + gpio::PE9>, //523,533 + ] + CH2(ComplementaryDisabled): [ + gpio::PA9>, //523,533 + gpio::PE11>, //523,533 + ] + CH3(ComplementaryDisabled): [ + gpio::PA10>, //523,533 + gpio::PE13>, //523,533 + ] + CH4(ComplementaryDisabled): [ + gpio::PA11>, //523,533 + gpio::PE14>, //523,533 + ] + CH1N: [ + gpio::PA7>, //523,533 + gpio::PB13>, //523,533 + gpio::PE8>, //523,533 + ] + CH2N: [ + gpio::PB0>, //523,533 + gpio::PB14>, //523,533 + gpio::PE10>, //523,533 + ] + CH3N: [ + gpio::PB1>, //523,533 + gpio::PB15>, //523,533 + gpio::PE12>, //523,533 + ] + CH4N: [ + gpio::PC5>, //523,533 + gpio::PD5>, //523,533 + gpio::PE15>, //523,533 + ] + BRK: [ + gpio::PA6>, //523,533 + gpio::PB12>, //523,533 + gpio::PE15>, //523,533 + ] + BRK2: [ + gpio::PE6>, //523,533 + gpio::PG4>, //523,533 + ] + ETR: [ + gpio::PA12>, //523,533 + gpio::PE7>, //523,533 + gpio::PG5>, //523,533 + ] + pac::TIM2: //523,533 + CH1(ComplementaryImpossible): [ + gpio::PA0>, //523,533 + gpio::PA5>, //523,533 + gpio::PA15>, //523,533 + ] + CH2(ComplementaryImpossible): [ + gpio::PA1>, //523,533 + gpio::PB3>, //523,533 + ] + CH3(ComplementaryImpossible): [ + gpio::PA2>, //523,533 + gpio::PB10>, //523,533 + ] + CH4(ComplementaryImpossible): [ + gpio::PA3>, //523,533 + gpio::PC4>, //523,533 + ] + CH1N: [] + CH2N: [] + BRK: [] + BRK2: [] + ETR: [ + gpio::PA0>, //523,533 + gpio::PA5>, //523,533 + gpio::PA15>, //523,533 + ] + pac::TIM3: //523,533 CH1(ComplementaryImpossible): [ - gpio::PB6>, //523,533,563,573 - gpio::PD12>, //523,533,563,573 + gpio::PA6>, //523,533 + gpio::PB4>, //523,533 + gpio::PC6>, //523,533 ] CH2(ComplementaryImpossible): [ - gpio::PB7>, //523,533,563,573 - gpio::PD13>, //523,533,563,573 + gpio::PA7>, //523,533 + gpio::PB5>, //523,533 + gpio::PC7>, //523,533 ] CH3(ComplementaryImpossible): [ - gpio::PB8>, //523,533,563,573 - gpio::PD14>, //523,533,563,573 + gpio::PB0>, //523,533 + gpio::PC8>, //523,533 ] CH4(ComplementaryImpossible): [ - gpio::PB9>, //523,533,563,573 - gpio::PC2>, //523,533,563,573 - gpio::PD15>, //523,533,563,573 + gpio::PB1>, //523,533 + gpio::PC9>, //523,533 ] CH1N: [] CH2N: [] BRK: [] BRK2: [] ETR: [ - gpio::PE0>, //523,533,563,573 + gpio::PD2>, //523,533 + ] + pac::TIM4: //523,533 + CH1(ComplementaryImpossible): [ + gpio::PB6>, //523,533 + gpio::PD12>, //523,533 + ] + CH2(ComplementaryImpossible): [ + gpio::PB7>, //523,533 + gpio::PD13>, //523,533 + ] + CH3(ComplementaryImpossible): [ + gpio::PB8>, //523,533 + gpio::PD14>, //523,533 + ] + CH4(ComplementaryImpossible): [ + gpio::PB9>, //523,533 + gpio::PC2>, //523,533 + gpio::PD15>, //523,533 + ] + CH1N: [] + CH2N: [] + BRK: [] + BRK2: [] + ETR: [ + gpio::PE0>, //523,533 ] pac::TIM5: //523,533,563,573 CH1(ComplementaryImpossible): [ - gpio::PA0>, //523,533,563,573 + gpio::PA0>, //523,533 + ] + CH2(ComplementaryImpossible): [ + gpio::PA1>, //523,533 + ] + CH3(ComplementaryImpossible): [ + gpio::PA2>, //523,533 + ] + CH4(ComplementaryImpossible): [ + gpio::PA3>, //523,533 + ] + CH1N: [] + CH2N: [] + BRK: [] + BRK2: [] + ETR: [ + gpio::PA4>, //523,533 + ] + pac::TIM8: //523,533 + // According to Table 7. Timer features in the DS14540 Rev 2 and DS14539 Rev 2 datasheets TIM8 has 3 complementary outputs + // but according to Table 16. Alternate functions there are 4 such outputs + CH1(ComplementaryDisabled): [ + gpio::PB10>, //523,533 + gpio::PC6>, //523,533 + ] + CH2(ComplementaryDisabled): [ + gpio::PB13>, //523,533 + gpio::PC7>, //523,533 + ] + CH3(ComplementaryDisabled): [ + gpio::PB12>, //523,533 + gpio::PC8>, //523,533 + ] + CH4(ComplementaryDisabled): [ + gpio::PC9>, //523,533 + ] + CH1N: [ + gpio::PA5>, //523,533 + gpio::PA7>, //523,533 + ] + CH2N: [ + gpio::PB0>, //523,533 + gpio::PB14>, //523,533 + ] + CH3N: [ + gpio::PB1>, //523,533 + gpio::PB15>, //523,533 + ] + CH4N: [ + gpio::PB2>, //523,533 + gpio::PD0>, //523,533 + ] + BRK: [ + gpio::PA6>, //523,533 + gpio::PG2>, //523,533 + ] + BRK2: [ + gpio::PA8>, //523,533 + gpio::PG3>, //523,533 + ] + ETR: [ + gpio::PA0>, //523,533 + gpio::PG8>, //523,533 + ] + pac::TIM12: //523,533 + // According to Table 7. Timer features in the DS14540 Rev 2 and DS14539 Rev 2 datasheets TIM12 has 1 complementary output + // but according to Table 16. Alternate functions there exists no such output + CH1(ComplementaryImpossible): [ + gpio::PB14>, //523,533 + ] + CH2(ComplementaryImpossible): [ + gpio::PB15>, //523,533 + ] + CH1N: [] + CH2N: [] + BRK: [] + BRK2: [] + ETR: [] + pac::TIM15: //523,533 + CH1(ComplementaryDisabled): [ + gpio::PA2>, //523,533 + gpio::PC12>, //523,533 + gpio::PE5>, //523,533 + ] + CH2(ComplementaryImpossible): [ + gpio::PA3>, //523,533 + gpio::PE6>, //523,533 + ] + CH1N: [ + gpio::PA1>, //523,533 + gpio::PE4>, //523,533 + ] + CH2N: [] + BRK: [ + gpio::PA0>, //523,533 + gpio::PD2>, //523,533 + gpio::PE3>, //523,533 + ] + BRK2: [] + ETR: [] +); + +#[cfg(feature = "h56x_h573")] +pins!( + pac::TIM1: //563,573 + CH1(ComplementaryDisabled): [ + gpio::PA8>, //563,573 + gpio::PE9>, //563,573 + gpio::PH11>, //563,573 + ] + CH2(ComplementaryDisabled): [ + gpio::PA9>, //563,573 + gpio::PE11>, //563,573 + gpio::PH9>, //563,573 + ] + CH3(ComplementaryDisabled): [ + gpio::PA10>, //563,573 + gpio::PE13>, //563,573 + gpio::PH7>, //563,573 + ] + CH4(ComplementaryDisabled): [ + gpio::PA11>, //563,573 + gpio::PE14>, //563,573 + ] + CH1N: [ + gpio::PA7>, //563,573 + gpio::PB13>, //563,573 + gpio::PE8>, //563,573 + gpio::PH10>, //563,573 + ] + CH2N: [ + gpio::PB0>, //563,573 + gpio::PB14>, //563,573 + gpio::PE10>, //563,573 + gpio::PH8>, //563,573 + ] + CH3N: [ + gpio::PB1>, //563,573 + gpio::PB15>, //563,573 + gpio::PE12>, //563,573 + gpio::PH6>, //563,573 + ] + CH4N: [ + gpio::PC5>, //563,573 + gpio::PD5>, //563,573 + gpio::PE15>, //563,573 + ] + BRK: [ + gpio::PA6>, //563,573 + gpio::PB12>, //563,573 + gpio::PE15>, //563,573 + gpio::PH12>, //563,573 + ] + BRK2: [ + gpio::PE6>, //563,573 + gpio::PG4>, //563,573 + ] + ETR: [ + gpio::PA12>, //563,573 + gpio::PE7>, //563,573 + gpio::PG5>, //563,573 + ] + pac::TIM2: //563,573 + CH1(ComplementaryImpossible): [ + gpio::PA0>, //563,573 + gpio::PA5>, //563,573 + gpio::PA15>, //563,573 + ] + CH2(ComplementaryImpossible): [ + gpio::PA1>, //563,573 + gpio::PB3>, //563,573 + ] + CH3(ComplementaryImpossible): [ + gpio::PA2>, //563,573 + gpio::PB10>, //563,573 + ] + CH4(ComplementaryImpossible): [ + gpio::PA3>, //563,573 + gpio::PC4>, //563,573 + gpio::PB11>, //563,573 + ] + CH1N: [] + CH2N: [] + BRK: [] + BRK2: [] + ETR: [ + gpio::PA0>, //563,573 + gpio::PA5>, //563,573 + gpio::PA15>, //563,573 + ] + pac::TIM3: //563,573 + CH1(ComplementaryImpossible): [ + gpio::PA6>, //563,573 + gpio::PB4>, //563,573 + gpio::PC6>, //563,573 + ] + CH2(ComplementaryImpossible): [ + gpio::PA7>, //563,573 + gpio::PB5>, //563,573 + gpio::PC7>, //563,573 + ] + CH3(ComplementaryImpossible): [ + gpio::PB0>, //563,573 + gpio::PC8>, //563,573 + ] + CH4(ComplementaryImpossible): [ + gpio::PB1>, //563,573 + gpio::PC9>, //563,573 + ] + CH1N: [] + CH2N: [] + BRK: [] + BRK2: [] + ETR: [ + gpio::PD2>, //563,573 + ] + pac::TIM4: //563,573 + CH1(ComplementaryImpossible): [ + gpio::PB6>, //563,573 + gpio::PD12>, //563,573 + ] + CH2(ComplementaryImpossible): [ + gpio::PB7>, //563,573 + gpio::PD13>, //563,573 + ] + CH3(ComplementaryImpossible): [ + gpio::PB8>, //563,573 + gpio::PD14>, //563,573 + ] + CH4(ComplementaryImpossible): [ + gpio::PB9>, //563,573 + gpio::PC2>, //563,573 + gpio::PD15>, //563,573 + ] + CH1N: [] + CH2N: [] + BRK: [] + BRK2: [] + ETR: [ + gpio::PE0>, //563,573 + ] + pac::TIM5: //563,573 + CH1(ComplementaryImpossible): [ + gpio::PA0>, //563,573 gpio::PH10>, //563,573 ] CH2(ComplementaryImpossible): [ - gpio::PA1>, //523,533,563,573 + gpio::PA1>, //563,573 gpio::PH11>, //563,573 ] CH3(ComplementaryImpossible): [ - gpio::PA2>, //523,533,563,573 + gpio::PA2>, //563,573 gpio::PH12>, //563,573 ] CH4(ComplementaryImpossible): [ - gpio::PA3>, //523,533,563,573 + gpio::PA3>, //563,573 gpio::PI0>, //563,573 ] CH1N: [] @@ -362,78 +693,77 @@ pins!( BRK: [] BRK2: [] ETR: [ - gpio::PA4>, //523,533,563,573 + gpio::PA4>, //563,573 gpio::PH8>, //563,573 ] - pac::TIM8: //523,533,563,573 - CH1(ComplementaryImpossible): [ - gpio::PB10>, //523,533 - gpio::PC6>, //523,533,563,573 + pac::TIM8: //563,573 + CH1(ComplementaryDisabled): [ + gpio::PC6>, //563,573 gpio::PH6>, //563,573 gpio::PI5>, //563,573 ] - CH2(ComplementaryImpossible): [ - gpio::PB13>, //523,533 - gpio::PC7>, //523,533,563,573 + CH2(ComplementaryDisabled): [ + gpio::PC7>, //563,573 gpio::PH8>, //563,573 gpio::PI6>, //563,573 ] - CH3(ComplementaryImpossible): [ - gpio::PB12>, //523,533 - gpio::PC8>, //523,533,563,573 + CH3(ComplementaryDisabled): [ + gpio::PC8>, //563,573 gpio::PH10>, //563,573 gpio::PI7>, //563,573 ] - CH4(ComplementaryImpossible): [ - gpio::PC9>, //523,533,563,573 + CH4(ComplementaryDisabled): [ + gpio::PC9>, //563,573 gpio::PI2>, //563,573 ] CH1N: [ - gpio::PA5>, //523,533,563,573 - gpio::PA7>, //523,533,563,573 + gpio::PA5>, //563,573 + gpio::PA7>, //563,573 gpio::PH7>, //563,573 gpio::PH13>, //563,573 ] CH2N: [ - gpio::PB0>, //523,533,563,573 - gpio::PB14>, //523,533,563,573 + gpio::PB0>, //563,573 + gpio::PB14>, //563,573 gpio::PH9>, //563,573 gpio::PH14>, //563,573 ] CH3N: [ - gpio::PB1>, //523,533,563,573 - gpio::PB15>, //523,533,563,573 + gpio::PB1>, //563,573 + gpio::PB15>, //563,573 gpio::PH11>, //563,573 gpio::PH15>, //563,573 ] CH4N: [ - gpio::PB2>, //523,533,563,573 - gpio::PD0>, //523,533,563,573 + gpio::PB2>, //563,573 + gpio::PD0>, //563,573 gpio::PH12>, //563,573 ] BRK: [ - gpio::PA6>, //523,533,563,573 - gpio::PG2>, //523,533,563,573 + gpio::PA6>, //563,573 + gpio::PG2>, //563,573 gpio::PH12>, //563,573 gpio::PI4>, //563,573 ] BRK2: [ - gpio::PA8>, //523,533,563,573 - gpio::PG3>, //523,533,563,573 + gpio::PA8>, //563,573 + gpio::PG3>, //563,573 gpio::PI1>, //563,573 ] ETR: [ - gpio::PA0>, //523,533,563,573 - gpio::PG8>, //523,533,563,573 + gpio::PA0>, //563,573 + gpio::PG8>, //563,573 gpio::PI3>, //563,573 ] - pac::TIM12: //523,533,563,573 + pac::TIM12: //563,573 + // According to Table 7. Timer features in the DS14121 Rev 5 and DS14258 Rev 6 datasheets TIM12 has 1 complementary output + // but according to Table 16. Alternate functions there exists no such output CH1(ComplementaryImpossible): [ - gpio::PB14>, //523,533,563,573 + gpio::PB14>, //563,573 gpio::PH6>, //563,573 ] CH2(ComplementaryImpossible): [ - gpio::PB15>, //523,533,563,573 + gpio::PB15>, //563,573 gpio::PH9>, //563,573 ] CH1N: [] @@ -442,6 +772,8 @@ pins!( BRK2: [] ETR: [] pac::TIM13: //563,573 + // According to Table 7. Timer features in the DS14121 Rev 5 and DS14258 Rev 6 datasheets TIM13 has 1 complementary output + // but according to Table 16. Alternate functions there exists no such output CH1(ComplementaryImpossible): [ gpio::PA6>, //563,573 gpio::PF8>, //563,573 @@ -452,6 +784,8 @@ pins!( BRK2: [] ETR: [] pac::TIM14: //563,573 + // According to Table 7. Timer features in the DS14121 Rev 5 and DS14258 Rev 6 datasheets TIM14 has 1 complementary output + // but according to Table 16. Alternate functions there exists no such output CH1(ComplementaryImpossible): [ gpio::PA7>, //563,573 gpio::PF9>, //563,573 @@ -461,60 +795,60 @@ pins!( BRK: [] BRK2: [] ETR: [] - pac::TIM15: //523,533,563,573 - CH1(ComplementaryImpossible): [ - gpio::PA2>, //523,533,563,573 - gpio::PC12>, //523,533,563,573 - gpio::PE5>, //523,533,563,573 + pac::TIM15: //563,573 + CH1(ComplementaryDisabled): [ + gpio::PA2>, //563,573 + gpio::PC12>, //563,573 + gpio::PE5>, //563,573 ] CH2(ComplementaryImpossible): [ - gpio::PA3>, //523,533,563,573 - gpio::PE6>, //523,533,563,573 + gpio::PA3>, //563,573 + gpio::PE6>, //563,573 ] CH1N: [ - gpio::PA1>, //523,533,563,573 - gpio::PE4>, //523,533,563 + gpio::PA1>, //563,573 + gpio::PE4>, //563,573 ] CH2N: [] BRK: [ - gpio::PA0>, //523,533,563,573 - gpio::PD2>, //523,533,563,573 - gpio::PE3>, //523,533,563,573 + gpio::PA0>, //563,573 + gpio::PD2>, //563,573 + gpio::PE3>, //563,573 ] BRK2: [] ETR: [] pac::TIM16: //563,573 - CH1(ComplementaryImpossible): [ - gpio::PD8>, //563,573 - gpio::PF6>, //563,573 - ] - CH1N: [ - gpio::PB6>, //563,573 - gpio::PF8>, //563,573 - ] - CH2N: [] - BRK: [ - gpio::PB4>, //563,573 - gpio::PC0>, //563,573 - gpio::PF10>, //563,573 - ] - BRK2: [] - ETR: [] - pac::TIM17: //563,573 - CH1(ComplementaryImpossible): [ - gpio::PB9>, //563,573 - gpio::PC2>, //563,573 - gpio::PF7>, //563,573 - ] - CH1N: [ - gpio::PB7>, //563,573 - gpio::PF9>, //563,573 - ] - CH2N: [] - BRK: [ - gpio::PB5>, //563,573 - gpio::PG6>, //563,573 - ] - BRK2: [] - ETR: [] -); \ No newline at end of file + CH1(ComplementaryDisabled): [ + gpio::PD8>, //563,573 + gpio::PF6>, //563,573 + ] + CH1N: [ + gpio::PB6>, //563,573 + gpio::PF8>, //563,573 + ] + CH2N: [] + BRK: [ + gpio::PB4>, //563,573 + gpio::PC0>, //563,573 + gpio::PF10>, //563,573 + ] + BRK2: [] + ETR: [] +pac::TIM17: //563,573 + CH1(ComplementaryDisabled): [ + gpio::PB9>, //563,573 + gpio::PC2>, //563,573 + gpio::PF7>, //563,573 + ] + CH1N: [ + gpio::PB7>, //563,573 + gpio::PF9>, //563,573 + ] + CH2N: [] + BRK: [ + gpio::PB5>, //563,573 + gpio::PG6>, //563,573 + ] + BRK2: [] + ETR: [] +); From 94183474efec7baca3a69afaa5758d1a50652e30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Sn=C3=B6man?= Date: Thu, 11 Sep 2025 11:46:35 +0200 Subject: [PATCH 10/12] Compilable pwm pins for all devices --- src/pwm/h5.rs | 910 +++++++++++++++++++++++++++---------------------- src/pwm/mod.rs | 174 +--------- src/timer.rs | 11 +- 3 files changed, 512 insertions(+), 583 deletions(-) diff --git a/src/pwm/h5.rs b/src/pwm/h5.rs index 22ca9fb..eb228e5 100644 --- a/src/pwm/h5.rs +++ b/src/pwm/h5.rs @@ -1,7 +1,54 @@ +use super::{ + BreakInput, Ch, ComplementaryDisabled, ComplementaryImpossible, + ExternalTriggerPins, FaultPins, NPins, Pins, Pwm, C1, C2, C3, C4, +}; +use crate::gpio::{self, Alternate}; +use crate::pac; + // Pin definitions, mark which pins can be used with which timers and channels macro_rules! pins { // Single channel timer - ($($TIMX:ty: OUT: [$($OUT:ty),*])+) => { + ($($TIMX:ty: + CH1($COMP1:ty): [$($( #[ $pmeta1:meta ] )* $CH1:ty),*] + CH1N: [$($( #[ $pmeta2:meta ] )* $CH1N:ty),*] + BRK: [$($( #[ $pmeta3:meta ] )* $BRK:ty),*] + BRK2: [$($( #[ $pmeta4:meta ] )* $BRK2:ty),*] // remove? + ETR: [$($( #[ $pmeta5:meta ] )* $ETR:ty),*] + )+) => { + $( + $( + $( #[ $pmeta1 ] )* + impl Pins<$TIMX, Ch, $COMP1> for $CH1 { + type Channel = Pwm<$TIMX, C1, $COMP1>; + fn split() -> Self::Channel { + Pwm::new() + } + } + )* + $( + $( #[ $pmeta2 ] )* + impl NPins<$TIMX, Ch> for $CH1N {} + )* + $( + $( #[ $pmeta3 ] )* + impl FaultPins<$TIMX,> for $BRK { + const INPUT: BreakInput = BreakInput::BreakIn; + } + )* + $( + $( #[ $pmeta4 ] )* + impl FaultPins<$TIMX> for $BRK2 { + const INPUT: BreakInput = BreakInput::BreakIn2; + } + )* + $( + $( #[ $pmeta5 ] )* + impl ExternalTriggerPins<$TIMX> for $ETR {} + )* + )+ + }; + // Old single channel timer + /*($($TIMX:ty: OUT: [$($OUT:ty),*])+) => { $( $( impl Pins<$TIMX, Ch, ComplementaryImpossible> for $OUT { @@ -12,7 +59,7 @@ macro_rules! pins { } )* )+ - }; + };*/ // Dual channel timer $pm ($($TIMX:ty: CH1($COMP1:ty): [$($( #[ $pmeta1:meta ] )* $CH1:ty),*] @@ -155,700 +202,737 @@ macro_rules! pins { } } +// Quad channel timers #[cfg(feature = "rm0492")] pins!( - pac::TIM1: //503 + pac::TIM1: CH1(ComplementaryDisabled): [ - gpio::PA8>, //503 - gpio::PA13>, //503 - gpio::PB1>, //503 - gpio::PB7>, //503 - gpio::PC6>, //503 + gpio::PA8>, + gpio::PA13>, + gpio::PB1>, + gpio::PB7>, + gpio::PC6> ] CH2(ComplementaryDisabled): [ - gpio::PA9>, //503 - gpio::PA14>, //503 - gpio::PC7>, //503 - gpio::PB4>, //503 - gpio::PB6>, //503 + gpio::PA9>, + gpio::PA14>, + gpio::PC7>, + gpio::PB4>, + gpio::PB6> ] CH3(ComplementaryDisabled): [ - gpio::PA10>, //503 - gpio::PB5>, //503 - gpio::PC8>, //503 - gpio::PA1>, //503 + gpio::PA10>, + gpio::PB5>, + gpio::PC8>, + gpio::PA1> ] CH4(ComplementaryDisabled): [ - gpio::PA11>, //503 - gpio::PC9>, //503 - gpio::PA2>, //503 - gpio::PC12>, //503 + gpio::PA11>, + gpio::PC9>, + gpio::PA2>, + gpio::PC12> ] CH1N: [ - gpio::PA7>, //503 - gpio::PB13>, //503 - gpio::PA3>, //503 + gpio::PA7>, + gpio::PB13>, + gpio::PA3> ] CH2N: [ - gpio::PB0>, //503 - gpio::PB14>, //503 - gpio::PA4>, //503 - gpio::PB2>, //503 - gpio::PB7>, //503 + gpio::PB0>, + gpio::PB14>, + gpio::PA4>, + gpio::PB2>, + gpio::PB7> ] CH3N: [ - gpio::PB1>, //503 - gpio::PB15>, //503 - gpio::PB6>, //503 + gpio::PB1>, + gpio::PB15>, + gpio::PB6> ] CH4N: [ - gpio::PC5>, //503 - gpio::PA8>, //503 - gpio::PA14>, //503 + gpio::PC5>, + gpio::PA8>, + gpio::PA14> ] BRK: [ - gpio::PA6>, //503 - gpio::PB12>, //503 - gpio::PA4>, //503 - gpio::PB3>, //503 + gpio::PA6>, + gpio::PB12>, + gpio::PA4>, + gpio::PB3> ] BRK2: [ - gpio::PB8>, //503 - gpio::PC10>, //503 - gpio::PC11>, //503 + gpio::PB8>, + gpio::PC10>, + gpio::PC11> ] ETR: [ - gpio::PA12>, //503 - gpio::PC0>, //503 - gpio::PA13>, //503 - gpio::PB0>, //503 + gpio::PA12>, + gpio::PC0>, + gpio::PA13>, + gpio::PB0> ] - pac::TIM2: //503 + pac::TIM2: CH1(ComplementaryImpossible): [ - gpio::PA0>, //503 - gpio::PA5>, //503 - gpio::PA15>, //503 - gpio::PB2>, //503 + gpio::PA0>, + gpio::PA5>, + gpio::PA15>, + gpio::PB2> ] CH2(ComplementaryImpossible): [ - gpio::PA1>, //503 - gpio::PB3>, //503 - gpio::PC11>, //503 + gpio::PA1>, + gpio::PB3>, + gpio::PC11> ] CH3(ComplementaryImpossible): [ - gpio::PA2>, //503 - gpio::PB10>, //503 - gpio::PD2>, //503 - gpio::PA7>, //503 + gpio::PA2>, + gpio::PB10>, + gpio::PD2>, + gpio::PA7> ] CH4(ComplementaryImpossible): [ - gpio::PA3>, //503 - gpio::PC4>, //503 - gpio::PC12>, //503 - gpio::PA12>, //503 + gpio::PA3>, + gpio::PC4>, + gpio::PC12>, + gpio::PA12> ] CH1N: [] CH2N: [] + CH3N: [] + CH4N: [] BRK: [] BRK2: [] ETR: [ - gpio::PA0>, //503 - gpio::PA5>, //503 - gpio::PA15>, //503 - gpio::PD2>, //503 + gpio::PA0>, + gpio::PA5>, + gpio::PA15>, + gpio::PD2> ] - pac::TIM3: //503 + pac::TIM3: CH1(ComplementaryImpossible): [ - gpio::PA6>, //503 - gpio::PB4>, //503 - gpio::PC6>, //503 - gpio::PA0>, //503 - gpio::PA14>, //503 + gpio::PA6>, + gpio::PB4>, + gpio::PC6>, + gpio::PA0>, + gpio::PA14> ] CH2(ComplementaryImpossible): [ - gpio::PA7>, //503 - gpio::PB5>, //503 - gpio::PC7>, //503 - gpio::PA11>, //503 + gpio::PA7>, + gpio::PB5>, + gpio::PC7>, + gpio::PA11> ] CH3(ComplementaryImpossible): [ - gpio::PB0>, //503 - gpio::PC8>, //503 - gpio::PA8>, //503 - gpio::PB6>, //503 + gpio::PB0>, + gpio::PC8>, + gpio::PA8>, + gpio::PB6> ] CH4(ComplementaryImpossible): [ - gpio::PB1>, //503 - gpio::PC9>, //503 - gpio::PA12>, //503 - gpio::PB15>, //503 + gpio::PB1>, + gpio::PC9>, + gpio::PA12>, + gpio::PB15> ] CH1N: [] CH2N: [] + CH3N: [] + CH4N: [] BRK: [] BRK2: [] ETR: [ - gpio::PD2>, //503 - gpio::PA2>, //503 - gpio::PB7>, //503 - gpio::PC1>, //503 + gpio::PD2>, + gpio::PA2>, + gpio::PB7>, + gpio::PC1> ] ); +// Dual channel timers #[cfg(feature = "h523_h533")] pins!( - pac::TIM1: //523,533 + // TODO: TIM12 seems to be missing for 523's pac, re add once fixed + /*pac::TIM12: + // According to Table 7. Timer features in the DS14540 Rev 2 and DS14539 Rev 2 datasheets TIM12 has 1 complementary output + // but according to Table 16. Alternate functions there exists no such output + CH1(ComplementaryImpossible): [ + gpio::PB14> + ] + CH2(ComplementaryImpossible): [ + gpio::PB15> + ] + CH1N: [] + CH2N: [] + BRK: [] + BRK2: [] + ETR: []*/ + pac::TIM15: + CH1(ComplementaryDisabled): [ + gpio::PA2>, + gpio::PC12>, + gpio::PE5> + ] + CH2(ComplementaryImpossible): [ + gpio::PA3>, + gpio::PE6> + ] + CH1N: [ + gpio::PA1>, + gpio::PE4> + ] + CH2N: [] + BRK: [ + gpio::PA0>, + gpio::PD2>, + gpio::PE3> + ] + BRK2: [] + ETR: [] +); + +// Quad channel timers +#[cfg(feature = "h523_h533")] +pins!( + pac::TIM1: // According to Table 7. Timer features in the DS14540 Rev 2 and DS14539 Rev 2 datasheets TIM8 has 3 complementary outputs // but according to Table 16. Alternate functions there are 4 such outputs CH1(ComplementaryDisabled): [ - gpio::PA8>, //523,533 - gpio::PE9>, //523,533 + gpio::PA8>, + gpio::PE9> ] CH2(ComplementaryDisabled): [ - gpio::PA9>, //523,533 - gpio::PE11>, //523,533 + gpio::PA9>, + gpio::PE11> ] CH3(ComplementaryDisabled): [ - gpio::PA10>, //523,533 - gpio::PE13>, //523,533 + gpio::PA10>, + gpio::PE13> ] CH4(ComplementaryDisabled): [ - gpio::PA11>, //523,533 - gpio::PE14>, //523,533 + gpio::PA11>, + gpio::PE14> ] CH1N: [ - gpio::PA7>, //523,533 - gpio::PB13>, //523,533 - gpio::PE8>, //523,533 + gpio::PA7>, + gpio::PB13>, + gpio::PE8> ] CH2N: [ - gpio::PB0>, //523,533 - gpio::PB14>, //523,533 - gpio::PE10>, //523,533 + gpio::PB0>, + gpio::PB14>, + gpio::PE10> ] CH3N: [ - gpio::PB1>, //523,533 - gpio::PB15>, //523,533 - gpio::PE12>, //523,533 + gpio::PB1>, + gpio::PB15>, + gpio::PE12> ] CH4N: [ - gpio::PC5>, //523,533 - gpio::PD5>, //523,533 - gpio::PE15>, //523,533 + gpio::PC5>, + gpio::PD5>, + gpio::PE15> ] BRK: [ - gpio::PA6>, //523,533 - gpio::PB12>, //523,533 - gpio::PE15>, //523,533 + gpio::PA6>, + gpio::PB12>, + gpio::PE15> ] BRK2: [ - gpio::PE6>, //523,533 - gpio::PG4>, //523,533 + gpio::PE6>, + gpio::PG4> ] ETR: [ - gpio::PA12>, //523,533 - gpio::PE7>, //523,533 - gpio::PG5>, //523,533 + gpio::PA12>, + gpio::PE7>, + gpio::PG5> ] - pac::TIM2: //523,533 + pac::TIM2: CH1(ComplementaryImpossible): [ - gpio::PA0>, //523,533 - gpio::PA5>, //523,533 - gpio::PA15>, //523,533 + gpio::PA0>, + gpio::PA5>, + gpio::PA15> ] CH2(ComplementaryImpossible): [ - gpio::PA1>, //523,533 - gpio::PB3>, //523,533 + gpio::PA1>, + gpio::PB3> ] CH3(ComplementaryImpossible): [ - gpio::PA2>, //523,533 - gpio::PB10>, //523,533 + gpio::PA2>, + gpio::PB10> ] CH4(ComplementaryImpossible): [ - gpio::PA3>, //523,533 - gpio::PC4>, //523,533 + gpio::PA3>, + gpio::PC4> ] CH1N: [] CH2N: [] + CH3N: [] + CH4N: [] BRK: [] BRK2: [] ETR: [ - gpio::PA0>, //523,533 - gpio::PA5>, //523,533 - gpio::PA15>, //523,533 + gpio::PA0>, + gpio::PA5>, + gpio::PA15> ] - pac::TIM3: //523,533 + pac::TIM3: CH1(ComplementaryImpossible): [ - gpio::PA6>, //523,533 - gpio::PB4>, //523,533 - gpio::PC6>, //523,533 + gpio::PA6>, + gpio::PB4>, + gpio::PC6> ] CH2(ComplementaryImpossible): [ - gpio::PA7>, //523,533 - gpio::PB5>, //523,533 - gpio::PC7>, //523,533 + gpio::PA7>, + gpio::PB5>, + gpio::PC7> ] CH3(ComplementaryImpossible): [ - gpio::PB0>, //523,533 - gpio::PC8>, //523,533 + gpio::PB0>, + gpio::PC8> ] CH4(ComplementaryImpossible): [ - gpio::PB1>, //523,533 - gpio::PC9>, //523,533 + gpio::PB1>, + gpio::PC9> ] CH1N: [] CH2N: [] + CH3N: [] + CH4N: [] BRK: [] BRK2: [] ETR: [ - gpio::PD2>, //523,533 + gpio::PD2> ] - pac::TIM4: //523,533 + pac::TIM4: CH1(ComplementaryImpossible): [ - gpio::PB6>, //523,533 - gpio::PD12>, //523,533 + gpio::PB6>, + gpio::PD12> ] CH2(ComplementaryImpossible): [ - gpio::PB7>, //523,533 - gpio::PD13>, //523,533 + gpio::PB7>, + gpio::PD13> ] CH3(ComplementaryImpossible): [ - gpio::PB8>, //523,533 - gpio::PD14>, //523,533 + gpio::PB8>, + gpio::PD14> ] CH4(ComplementaryImpossible): [ - gpio::PB9>, //523,533 - gpio::PC2>, //523,533 - gpio::PD15>, //523,533 + gpio::PB9>, + gpio::PC2>, + gpio::PD15> ] CH1N: [] CH2N: [] + CH3N: [] + CH4N: [] BRK: [] BRK2: [] ETR: [ - gpio::PE0>, //523,533 + gpio::PE0> ] - pac::TIM5: //523,533,563,573 + pac::TIM5: CH1(ComplementaryImpossible): [ - gpio::PA0>, //523,533 + gpio::PA0> ] CH2(ComplementaryImpossible): [ - gpio::PA1>, //523,533 + gpio::PA1> ] CH3(ComplementaryImpossible): [ - gpio::PA2>, //523,533 + gpio::PA2> ] CH4(ComplementaryImpossible): [ - gpio::PA3>, //523,533 + gpio::PA3> ] CH1N: [] CH2N: [] + CH3N: [] + CH4N: [] BRK: [] BRK2: [] ETR: [ - gpio::PA4>, //523,533 + gpio::PA4> ] - pac::TIM8: //523,533 + pac::TIM8: // According to Table 7. Timer features in the DS14540 Rev 2 and DS14539 Rev 2 datasheets TIM8 has 3 complementary outputs // but according to Table 16. Alternate functions there are 4 such outputs CH1(ComplementaryDisabled): [ - gpio::PB10>, //523,533 - gpio::PC6>, //523,533 + gpio::PB10>, + gpio::PC6> ] CH2(ComplementaryDisabled): [ - gpio::PB13>, //523,533 - gpio::PC7>, //523,533 + gpio::PB13>, + gpio::PC7> ] CH3(ComplementaryDisabled): [ - gpio::PB12>, //523,533 - gpio::PC8>, //523,533 + gpio::PB12>, + gpio::PC8> ] CH4(ComplementaryDisabled): [ - gpio::PC9>, //523,533 + gpio::PC9> ] CH1N: [ - gpio::PA5>, //523,533 - gpio::PA7>, //523,533 + gpio::PA5>, + gpio::PA7> ] CH2N: [ - gpio::PB0>, //523,533 - gpio::PB14>, //523,533 + gpio::PB0>, + gpio::PB14> ] CH3N: [ - gpio::PB1>, //523,533 - gpio::PB15>, //523,533 + gpio::PB1>, + gpio::PB15> ] CH4N: [ - gpio::PB2>, //523,533 - gpio::PD0>, //523,533 + gpio::PB2>, + gpio::PD0> ] BRK: [ - gpio::PA6>, //523,533 - gpio::PG2>, //523,533 + gpio::PA6>, + gpio::PG2> ] BRK2: [ - gpio::PA8>, //523,533 - gpio::PG3>, //523,533 + gpio::PA8>, + gpio::PG3> ] ETR: [ - gpio::PA0>, //523,533 - gpio::PG8>, //523,533 + gpio::PA0>, + gpio::PG8> ] - pac::TIM12: //523,533 - // According to Table 7. Timer features in the DS14540 Rev 2 and DS14539 Rev 2 datasheets TIM12 has 1 complementary output +); + +// Single channel timers +#[cfg(feature = "h56x_h573")] +pins!( + pac::TIM13: + // According to Table 7. Timer features in the DS14121 Rev 5 and DS14258 Rev 6 datasheets TIM13 has 1 complementary output + // but according to Table 16. Alternate functions there exists no such output + CH1(ComplementaryImpossible): [ + gpio::PA6>, + gpio::PF8> + ] + CH1N: [] + BRK: [] + BRK2: [] + ETR: [] + pac::TIM14: + // According to Table 7. Timer features in the DS14121 Rev 5 and DS14258 Rev 6 datasheets TIM14 has 1 complementary output // but according to Table 16. Alternate functions there exists no such output CH1(ComplementaryImpossible): [ - gpio::PB14>, //523,533 + gpio::PA7>, + gpio::PF9> + ] + CH1N: [] + BRK: [] + BRK2: [] + ETR: [] + pac::TIM16: + CH1(ComplementaryDisabled): [ + gpio::PD8>, + gpio::PF6> + ] + CH1N: [ + gpio::PB6>, + gpio::PF8> + ] + BRK: [ + gpio::PB4>, + gpio::PC0>, + gpio::PF10> + ] + BRK2: [] + ETR: [] + pac::TIM17: + CH1(ComplementaryDisabled): [ + gpio::PB9>, + gpio::PC2>, + gpio::PF7> + ] + CH1N: [ + gpio::PB7>, + gpio::PF9> + ] + BRK: [ + gpio::PB5>, + gpio::PG6> + ] + BRK2: [] + ETR: [] +); + +// Dual channel timers +#[cfg(feature = "h56x_h573")] +pins!( + pac::TIM12: + // According to Table 7. Timer features in the DS14121 Rev 5 and DS14258 Rev 6 datasheets TIM12 has 1 complementary output + // but according to Table 16. Alternate functions there exists no such output + CH1(ComplementaryImpossible): [ + gpio::PB14>, + gpio::PH6> ] CH2(ComplementaryImpossible): [ - gpio::PB15>, //523,533 + gpio::PB15>, + gpio::PH9> ] CH1N: [] CH2N: [] BRK: [] BRK2: [] ETR: [] - pac::TIM15: //523,533 + + pac::TIM15: CH1(ComplementaryDisabled): [ - gpio::PA2>, //523,533 - gpio::PC12>, //523,533 - gpio::PE5>, //523,533 + gpio::PA2>, + gpio::PC12>, + gpio::PE5> ] CH2(ComplementaryImpossible): [ - gpio::PA3>, //523,533 - gpio::PE6>, //523,533 + gpio::PA3>, + gpio::PE6> ] CH1N: [ - gpio::PA1>, //523,533 - gpio::PE4>, //523,533 + gpio::PA1>, + gpio::PE4> ] CH2N: [] BRK: [ - gpio::PA0>, //523,533 - gpio::PD2>, //523,533 - gpio::PE3>, //523,533 + gpio::PA0>, + gpio::PD2>, + gpio::PE3> ] BRK2: [] ETR: [] + ); +// Quad channel timers #[cfg(feature = "h56x_h573")] pins!( - pac::TIM1: //563,573 + pac::TIM1: CH1(ComplementaryDisabled): [ - gpio::PA8>, //563,573 - gpio::PE9>, //563,573 - gpio::PH11>, //563,573 + gpio::PA8>, + gpio::PE9>, + gpio::PH11> ] CH2(ComplementaryDisabled): [ - gpio::PA9>, //563,573 - gpio::PE11>, //563,573 - gpio::PH9>, //563,573 + gpio::PA9>, + gpio::PE11>, + gpio::PH9> ] CH3(ComplementaryDisabled): [ - gpio::PA10>, //563,573 - gpio::PE13>, //563,573 - gpio::PH7>, //563,573 + gpio::PA10>, + gpio::PE13>, + gpio::PH7> ] CH4(ComplementaryDisabled): [ - gpio::PA11>, //563,573 - gpio::PE14>, //563,573 + gpio::PA11>, + gpio::PE14> ] CH1N: [ - gpio::PA7>, //563,573 - gpio::PB13>, //563,573 - gpio::PE8>, //563,573 - gpio::PH10>, //563,573 + gpio::PA7>, + gpio::PB13>, + gpio::PE8>, + gpio::PH10> ] CH2N: [ - gpio::PB0>, //563,573 - gpio::PB14>, //563,573 - gpio::PE10>, //563,573 - gpio::PH8>, //563,573 + gpio::PB0>, + gpio::PB14>, + gpio::PE10>, + gpio::PH8> ] CH3N: [ - gpio::PB1>, //563,573 - gpio::PB15>, //563,573 - gpio::PE12>, //563,573 - gpio::PH6>, //563,573 + gpio::PB1>, + gpio::PB15>, + gpio::PE12>, + gpio::PH6> ] CH4N: [ - gpio::PC5>, //563,573 - gpio::PD5>, //563,573 - gpio::PE15>, //563,573 + gpio::PC5>, + gpio::PD5>, + gpio::PE15> ] BRK: [ - gpio::PA6>, //563,573 - gpio::PB12>, //563,573 - gpio::PE15>, //563,573 - gpio::PH12>, //563,573 + gpio::PA6>, + gpio::PB12>, + gpio::PE15>, + gpio::PH12> ] BRK2: [ - gpio::PE6>, //563,573 - gpio::PG4>, //563,573 + gpio::PE6>, + gpio::PG4> ] ETR: [ - gpio::PA12>, //563,573 - gpio::PE7>, //563,573 - gpio::PG5>, //563,573 + gpio::PA12>, + gpio::PE7>, + gpio::PG5> ] - pac::TIM2: //563,573 + pac::TIM2: CH1(ComplementaryImpossible): [ - gpio::PA0>, //563,573 - gpio::PA5>, //563,573 - gpio::PA15>, //563,573 + gpio::PA0>, + gpio::PA5>, + gpio::PA15> ] CH2(ComplementaryImpossible): [ - gpio::PA1>, //563,573 - gpio::PB3>, //563,573 + gpio::PA1>, + gpio::PB3> ] CH3(ComplementaryImpossible): [ - gpio::PA2>, //563,573 - gpio::PB10>, //563,573 + gpio::PA2>, + gpio::PB10> ] CH4(ComplementaryImpossible): [ - gpio::PA3>, //563,573 - gpio::PC4>, //563,573 - gpio::PB11>, //563,573 + gpio::PA3>, + gpio::PC4>, + gpio::PB11> ] CH1N: [] CH2N: [] + CH3N: [] + CH4N: [] BRK: [] BRK2: [] ETR: [ - gpio::PA0>, //563,573 - gpio::PA5>, //563,573 - gpio::PA15>, //563,573 + gpio::PA0>, + gpio::PA5>, + gpio::PA15> ] - pac::TIM3: //563,573 + pac::TIM3: CH1(ComplementaryImpossible): [ - gpio::PA6>, //563,573 - gpio::PB4>, //563,573 - gpio::PC6>, //563,573 + gpio::PA6>, + gpio::PB4>, + gpio::PC6> ] CH2(ComplementaryImpossible): [ - gpio::PA7>, //563,573 - gpio::PB5>, //563,573 - gpio::PC7>, //563,573 + gpio::PA7>, + gpio::PB5>, + gpio::PC7> ] CH3(ComplementaryImpossible): [ - gpio::PB0>, //563,573 - gpio::PC8>, //563,573 + gpio::PB0>, + gpio::PC8> ] CH4(ComplementaryImpossible): [ - gpio::PB1>, //563,573 - gpio::PC9>, //563,573 + gpio::PB1>, + gpio::PC9> ] CH1N: [] CH2N: [] + CH3N: [] + CH4N: [] BRK: [] BRK2: [] ETR: [ - gpio::PD2>, //563,573 + gpio::PD2> ] - pac::TIM4: //563,573 + pac::TIM4: CH1(ComplementaryImpossible): [ - gpio::PB6>, //563,573 - gpio::PD12>, //563,573 + gpio::PB6>, + gpio::PD12> ] CH2(ComplementaryImpossible): [ - gpio::PB7>, //563,573 - gpio::PD13>, //563,573 + gpio::PB7>, + gpio::PD13> ] CH3(ComplementaryImpossible): [ - gpio::PB8>, //563,573 - gpio::PD14>, //563,573 + gpio::PB8>, + gpio::PD14> ] CH4(ComplementaryImpossible): [ - gpio::PB9>, //563,573 - gpio::PC2>, //563,573 - gpio::PD15>, //563,573 + gpio::PB9>, + gpio::PC2>, + gpio::PD15> ] CH1N: [] CH2N: [] + CH3N: [] + CH4N: [] BRK: [] BRK2: [] ETR: [ - gpio::PE0>, //563,573 + gpio::PE0> ] - pac::TIM5: //563,573 + pac::TIM5: CH1(ComplementaryImpossible): [ - gpio::PA0>, //563,573 - gpio::PH10>, //563,573 + gpio::PA0>, + gpio::PH10> ] CH2(ComplementaryImpossible): [ - gpio::PA1>, //563,573 - gpio::PH11>, //563,573 + gpio::PA1>, + gpio::PH11> ] CH3(ComplementaryImpossible): [ - gpio::PA2>, //563,573 - gpio::PH12>, //563,573 + gpio::PA2>, + gpio::PH12> ] CH4(ComplementaryImpossible): [ - gpio::PA3>, //563,573 - gpio::PI0>, //563,573 + gpio::PA3>, + gpio::PI0> ] CH1N: [] CH2N: [] + CH3N: [] + CH4N: [] BRK: [] BRK2: [] ETR: [ - gpio::PA4>, //563,573 - gpio::PH8>, //563,573 + gpio::PA4>, + gpio::PH8> ] - pac::TIM8: //563,573 + pac::TIM8: CH1(ComplementaryDisabled): [ - gpio::PC6>, //563,573 - gpio::PH6>, //563,573 - gpio::PI5>, //563,573 + gpio::PC6>, + gpio::PH6>, + gpio::PI5> ] CH2(ComplementaryDisabled): [ - gpio::PC7>, //563,573 - gpio::PH8>, //563,573 - gpio::PI6>, //563,573 + gpio::PC7>, + gpio::PH8>, + gpio::PI6> ] CH3(ComplementaryDisabled): [ - gpio::PC8>, //563,573 - gpio::PH10>, //563,573 - gpio::PI7>, //563,573 + gpio::PC8>, + gpio::PH10>, + gpio::PI7> ] CH4(ComplementaryDisabled): [ - gpio::PC9>, //563,573 - gpio::PI2>, //563,573 + gpio::PC9>, + gpio::PI2> ] CH1N: [ - gpio::PA5>, //563,573 - gpio::PA7>, //563,573 - gpio::PH7>, //563,573 - gpio::PH13>, //563,573 + gpio::PA5>, + gpio::PA7>, + gpio::PH7>, + gpio::PH13> ] CH2N: [ - gpio::PB0>, //563,573 - gpio::PB14>, //563,573 - gpio::PH9>, //563,573 - gpio::PH14>, //563,573 + gpio::PB0>, + gpio::PB14>, + gpio::PH9>, + gpio::PH14> ] CH3N: [ - gpio::PB1>, //563,573 - gpio::PB15>, //563,573 - gpio::PH11>, //563,573 - gpio::PH15>, //563,573 + gpio::PB1>, + gpio::PB15>, + gpio::PH11>, + gpio::PH15> ] CH4N: [ - gpio::PB2>, //563,573 - gpio::PD0>, //563,573 - gpio::PH12>, //563,573 + gpio::PB2>, + gpio::PD0>, + gpio::PH12> ] BRK: [ - gpio::PA6>, //563,573 - gpio::PG2>, //563,573 - gpio::PH12>, //563,573 - gpio::PI4>, //563,573 + gpio::PA6>, + gpio::PG2>, + gpio::PH12>, + gpio::PI4> ] BRK2: [ - gpio::PA8>, //563,573 - gpio::PG3>, //563,573 - gpio::PI1>, //563,573 + gpio::PA8>, + gpio::PG3>, + gpio::PI1> ] ETR: [ - gpio::PA0>, //563,573 - gpio::PG8>, //563,573 - gpio::PI3>, //563,573 - ] - pac::TIM12: //563,573 - // According to Table 7. Timer features in the DS14121 Rev 5 and DS14258 Rev 6 datasheets TIM12 has 1 complementary output - // but according to Table 16. Alternate functions there exists no such output - CH1(ComplementaryImpossible): [ - gpio::PB14>, //563,573 - gpio::PH6>, //563,573 + gpio::PA0>, + gpio::PG8>, + gpio::PI3> ] - CH2(ComplementaryImpossible): [ - gpio::PB15>, //563,573 - gpio::PH9>, //563,573 - ] - CH1N: [] - CH2N: [] - BRK: [] - BRK2: [] - ETR: [] - pac::TIM13: //563,573 - // According to Table 7. Timer features in the DS14121 Rev 5 and DS14258 Rev 6 datasheets TIM13 has 1 complementary output - // but according to Table 16. Alternate functions there exists no such output - CH1(ComplementaryImpossible): [ - gpio::PA6>, //563,573 - gpio::PF8>, //563,573 - ] - CH1N: [] - CH2N: [] - BRK: [] - BRK2: [] - ETR: [] - pac::TIM14: //563,573 - // According to Table 7. Timer features in the DS14121 Rev 5 and DS14258 Rev 6 datasheets TIM14 has 1 complementary output - // but according to Table 16. Alternate functions there exists no such output - CH1(ComplementaryImpossible): [ - gpio::PA7>, //563,573 - gpio::PF9>, //563,573 - ] - CH1N: [] - CH2N: [] - BRK: [] - BRK2: [] - ETR: [] - pac::TIM15: //563,573 - CH1(ComplementaryDisabled): [ - gpio::PA2>, //563,573 - gpio::PC12>, //563,573 - gpio::PE5>, //563,573 - ] - CH2(ComplementaryImpossible): [ - gpio::PA3>, //563,573 - gpio::PE6>, //563,573 - ] - CH1N: [ - gpio::PA1>, //563,573 - gpio::PE4>, //563,573 - ] - CH2N: [] - BRK: [ - gpio::PA0>, //563,573 - gpio::PD2>, //563,573 - gpio::PE3>, //563,573 - ] - BRK2: [] - ETR: [] - pac::TIM16: //563,573 - CH1(ComplementaryDisabled): [ - gpio::PD8>, //563,573 - gpio::PF6>, //563,573 - ] - CH1N: [ - gpio::PB6>, //563,573 - gpio::PF8>, //563,573 - ] - CH2N: [] - BRK: [ - gpio::PB4>, //563,573 - gpio::PC0>, //563,573 - gpio::PF10>, //563,573 - ] - BRK2: [] - ETR: [] -pac::TIM17: //563,573 - CH1(ComplementaryDisabled): [ - gpio::PB9>, //563,573 - gpio::PC2>, //563,573 - gpio::PF7>, //563,573 - ] - CH1N: [ - gpio::PB7>, //563,573 - gpio::PF9>, //563,573 - ] - CH2N: [] - BRK: [ - gpio::PB5>, //563,573 - gpio::PG6>, //563,573 - ] - BRK2: [] - ETR: [] ); diff --git a/src/pwm/mod.rs b/src/pwm/mod.rs index 4c6f6fe..2e82357 100644 --- a/src/pwm/mod.rs +++ b/src/pwm/mod.rs @@ -203,12 +203,6 @@ pub trait ExternalTriggerPins {} /// Channel wrapper pub struct Ch; -impl Ch { - const EN: u32 = 1 << (C * 4); - const POL: u32 = 1 << (C * 4 + 1); - const N_EN: u32 = 1 << (C * 4 + 2); - const N_POL: u32 = 1 << (C * 4 + 3); -} /// Marker struct for PWM channel 1 on Pins trait and Pwm struct pub const C1: u8 = 0; @@ -426,152 +420,6 @@ pins_tuples! { (C4, C1, C2, C3) } -// Pin definitions, mark which pins can be used with which timers and channels -macro_rules! pins { - // Single channel timer - ($($TIMX:ty: OUT: [$($OUT:ty),*])+) => { - $( - $( - impl Pins<$TIMX, Ch, ComplementaryImpossible> for $OUT { - type Channel = Pwm<$TIMX, C1, ComplementaryImpossible>; - fn split() -> Self::Channel { - Pwm::new() - } - } - )* - )+ - }; - // Dual channel timer $pm - ($($TIMX:ty: - CH1($COMP1:ty): [$($( #[ $pmeta1:meta ] )* $CH1:ty),*] - CH2($COMP2:ty): [$($( #[ $pmeta2:meta ] )* $CH2:ty),*] - CH1N: [$($( #[ $pmeta3:meta ] )* $CH1N:ty),*] - CH2N: [$($( #[ $pmeta4:meta ] )* $CH2N:ty),*] - BRK: [$($( #[ $pmeta5:meta ] )* $BRK:ty),*] - BRK2: [$($( #[ $pmeta6:meta ] )* $BRK2:ty),*] - )+) => { - $( - $( - $( #[ $pmeta1 ] )* - impl Pins<$TIMX, Ch, $COMP1> for $CH1 { - type Channel = Pwm<$TIMX, C1, $COMP1>; - fn split() -> Self::Channel { - Pwm::new() - } - } - )* - $( - $( #[ $pmeta2 ] )* - impl Pins<$TIMX, Ch, $COMP2> for $CH2 { - type Channel = Pwm<$TIMX, C2, $COMP2>; - fn split() -> Self::Channel { - Pwm::new() - } - } - )* - $( - $( #[ $pmeta3 ] )* - impl NPins<$TIMX, Ch> for $CH1N {} - )* - $( - $( #[ $pmeta4 ] )* - impl NPins<$TIMX, Ch> for $CH2N {} - )* - $( - $( #[ $pmeta5 ] )* - impl FaultPins<$TIMX,> for $BRK { - const INPUT: BreakInput = BreakInput::BreakIn; - } - )* - $( - $( #[ $pmeta6 ] )* - impl FaultPins<$TIMX> for $BRK2 { - const INPUT: BreakInput = BreakInput::BreakIn2; - } - )* - )+ - }; - // Quad channel timers - ($($TIMX:ty: - CH1($COMP1:ty): [$($( #[ $pmeta1:meta ] )* $CH1:ty),*] - CH2($COMP2:ty): [$($( #[ $pmeta2:meta ] )* $CH2:ty),*] - CH3($COMP3:ty): [$($( #[ $pmeta3:meta ] )* $CH3:ty),*] - CH4($COMP4:ty): [$($( #[ $pmeta4:meta ] )* $CH4:ty),*] - CH1N: [$($( #[ $pmeta5:meta ] )* $CH1N:ty),*] - CH2N: [$($( #[ $pmeta6:meta ] )* $CH2N:ty),*] - CH3N: [$($( #[ $pmeta7:meta ] )* $CH3N:ty),*] - CH4N: [$($( #[ $pmeta8:meta ] )* $CH4N:ty),*] - BRK: [$($( #[ $pmeta9:meta ] )* $BRK:ty),*] - BRK2: [$($( #[ $pmeta10:meta ] )* $BRK2:ty),*] - )+) => { - $( - $( - $( #[ $pmeta1 ] )* - impl Pins<$TIMX, Ch, $COMP1> for $CH1 { - type Channel = Pwm<$TIMX, C1, $COMP1>; - fn split() -> Self::Channel { - Pwm::new() - } - } - )* - $( - $( #[ $pmeta2 ] )* - impl Pins<$TIMX, Ch, $COMP2> for $CH2 { - type Channel = Pwm<$TIMX, C2, $COMP2>; - fn split() -> Self::Channel { - Pwm::new() - } - } - )* - $( - $( #[ $pmeta3 ] )* - impl Pins<$TIMX, Ch, $COMP3> for $CH3 { - type Channel = Pwm<$TIMX, C3, $COMP3>; - fn split() -> Self::Channel { - Pwm::new() - } - } - )* - $( - $( #[ $pmeta4 ] )* - impl Pins<$TIMX, Ch, $COMP4> for $CH4 { - type Channel = Pwm<$TIMX, C4, $COMP4>; - fn split() -> Self::Channel { - Pwm::new() - } - } - )* - $( - $( #[ $pmeta5 ] )* - impl NPins<$TIMX, Ch> for $CH1N {} - )* - $( - $( #[ $pmeta6 ] )* - impl NPins<$TIMX, Ch> for $CH2N {} - )* - $( - $( #[ $pmeta7 ] )* - impl NPins<$TIMX, Ch> for $CH3N {} - )* - $( - $( #[ $pmeta8 ] )* - impl NPins<$TIMX, Ch> for $CH4N {} - )* - $( - $( #[ $pmeta9 ] )* - impl FaultPins<$TIMX> for $BRK { - const INPUT: BreakInput = BreakInput::BreakIn; - } - )* - $( - $( #[ $pmeta10 ] )* - impl FaultPins<$TIMX> for $BRK2 { - const INPUT: BreakInput = BreakInput::BreakIn2; - } - )* - )+ - } -} // Period and prescaler calculator for 32-bit timers // Returns (arr, psc) fn calculate_frequency_32bit( @@ -1026,16 +874,16 @@ tim_hal! { pac::TIM7: (tim7, Tim7, u16, 16), } -#[cfg(feature="rm0481")] +#[cfg(feature = "rm0481")] tim_hal! { pac::TIM4: (tim4, Tim4, u16, 16, DIR: cms), pac::TIM5: (tim5, Tim5, u32, 32, DIR: cms), pac::TIM8: (tim8, Tim8, u16, 16, DIR: cms, BDTR: bdtr, enabled, af1, clear_bit, clear_bit), //pac::TIM12: (tim12, Tim12, u16, 16), - pac::TIM15: (tim15, Tim15, u16, 16, BDTR: bdtr, set_bit, af1, set_bit), + pac::TIM15: (tim15, Tim15, u16, 16, BDTR: bdtr, set_bit, af1, set_bit), } // TODO: TIM12 seems to be missing for 523's pac, re add once fixed -#[cfg(feature="h56x_h573")] +#[cfg(feature = "h56x_h573")] tim_hal! { pac::TIM13: (tim13, Tim13, u16, 16), pac::TIM14: (tim14, Tim14, u16, 16), @@ -1241,7 +1089,7 @@ tim_pin_hal! { (C1, ccmr1_output, oc1pe, oc1m), (C2, ccmr1_output, oc2pe, oc2m), }*/ // TODO: TIM12 seems to be missing for 523's pac, re add once fixed -#[cfg(feature="rm0481")] +#[cfg(feature = "rm0481")] tim_pin_hal! { pac::TIM15, u16, ccne: (C1, ccmr1_output, oc1pe, oc1m), @@ -1249,19 +1097,19 @@ tim_pin_hal! { } // Single channel timers -#[cfg(feature="h56x_h573")] +#[cfg(feature = "h56x_h573")] tim_pin_hal! { pac::TIM13, u16: (C1, ccmr1_output, oc1pe, oc1m), } -#[cfg(feature="h56x_h573")] +#[cfg(feature = "h56x_h573")] tim_pin_hal! { pac::TIM14, u16: (C1, ccmr1_output, oc1pe, oc1m), } -#[cfg(feature="h56x_h573")] +#[cfg(feature = "h56x_h573")] tim_pin_hal! { pac::TIM16, u16: (C1, ccmr1_output, oc1pe, oc1m), } -#[cfg(feature="h56x_h573")] +#[cfg(feature = "h56x_h573")] tim_pin_hal! { pac::TIM17, u16: (C1, ccmr1_output, oc1pe, oc1m), } @@ -1288,7 +1136,7 @@ tim_pin_hal! { (C3, ccmr2_output, oc3pe, oc3m), (C4, ccmr2_output, oc4pe, oc4m), } -#[cfg(feature="rm0481")] +#[cfg(feature = "rm0481")] tim_pin_hal! { pac::TIM4, u16: (C1, ccmr1_output, oc1pe, oc1m), @@ -1296,7 +1144,7 @@ tim_pin_hal! { (C3, ccmr2_output, oc3pe, oc3m), (C4, ccmr2_output, oc4pe, oc4m), } -#[cfg(feature="rm0481")] +#[cfg(feature = "rm0481")] tim_pin_hal! { pac::TIM5, u32: (C1, ccmr1_output, oc1pe, oc1m), @@ -1304,7 +1152,7 @@ tim_pin_hal! { (C3, ccmr2_output, oc3pe, oc3m), (C4, ccmr2_output, oc4pe, oc4m), } -#[cfg(feature="rm0481")] +#[cfg(feature = "rm0481")] tim_pin_hal! { pac::TIM8, u16, ccne: (C1, ccmr1_output, oc1pe, oc1m), diff --git a/src/timer.rs b/src/timer.rs index b548ab7..058dd21 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -11,14 +11,10 @@ use core::marker::PhantomData; use crate::stm32::{TIM1, TIM2, TIM3, TIM6, TIM7}; -#[cfg(feature = "rm0481")] -use crate::stm32::{ - TIM4, TIM5, TIM8, /*TIM12,*/ TIM15, -}; // TODO: TIM12 seems to be missing for 523's pac, re add once fixed #[cfg(feature = "h56x_h573")] -use crate::stm32::{ - TIM13, TIM14, TIM16, TIM17, -}; +use crate::stm32::{TIM13, TIM14, TIM16, TIM17}; +#[cfg(feature = "rm0481")] +use crate::stm32::{/*TIM12,*/ TIM15, TIM4, TIM5, TIM8}; // TODO: TIM12 seems to be missing for 523's pac, re add once fixed use cast::{u16, u32}; use void::Void; @@ -58,6 +54,7 @@ impl_tim_ker_ck! { #[cfg(feature = "h56x_h573")] impl_tim_ker_ck! { timx_ker_ck: TIM13, TIM14 + timy_ker_ck: TIM16, TIM17 } /// External trait for hardware timers From 8b5f45fd1e7c3e65a48555d51e85326e80aa6beb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Sn=C3=B6man?= Date: Thu, 11 Sep 2025 13:05:14 +0200 Subject: [PATCH 11/12] Added listen and clear interrupt to pwm --- src/pwm/mod.rs | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/pwm/mod.rs b/src/pwm/mod.rs index 2e82357..9d13f82 100644 --- a/src/pwm/mod.rs +++ b/src/pwm/mod.rs @@ -174,7 +174,7 @@ use crate::pac; use crate::rcc::{rec, CoreClocks, ResetEnable}; use crate::time::{Hertz, NanoSeconds}; -use crate::timer::GetClk; +use crate::timer::{GetClk, Event}; use fugit::ExtU32; // This trait marks that a GPIO pin can be used with a specific timer channel @@ -842,6 +842,49 @@ macro_rules! tim_hal { } } + impl PwmControl<$TIMX, F> { + /// Start listening for `event` + pub fn listen(&mut self, event: Event) { + match event { + Event::TimeOut => { + let tim = unsafe { <$TIMX>::steal() }; + // Enable update event interrupt + tim.dier().write(|w| w.uie().set_bit()); + } + } + } + + /// Stop listening for `event` + pub fn unlisten(&mut self, event: Event) { + match event { + Event::TimeOut => { + let tim = unsafe { <$TIMX>::steal() }; + // Disable update event interrupt + tim.dier().write(|w| w.uie().clear_bit()); + let _ = tim.dier().read(); + let _ = tim.dier().read(); // Delay 2 peripheral clocks + } + } + } + + /// Check if Update Interrupt flag is cleared + pub fn is_irq_clear(&mut self) -> bool { + let tim = unsafe { <$TIMX>::steal() }; + tim.sr().read().uif().bit_is_clear() + } + + /// Clears interrupt flag + pub fn clear_irq(&mut self) { + let tim = unsafe { <$TIMX>::steal() }; + tim.sr().modify(|_, w| { + // Clears timeout event + w.uif().clear_bit() + }); + let _ = tim.sr().read(); + let _ = tim.sr().read(); // Delay 2 peripheral clocks + } + } + impl FaultMonitor for PwmControl<$TIMX, FaultEnabled> { fn is_fault_active(&self) -> bool { let tim = unsafe { &*<$TIMX>::ptr() }; From 9f69f0e8b37b15f6af88c5f3a1573cf08cd55d0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Sn=C3=B6man?= Date: Thu, 11 Sep 2025 13:43:12 +0200 Subject: [PATCH 12/12] Moved functions.. --- src/pwm/mod.rs | 86 +++++++++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/src/pwm/mod.rs b/src/pwm/mod.rs index 9d13f82..c9d4cdb 100644 --- a/src/pwm/mod.rs +++ b/src/pwm/mod.rs @@ -823,6 +823,49 @@ macro_rules! tim_hal { )? } + impl PwmControl<$TIMX, F> { + /// Start listening for `event` + pub fn listen(&mut self, event: Event) { + match event { + Event::TimeOut => { + let tim = unsafe { <$TIMX>::steal() }; + // Enable update event interrupt + tim.dier().write(|w| w.uie().set_bit()); + } + } + } + + /// Stop listening for `event` + pub fn unlisten(&mut self, event: Event) { + match event { + Event::TimeOut => { + let tim = unsafe { <$TIMX>::steal() }; + // Disable update event interrupt + tim.dier().write(|w| w.uie().clear_bit()); + let _ = tim.dier().read(); + let _ = tim.dier().read(); // Delay 2 peripheral clocks + } + } + } + + /// Check if Update Interrupt flag is cleared + pub fn is_irq_clear(&mut self) -> bool { + let tim = unsafe { <$TIMX>::steal() }; + tim.sr().read().uif().bit_is_clear() + } + + /// Clears interrupt flag + pub fn clear_irq(&mut self) { + let tim = unsafe { <$TIMX>::steal() }; + tim.sr().modify(|_, w| { + // Clears timeout event + w.uif().clear_bit() + }); + let _ = tim.sr().read(); + let _ = tim.sr().read(); // Delay 2 peripheral clocks + } + } + // Timers with break/fault, dead time, and complimentary capabilities $( impl PwmBuilder<$TIMX, PINS, CHANNEL, FaultDisabled, COMP, $typ> { @@ -842,49 +885,6 @@ macro_rules! tim_hal { } } - impl PwmControl<$TIMX, F> { - /// Start listening for `event` - pub fn listen(&mut self, event: Event) { - match event { - Event::TimeOut => { - let tim = unsafe { <$TIMX>::steal() }; - // Enable update event interrupt - tim.dier().write(|w| w.uie().set_bit()); - } - } - } - - /// Stop listening for `event` - pub fn unlisten(&mut self, event: Event) { - match event { - Event::TimeOut => { - let tim = unsafe { <$TIMX>::steal() }; - // Disable update event interrupt - tim.dier().write(|w| w.uie().clear_bit()); - let _ = tim.dier().read(); - let _ = tim.dier().read(); // Delay 2 peripheral clocks - } - } - } - - /// Check if Update Interrupt flag is cleared - pub fn is_irq_clear(&mut self) -> bool { - let tim = unsafe { <$TIMX>::steal() }; - tim.sr().read().uif().bit_is_clear() - } - - /// Clears interrupt flag - pub fn clear_irq(&mut self) { - let tim = unsafe { <$TIMX>::steal() }; - tim.sr().modify(|_, w| { - // Clears timeout event - w.uif().clear_bit() - }); - let _ = tim.sr().read(); - let _ = tim.sr().read(); // Delay 2 peripheral clocks - } - } - impl FaultMonitor for PwmControl<$TIMX, FaultEnabled> { fn is_fault_active(&self) -> bool { let tim = unsafe { &*<$TIMX>::ptr() };