From 473e9cb85e217d71b5cfeefad920777a934d4acf Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Tue, 3 Dec 2024 12:55:37 +0100 Subject: [PATCH 01/25] Same code as stm32-rs/stm32g4xx-hal#146 commit 'Bump pac' 558969 , wich updates the pac to 0.19.0 --- src/adc_trigger.rs | 23 ++ src/capture.rs | 265 ++++++++++++++ src/compare_register.rs | 186 ++++++++++ src/control.rs | 377 +++++++++++++++++++ src/deadtime.rs | 79 ++++ src/event.rs | 17 + src/event.rs_old | 619 +++++++++++++++++++++++++++++++ src/external_event.rs | 367 +++++++++++++++++++ src/fault.rs | 270 ++++++++++++++ src/mod.rs | 782 ++++++++++++++++++++++++++++++++++++++++ src/output.rs | 220 +++++++++++ src/timer.rs | 355 ++++++++++++++++++ src/timer_eev_cfg.rs | 194 ++++++++++ 13 files changed, 3754 insertions(+) create mode 100644 src/adc_trigger.rs create mode 100644 src/capture.rs create mode 100644 src/compare_register.rs create mode 100644 src/control.rs create mode 100644 src/deadtime.rs create mode 100644 src/event.rs create mode 100644 src/event.rs_old create mode 100644 src/external_event.rs create mode 100644 src/fault.rs create mode 100644 src/mod.rs create mode 100644 src/output.rs create mode 100644 src/timer.rs create mode 100644 src/timer_eev_cfg.rs diff --git a/src/adc_trigger.rs b/src/adc_trigger.rs new file mode 100644 index 0000000..6238501 --- /dev/null +++ b/src/adc_trigger.rs @@ -0,0 +1,23 @@ +use core::marker::PhantomData; + +pub trait Adc13Trigger { + const BITS: u32; +} + +pub trait Adc24Trigger { + const BITS: u32; +} + +pub trait Adc579Trigger { + const BITS: u32; +} + +pub trait Adc6810Trigger { + const BITS: u32; +} + +/// Handle to timers reset/roll-over event +pub struct TimerReset(pub(crate) PhantomData); + +/// Handle to timers period event +pub struct TimerPeriod(pub(crate) PhantomData); diff --git a/src/capture.rs b/src/capture.rs new file mode 100644 index 0000000..eb1d047 --- /dev/null +++ b/src/capture.rs @@ -0,0 +1,265 @@ +use super::timer; +use crate::dma::mux::DmaMuxResources; +use crate::dma::traits::TargetAddress; +use crate::dma::PeripheralToMemory; +use crate::stm32::{HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF}; +use core::marker::PhantomData; + +pub struct Ch1; +pub struct Ch2; + +pub struct Dma; +pub struct NoDma; + +/// Type alias for the default capture for channel 1 +pub type HrCaptCh1 = HrCapt; + +/// Type alias for the default capture for channel 2 +pub type HrCaptCh2 = HrCapt; + +pub struct HrCapt { + _x: PhantomData<(TIM, PSCL, CH, DMA)>, +} + +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Copy, Clone, Debug)] +pub enum CountingDirection { + Up = 0, + Down = 1, +} + +/// Implemented for +/// * TIM's update event +/// * EEVT1-10 +/// +/// TODO: +/// * All neighbor timers CMP1, CPM2, OUT1_RST and OUT1_SET events +pub trait CaptureEvent { + const BITS: u32; +} + +/// Trait for capture channels used for capturing edges +/// +/// ``` +/// let capture: HrCapt<_, _, _> = todo!(); +/// if capture.is_pending() { +/// let (value, dir) = capture.get_last(); +/// capture.clear_interrupt(); +/// defmt::info!("Edge captured at counter value: {}, with: {}", value, dir); +/// } +/// ``` +/// +/// or alternatively +/// +/// ``` +/// let capture: HrCapt<_, _, _> = todo!(); +/// if let Some((value, dir)) = capture.get() { +/// defmt::info!("Edge captured at counter value: {}, with: {}", value, dir); +/// } +/// ``` +pub trait HrCapture { + /// Try to get the capture value + /// + /// Returns none if edge has been captured since last time + /// + /// NOTE: This function will use [`Self::is_pending`] to chech if there is a value available and + /// [`Self::clear_interrupt`] to clear it. + fn get(&mut self) -> Option<(u16, CountingDirection)> { + if self.is_pending() { + let value = self.get_last(); + self.clear_interrupt(); + Some(value) + } else { + None + } + } + + /// Get number of ticks relative to beginning of upcounting + /// + /// where captures during down counting count as negative (before the upcount) + /// + /// ```txt + /// Counter + /// ---------------------------------- <--- period + /// \ ^ / + /// \ | / + /// \ | / + /// \ | / + /// Down count \ | / Up count + /// \|/ + /// <-------------- 0 --------------> t + /// Negative result | positive result + /// ``` + /// + /// NOTE: This function will use [`Self::is_pending`] to chech if there is a value available and + /// [`Self::clear_interrupt`] to clear it. + fn get_signed(&mut self, period: u16) -> Option { + if self.is_pending() { + let value = self.get_last_signed(period); + self.clear_interrupt(); + Some(value) + } else { + None + } + } + + fn get_last(&self) -> (u16, CountingDirection); + + /// Get number of ticks relative to beginning of upcounting + /// + /// where captures during down counting count as negative (before the upcount) + /// + /// ``` + /// Counter + /// ---------------------------------- <--- period + /// \ ^ / + /// \ | / + /// \ | / + /// \ | / + /// Down count \ | / Up count + /// \|/ + /// <-------------- 0 --------------> t + /// Negative result | positive result + /// ``` + fn get_last_signed(&self, period: u16) -> i32 { + let (value, dir) = self.get_last(); + + // The capture counter always counts up and restarts at period + match dir { + CountingDirection::Up => i32::from(value), + CountingDirection::Down => i32::from(value) - i32::from(period), + } + } + + fn clear_interrupt(&mut self); + + fn is_pending(&self) -> bool; +} + +pub fn dma_value_to_dir_and_value(x: u32) -> (u16, CountingDirection) { + let value = (x & 0xFFFF) as u16; + match x & (1 << 16) != 0 { + true => (value, CountingDirection::Down), + false => (value, CountingDirection::Up), + } +} + +pub fn dma_value_to_signed(x: u32, period: u16) -> i32 { + let (value, dir) = dma_value_to_dir_and_value(x); + + // The capture counter always counts up and restarts at period + match dir { + CountingDirection::Up => i32::from(value), + CountingDirection::Down => i32::from(value) - i32::from(period), + } +} + +macro_rules! impl_capture { + ($($TIMX:ident),+) => {$( + impl_capture!($TIMX: Ch1, cpt1r, cpt1cr, cpt1, cpt1ie, cpt1de, cpt1c); + impl_capture!($TIMX: Ch2, cpt2r, cpt2cr, cpt2, cpt2ie, cpt2de, cpt2c); + )+}; + + ($TIMX:ident: $CH:ident, $cptXr:ident, $cptXcr:ident, $cptX:ident, $cptXie:ident, $cptXde:ident, $cptXc:ident) => { + impl HrCapt<$TIMX, PSCL, $CH, NoDma> { + /// Add event to capture + /// + /// If multiple events are added, they will be ORed together meaning + /// that a capture will be trigger if any one of the events triggers + pub fn add_event>(&mut self, _event: &E) { + let tim = unsafe { &*$TIMX::ptr() }; + + // SAFETY: We are the only one with access to cptXYcr + unsafe { + tim.$cptXcr().modify(|r, w| w.bits(r.bits() | E::BITS)); + } + } + + /// Remove event to capture + pub fn remove_event>(&mut self, _event: &E) { + let tim = unsafe { &*$TIMX::ptr() }; + + // SAFETY: We are the only one with access to cptXYcr + unsafe { + tim.$cptXcr().modify(|r, w| w.bits(r.bits() & !E::BITS)); + } + } + + /// Force capture trigger now + pub fn trigger_now(&mut self) { + // SAFETY: We are the only one with access to cptXYcr + let tim = unsafe { &*$TIMX::ptr() }; + + tim.$cptXcr().modify(|_, w| w.swcpt().set_bit()); + } + + // TODO: It would be sufficient to instead of hr_control only require exclusive access to the owning timer + // however that would be hard to do since typically the capture device is a field of that same timer. + // Would it make more sense to have this method direcly on HrTim instead? + pub fn enable_interrupt(&mut self, enable: bool, _hr_control: &mut super::HrPwmControl) { + let tim = unsafe { &*$TIMX::ptr() }; + + tim.dier().modify(|_r, w| w.$cptXie().bit(enable)); + } + + pub fn enable_dma(self, _ch: timer::DmaChannel<$TIMX>) -> HrCapt<$TIMX, PSCL, $CH, Dma> { + // SAFETY: We own the only insance of this timers dma channel, no one else can do this + let tim = unsafe { &*$TIMX::ptr() }; + tim.dier().modify(|_r, w| w.$cptXde().set_bit()); + HrCapt { + _x: PhantomData + } + } + } + + impl HrCapture for HrCapt<$TIMX, PSCL, $CH, DMA> { + fn get_last(&self) -> (u16, CountingDirection) { + let tim = unsafe { &*$TIMX::ptr() }; + let data = tim.$cptXr().read(); + + let dir = match data.dir().bit() { + true => CountingDirection::Down, + false => CountingDirection::Up, + }; + let value = data.cpt().bits(); + + (value, dir) + } + + fn clear_interrupt(&mut self) { + let tim = unsafe { &*$TIMX::ptr() }; + + // No need for exclusive access since this is a write only register + tim.icr().write(|w| w.$cptXc().clear()); + } + + fn is_pending(&self) -> bool { + let tim = unsafe { &*$TIMX::ptr() }; + + // No need for exclusive access since this is a read only register + tim.isr().read().$cptX().bit() + } + } + + unsafe impl TargetAddress for HrCapt<$TIMX, PSCL, $CH, Dma> { + #[inline(always)] + fn address(&self) -> u32 { + let tim = unsafe { &*$TIMX::ptr() }; + &tim.$cptXr() as *const _ as u32 + } + + type MemSize = u32; + + const REQUEST_LINE: Option = Some(DmaMuxResources::$TIMX as u8); + } + }; +} + +impl_capture! { + HRTIM_TIMA, + HRTIM_TIMB, + HRTIM_TIMC, + HRTIM_TIMD, + HRTIM_TIME, + HRTIM_TIMF +} diff --git a/src/compare_register.rs b/src/compare_register.rs new file mode 100644 index 0000000..0b54c74 --- /dev/null +++ b/src/compare_register.rs @@ -0,0 +1,186 @@ +use core::marker::PhantomData; + +use crate::stm32::{ + HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF, +}; + +pub trait HrCompareRegister { + fn get_duty(&self) -> u16; + fn set_duty(&mut self, duty: u16); +} + +pub struct HrCr1(PhantomData<(TIM, PSCL)>); +pub struct HrCr2(PhantomData<(TIM, PSCL)>); +pub struct HrCr3(PhantomData<(TIM, PSCL)>); +pub struct HrCr4(PhantomData<(TIM, PSCL)>); + +use super::adc_trigger::Adc13Trigger as Adc13; +use super::adc_trigger::Adc24Trigger as Adc24; +use super::adc_trigger::Adc579Trigger as Adc579; +use super::adc_trigger::Adc6810Trigger as Adc6810; + +macro_rules! hrtim_cr_helper { + (HRTIM_MASTER: $cr_type:ident: + $cmpXYr:ident, + [$(($Trigger:ty: $trigger_bits:expr)),*], + [$(($event_dst:ident, $tim_event_index:expr)),*], + $bit_index:literal + ) => { + // Strip bit_index since master timer has other bits that are common across all destinations + hrtim_cr_helper!(HRTIM_MASTER: $cr_type: $cmpXYr, [$(($Trigger: $trigger_bits)),*], [$(($event_dst, $tim_event_index)),*]); + }; + + ($TIMX:ident: $cr_type:ident: + $cmpXYr:ident, + [$(($Trigger:ty: $trigger_bits:expr)),*], + [$(($event_dst:ident, $tim_event_index:expr)),*] + $(, $bit_index:literal)* + ) => { + impl HrCompareRegister for $cr_type<$TIMX, PSCL> { + fn get_duty(&self) -> u16 { + let tim = unsafe { &*$TIMX::ptr() }; + + tim.$cmpXYr().read().cmp().bits() + } + fn set_duty(&mut self, duty: u16) { + let tim = unsafe { &*$TIMX::ptr() }; + + tim.$cmpXYr().write(|w| unsafe { w.cmp().bits(duty) }); + } + } + + $( + /// Compare match event + impl super::event::EventSource<$TIMX, PSCL> for $cr_type<$TIMX, PSCL> { + const BITS: u32 = 1 << $bit_index; + } + )* + + $( + /// Compare match event for neighbor timer + impl super::event::EventSource<$event_dst, PSCL> for $cr_type<$TIMX, PSCL> { + const BITS: u32 = 1 << ($tim_event_index + 11); // TIMEVNT1 is at bit 12, TIMEVNT2 at bit 13 etc + } + )* + + $( + impl $Trigger for $cr_type<$TIMX, PSCL> { + const BITS: u32 = $trigger_bits; + } + )* + }; +} + +macro_rules! hrtim_cr { + ($($TIMX:ident: [ + [$(($cr1_trigger:ident: $cr1_trigger_bits:expr)),*], [$(($cr1_event_dst:ident, $cr1_tim_event_index:expr)),*], + [$(($cr2_trigger:ident: $cr2_trigger_bits:expr)),*], [$(($cr2_event_dst:ident, $cr2_tim_event_index:expr)),*], + [$(($cr3_trigger:ident: $cr3_trigger_bits:expr)),*], [$(($cr3_event_dst:ident, $cr3_tim_event_index:expr)),*], + [$(($cr4_trigger:ident: $cr4_trigger_bits:expr)),*], [$(($cr4_event_dst:ident, $cr4_tim_event_index:expr)),*] + ]),+) => {$( + hrtim_cr_helper!($TIMX: HrCr1: cmp1r, [$(($cr1_trigger: $cr1_trigger_bits)),*], [$(($cr1_event_dst, $cr1_tim_event_index)),*], 3); + hrtim_cr_helper!($TIMX: HrCr2: cmp2r, [$(($cr2_trigger: $cr2_trigger_bits)),*], [$(($cr2_event_dst, $cr2_tim_event_index)),*], 4); + hrtim_cr_helper!($TIMX: HrCr3: cmp3r, [$(($cr3_trigger: $cr3_trigger_bits)),*], [$(($cr3_event_dst, $cr3_tim_event_index)),*], 5); + hrtim_cr_helper!($TIMX: HrCr4: cmp4r, [$(($cr4_trigger: $cr4_trigger_bits)),*], [$(($cr4_event_dst, $cr4_tim_event_index)),*], 6); + )+}; +} + +// See RM0440 Table 218. 'Events mapping across timer A to F' +hrtim_cr! { + HRTIM_MASTER: [ + [(Adc13: 1 << 0), (Adc24: 1 << 0), (Adc579: 0), (Adc6810: 0) ], [], + [(Adc13: 1 << 1), (Adc24: 1 << 1), (Adc579: 1), (Adc6810: 1) ], [], + [(Adc13: 1 << 2), (Adc24: 1 << 2), (Adc579: 2), (Adc6810: 2) ], [], + [(Adc13: 1 << 3), (Adc24: 1 << 3), (Adc579: 3), (Adc6810: 3) ], [] + ], + + HRTIM_TIMA: [ + [ ], [(HRTIM_TIMB, 1), (HRTIM_TIMD, 1) ], + [ (Adc24: 1 << 10), (Adc6810: 10)], [(HRTIM_TIMB, 2), (HRTIM_TIMC, 1) ], + [(Adc13: 1 << 11), (Adc579: 10) ], [(HRTIM_TIMC, 2), (HRTIM_TIMF, 1) ], + [(Adc13: 1 << 12), (Adc24: 1 << 12), (Adc579: 11), (Adc6810: 11)], [(HRTIM_TIMD, 2), (HRTIM_TIME, 1) ] + ], + + HRTIM_TIMB: [ + [ ], [(HRTIM_TIMA, 1), (HRTIM_TIMF, 2) ], + [ (Adc24: 1 << 14), (Adc6810: 13)], [(HRTIM_TIMA, 2), (HRTIM_TIMC, 3), (HRTIM_TIMD, 3)], + [(Adc13: 1 << 16), (Adc579: 14) ], [(HRTIM_TIMC, 4), (HRTIM_TIME, 2) ], + [(Adc13: 1 << 17), (Adc24: 1 << 16), (Adc579: 15), (Adc6810: 14)], [(HRTIM_TIMD, 4), (HRTIM_TIME, 3), (HRTIM_TIMF, 3)] + ], + + HRTIM_TIMC: [ + [ ], [(HRTIM_TIME, 4), (HRTIM_TIMF, 4) ], + [ (Adc24: 1 << 18), (Adc6810: 16)], [(HRTIM_TIMA, 3), (HRTIM_TIME, 5) ], + [(Adc13: 1 << 21), (Adc579: 18) ], [(HRTIM_TIMA, 4), (HRTIM_TIMB, 3) ], + [(Adc13: 1 << 22), (Adc24: 1 << 20), (Adc579: 19), (Adc6810: 17)], [(HRTIM_TIMB, 4), (HRTIM_TIMD, 5), (HRTIM_TIMF, 5)] + ], + + HRTIM_TIMD: [ + [ ], [(HRTIM_TIMA, 5), (HRTIM_TIME, 6) ], + [ (Adc24: 1 << 23), (Adc6810: 20)], [(HRTIM_TIMA, 6), (HRTIM_TIMC, 5), (HRTIM_TIME, 7)], + [(Adc13: 1 << 25), (Adc579: 21) ], [(HRTIM_TIMB, 5), (HRTIM_TIMF, 6) ], + [(Adc13: 1 << 26), (Adc24: 1 << 25), (Adc579: 22), (Adc6810: 21)], [(HRTIM_TIMB, 6), (HRTIM_TIMC, 6), (HRTIM_TIMF, 7)] + ], + + HRTIM_TIME: [ + [ ], [(HRTIM_TIMB, 7), (HRTIM_TIMD, 6) ], + [ (Adc24: 1 << 28), (Adc6810: 24)], [(HRTIM_TIMB, 8), (HRTIM_TIMF, 8) ], + [(Adc13: 1 << 29), (Adc24: 1 << 29), (Adc579: 24), (Adc6810: 25)], [(HRTIM_TIMA, 7), (HRTIM_TIMC, 7), (HRTIM_TIMF, 9)], + [(Adc13: 1 << 30), (Adc24: 1 << 30), (Adc579: 25), (Adc6810: 26)], [(HRTIM_TIMA, 8), (HRTIM_TIMC, 8), (HRTIM_TIMD, 7)] + ], + + HRTIM_TIMF: [ + [ (Adc24: 1 << 15) ], [(HRTIM_TIMD, 8) ], + [(Adc13: 1 << 10), (Adc24: 1 << 11), (Adc579: 27), (Adc6810: 28)], [(HRTIM_TIMC, 9) ], + [(Adc13: 1 << 15), (Adc579: 28), (Adc6810: 29)], [(HRTIM_TIMB, 9), (HRTIM_TIMD, 9), (HRTIM_TIME, 8)], + [(Adc13: 1 << 20), (Adc24: 1 << 19), (Adc579: 29), (Adc6810: 30)], [(HRTIM_TIMA, 9), (HRTIM_TIME, 9) ] + ] +} + +macro_rules! hrtim_master_cr { + ($($cr_type:ident: $cr_index:expr),*) => {$( + /// Compare match event for neighbor timer + impl super::event::EventSource for $cr_type { + const BITS: u32 = 1 << ($cr_index + 7); // MSTCMP1 is at bit 8 etc + } + + impl super::event::TimerResetEventSource for $cr_type { + const BITS: u32 = 1 << ($cr_index + 4); // MSTCMP1 is at bit 5 + } + )*}; +} + +hrtim_master_cr! { + HrCr1: 1, + HrCr2: 2, + HrCr3: 3, + HrCr4: 4 +} + +macro_rules! hrtim_timer_rst { + ($($TIMX:ident: $cr_type:ident: $bit_index:literal),*) => {$( + impl super::event::TimerResetEventSource for $cr_type<$TIMX, PSCL> { + const BITS: u32 = 1 << $bit_index; + } + )*}; +} + +hrtim_timer_rst! { + HRTIM_TIMA: HrCr2: 2, + HRTIM_TIMA: HrCr4: 3, + + HRTIM_TIMB: HrCr2: 2, + HRTIM_TIMB: HrCr4: 3, + + HRTIM_TIMC: HrCr2: 2, + HRTIM_TIMC: HrCr4: 3, + + HRTIM_TIMD: HrCr2: 2, + HRTIM_TIMD: HrCr4: 3, + + HRTIM_TIME: HrCr2: 2, + HRTIM_TIME: HrCr4: 3, + + HRTIM_TIMF: HrCr2: 2, + HRTIM_TIMF: HrCr4: 3 +} diff --git a/src/control.rs b/src/control.rs new file mode 100644 index 0000000..57974d6 --- /dev/null +++ b/src/control.rs @@ -0,0 +1,377 @@ +use crate::{ + hrtim::fault::{ + FltMonitor1, FltMonitor2, FltMonitor3, FltMonitor4, FltMonitor5, FltMonitor6, FltMonitorSys, + }, + rcc::{Enable, Rcc, Reset}, + stm32::{HRTIM_COMMON, RCC}, +}; + +use super::{external_event::EevInputs, fault::FaultInputs}; + +pub trait HrControltExt { + fn hr_control(self, _rcc: &mut Rcc) -> HrTimOngoingCalibration; +} + +impl HrControltExt for HRTIM_COMMON { + fn hr_control(self, _rcc: &mut Rcc) -> HrTimOngoingCalibration { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + + unsafe { + let rcc_ptr = &*RCC::ptr(); + + HRTIM_COMMON::enable(rcc_ptr); + HRTIM_COMMON::reset(rcc_ptr); + } + + // Start calibration procedure + common + .dllcr() + .write(|w| w.cal().set_bit().calen().clear_bit()); + + HrTimOngoingCalibration { + adc_trigger1_postscaler: AdcTriggerPostscaler::None, + adc_trigger2_postscaler: AdcTriggerPostscaler::None, + adc_trigger3_postscaler: AdcTriggerPostscaler::None, + adc_trigger4_postscaler: AdcTriggerPostscaler::None, + + adc_trigger5_postscaler: AdcTriggerPostscaler::None, + adc_trigger6_postscaler: AdcTriggerPostscaler::None, + adc_trigger7_postscaler: AdcTriggerPostscaler::None, + adc_trigger8_postscaler: AdcTriggerPostscaler::None, + adc_trigger9_postscaler: AdcTriggerPostscaler::None, + adc_trigger10_postscaler: AdcTriggerPostscaler::None, + + flt_divider: SamplingClkDiv::None, + eev_divider: SamplingClkDiv::None, + } + } +} + +pub struct HrTimOngoingCalibration { + adc_trigger1_postscaler: AdcTriggerPostscaler, + adc_trigger2_postscaler: AdcTriggerPostscaler, + adc_trigger3_postscaler: AdcTriggerPostscaler, + adc_trigger4_postscaler: AdcTriggerPostscaler, + + adc_trigger5_postscaler: AdcTriggerPostscaler, + adc_trigger6_postscaler: AdcTriggerPostscaler, + adc_trigger7_postscaler: AdcTriggerPostscaler, + adc_trigger8_postscaler: AdcTriggerPostscaler, + adc_trigger9_postscaler: AdcTriggerPostscaler, + adc_trigger10_postscaler: AdcTriggerPostscaler, + + flt_divider: SamplingClkDiv, + eev_divider: SamplingClkDiv, +} + +impl HrTimOngoingCalibration { + /// SAFETY: Calibration needs to be done before calling this + unsafe fn init(self) { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + + let Self { + adc_trigger1_postscaler, + adc_trigger2_postscaler, + adc_trigger3_postscaler, + adc_trigger4_postscaler, + + adc_trigger5_postscaler, + adc_trigger6_postscaler, + adc_trigger7_postscaler, + adc_trigger8_postscaler, + adc_trigger9_postscaler, + adc_trigger10_postscaler, + + flt_divider, + eev_divider, + } = self; + + unsafe { + // Enable periodic calibration + // with f_hrtim at 170MHz, these settings leads to + // a period of about 6.2ms + common + .dllcr() + .modify(|_r, w| w.calrte().bits(0b00).cal().set_bit().calen().clear_bit()); + common + .fltinr2() + .write(|w| w.fltsd().bits(flt_divider as u8)); + common.eecr3().write(|w| w.eevsd().bits(eev_divider as u8)); + + common.adcps1().write(|w| { + w.adc1psc() + .bits(adc_trigger1_postscaler as u8) + .adc2psc() + .bits(adc_trigger2_postscaler as u8) + .adc3psc() + .bits(adc_trigger3_postscaler as u8) + .adc4psc() + .bits(adc_trigger4_postscaler as u8) + .adc5psc() + .bits(adc_trigger5_postscaler as u8) + }); + + common.adcps2().write(|w| { + w.adc6psc() + .bits(adc_trigger6_postscaler as u8) + .adc7psc() + .bits(adc_trigger7_postscaler as u8) + .adc8psc() + .bits(adc_trigger8_postscaler as u8) + .adc9psc() + .bits(adc_trigger9_postscaler as u8) + .adc10psc() + .bits(adc_trigger10_postscaler as u8) + }); + + // TODO: Adc trigger 5-10 + } + } + + pub fn wait_for_calibration(self) -> (HrTimCalibrated, FaultInputs, EevInputs) { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + while common.isr().read().dllrdy().bit_is_clear() { + // Wait until ready + } + + // Calibration is now done, it is safe to continue + unsafe { self.init() }; + + (HrTimCalibrated, unsafe { FaultInputs::new() }, unsafe { + EevInputs::new() + }) + } + + pub fn set_adc1_trigger_psc(mut self, post_scaler: AdcTriggerPostscaler) -> Self { + self.adc_trigger1_postscaler = post_scaler; + self + } + + pub fn set_adc2_trigger_psc(mut self, post_scaler: AdcTriggerPostscaler) -> Self { + self.adc_trigger2_postscaler = post_scaler; + self + } + + pub fn set_adc3_trigger_psc(mut self, post_scaler: AdcTriggerPostscaler) -> Self { + self.adc_trigger3_postscaler = post_scaler; + self + } + + pub fn set_adc4_trigger_psc(mut self, post_scaler: AdcTriggerPostscaler) -> Self { + self.adc_trigger4_postscaler = post_scaler; + self + } + + pub fn set_fault_sampling_division(mut self, divider: SamplingClkDiv) -> Self { + self.flt_divider = divider; + self + } + + pub fn set_eev_sampling_division(mut self, divider: SamplingClkDiv) -> Self { + self.eev_divider = divider; + self + } +} + +/// This object may be used for things that needs to be done before any timers have been started but after the calibration has been completed. Its existence is proof that no timers have started. +/// +/// Once done with setup, use the `constrain` to get a `HrPwmControl` which can be used to start the timers. +#[non_exhaustive] +pub struct HrTimCalibrated; + +impl HrTimCalibrated { + pub fn constrain(self) -> HrPwmControl { + HrPwmControl { + control: HrPwmCtrl, + fault_sys: FltMonitorSys, + fault_1: FltMonitor1, + fault_2: FltMonitor2, + fault_3: FltMonitor3, + fault_4: FltMonitor4, + fault_5: FltMonitor5, + fault_6: FltMonitor6, + + adc_trigger1: Adc1Trigger, + adc_trigger2: Adc2Trigger, + adc_trigger3: Adc3Trigger, + adc_trigger4: Adc4Trigger, + adc_trigger5: Adc5Trigger, + adc_trigger6: Adc6Trigger, + adc_trigger7: Adc7Trigger, + adc_trigger8: Adc8Trigger, + adc_trigger9: Adc9Trigger, + adc_trigger10: Adc10Trigger, + } + } +} + +impl<'a> From<&'a mut HrPwmControl> for &'a mut HrPwmCtrl { + fn from(val: &'a mut HrPwmControl) -> Self { + &mut val.control + } +} + +/// Used as a token to guarantee unique access to resources common to multiple timers +/// +/// An instance of this object can be obtained from [`HrPwmControl`].control +#[non_exhaustive] +pub struct HrPwmCtrl; + +/// Used as a token to guarantee unique access to resources common to multiple timers +#[non_exhaustive] +pub struct HrPwmControl { + pub control: HrPwmCtrl, + + pub fault_sys: FltMonitorSys, + pub fault_1: FltMonitor1, + pub fault_2: FltMonitor2, + pub fault_3: FltMonitor3, + pub fault_4: FltMonitor4, + pub fault_5: FltMonitor5, + pub fault_6: FltMonitor6, + + pub adc_trigger1: Adc1Trigger, + pub adc_trigger2: Adc2Trigger, + pub adc_trigger3: Adc3Trigger, + pub adc_trigger4: Adc4Trigger, + + pub adc_trigger5: Adc5Trigger, + pub adc_trigger6: Adc6Trigger, + pub adc_trigger7: Adc7Trigger, + pub adc_trigger8: Adc8Trigger, + pub adc_trigger9: Adc9Trigger, + pub adc_trigger10: Adc10Trigger, +} + +macro_rules! impl_adc1234_trigger { + ($($t:ident: [$trait_:ident, $adcXr:ident, $variant345:ident $(, $variant12:ident)*]),*) => {$( + #[non_exhaustive] + pub struct $t; + + impl $t { + pub fn enable_source(&mut self, _trigger: &T) { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + unsafe { + common.$adcXr().modify(|r, w| w.bits(r.bits() | T::BITS)); + } + } + } + + $(impl From<&$t> for crate::adc::config::ExternalTrigger12 { + fn from(_val: &$t) -> Self { + crate::adc::config::ExternalTrigger12::$variant12 + } + })* + + impl From<&$t> for crate::adc::config::ExternalTrigger345 { + fn from(_val: &$t) -> Self { + crate::adc::config::ExternalTrigger345::$variant345 + } + } + )*} +} + +macro_rules! impl_adc5678910_trigger { + ($($t:ident: [$trait_:ident, $adcXtrg:ident, $variant345:ident, $variant12:ident]),*) => {$( + #[non_exhaustive] + pub struct $t; + + impl $t { + pub fn enable_source(&mut self, _trigger: &T) { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + common + .adcer() + .modify(|_r, w| unsafe { w.$adcXtrg().bits(T::BITS as u8) }); + } + } + + impl From<&$t> for crate::adc::config::ExternalTrigger12 { + fn from(_val: &$t) -> Self { + crate::adc::config::ExternalTrigger12::$variant12 + } + } + + impl From<&$t> for crate::adc::config::ExternalTrigger345 { + fn from(_val: &$t) -> Self { + crate::adc::config::ExternalTrigger345::$variant345 + } + } + + )*} +} + +impl_adc1234_trigger! {// reg adc345, adc12 + Adc1Trigger: [Adc13Trigger, adc1r, Hrtim_adc_trg_1, Hrtim_adc_trg_1], + Adc2Trigger: [Adc24Trigger, adc2r, Hrtim_adc_trg_2], + Adc3Trigger: [Adc13Trigger, adc3r, Hrtim_adc_trg_3, Hrtim_adc_trg_3], + Adc4Trigger: [Adc24Trigger, adc4r, Hrtim_adc_trg_4] +} + +impl_adc5678910_trigger! { + Adc5Trigger: [Adc579Trigger, adc5trg, Hrtim_adc_trg_5, Hrtim_adc_trg_5], + Adc6Trigger: [Adc6810Trigger, adc6trg, Hrtim_adc_trg_6, Hrtim_adc_trg_6], + Adc7Trigger: [Adc579Trigger, adc7trg, Hrtim_adc_trg_7, Hrtim_adc_trg_7], + Adc8Trigger: [Adc6810Trigger, adc8trg, Hrtim_adc_trg_8, Hrtim_adc_trg_8], + Adc9Trigger: [Adc579Trigger, adc9trg, Hrtim_adc_trg_9, Hrtim_adc_trg_9], + Adc10Trigger: [Adc6810Trigger, adc10trg, Hrtim_adc_trg_10, Hrtim_adc_trg_10] +} + +use super::adc_trigger::{Adc13Trigger, Adc24Trigger, Adc579Trigger, Adc6810Trigger}; + +pub enum AdcTriggerPostscaler { + None = 0, + Div2 = 1, + Div3 = 2, + Div4 = 3, + Div5 = 4, + Div6 = 5, + Div7 = 6, + Div8 = 7, + Div9 = 8, + Div10 = 9, + Div11 = 10, + Div12 = 11, + Div13 = 12, + Div14 = 13, + Div15 = 14, + Div16 = 15, + Div17 = 16, + Div18 = 17, + Div19 = 18, + Div20 = 19, + Div21 = 20, + Div22 = 21, + Div23 = 22, + Div24 = 23, + Div25 = 24, + Div26 = 25, + Div27 = 26, + Div28 = 27, + Div29 = 28, + Div30 = 29, + Div31 = 30, + Div32 = 31, +} + +/// The divsion ratio between f_hrtim and the fault signal sampling clock for digital filters +pub enum SamplingClkDiv { + /// No division + /// + /// fault signal sampling clock f_flts = f_hrtim + None = 0b00, + + /// 1/2 + /// + /// fault signal sampling clock f_flts = f_hrtim / 2 + Two = 0b01, + + /// 1/4 + /// + /// fault signal sampling clock f_flts = f_hrtim / 4 + Four = 0b10, + + /// 1/8 + /// + /// fault signal sampling clock f_flts = f_hrtim / 8 + Eight = 0b11, +} diff --git a/src/deadtime.rs b/src/deadtime.rs new file mode 100644 index 0000000..c59c064 --- /dev/null +++ b/src/deadtime.rs @@ -0,0 +1,79 @@ +#[derive(Copy, Clone, Debug)] +pub struct DeadtimeConfig { + /// Prescaler for both rising and falling deadtime + pub(crate) prescaler: DeadtimePrescaler, + + /// 9-bits + pub(crate) deadtime_rising_value: u16, + + /// Is deadtime negative + pub(crate) deadtime_rising_sign: bool, + + /// 9-bits + pub(crate) deadtime_falling_value: u16, + + /// Is deadtime negative + pub(crate) deadtime_falling_sign: bool, +} + +impl DeadtimeConfig { + /// See RM0440 Table 221 'Deadtime resolution and max absolute values' + pub fn prescaler(mut self, value: DeadtimePrescaler) -> Self { + self.prescaler = value; + self + } + + /// Panic if value can not fit in 9 bits + pub fn deadtime_rising_value(mut self, value: u16) -> Self { + // 9 bits + assert!(value < (1 << 9)); + + self.deadtime_rising_value = value; + + self + } + + pub fn deadtime_rising_sign(mut self, is_negative: bool) -> Self { + self.deadtime_rising_sign = is_negative; + self + } + + /// Panic if value can not fit in 9 bits + pub fn deadtime_falling_value(mut self, value: u16) -> Self { + // 9 bits + assert!(value < (1 << 9)); + + self.deadtime_falling_value = value; + + self + } + + pub fn deadtime_falling_sign(mut self, is_negative: bool) -> Self { + self.deadtime_falling_sign = is_negative; + self + } +} + +impl Default for DeadtimeConfig { + fn default() -> Self { + Self { + prescaler: DeadtimePrescaler::Thrtim, + deadtime_rising_value: 170, // about 1us when f_sys = 170MHz + deadtime_rising_sign: false, + deadtime_falling_value: 170, // about 1us when f_sys = 170MHz + deadtime_falling_sign: false, + } + } +} + +#[derive(Copy, Clone, Debug)] +pub enum DeadtimePrescaler { + ThrtimDiv8 = 0b000, + ThrtimDiv4 = 0b001, + ThrtimDiv2 = 0b010, + Thrtim = 0b011, + ThrtimMul2 = 0b100, + ThrtimMul4 = 0b101, + ThrtimMul8 = 0b110, + ThrtimMul16 = 0b111, +} diff --git a/src/event.rs b/src/event.rs new file mode 100644 index 0000000..29a1f7b --- /dev/null +++ b/src/event.rs @@ -0,0 +1,17 @@ +/// Event that can be used to set/reset an output +pub trait EventSource { + const BITS: u32; +} + +/// Event that can be used reset the timer counter +/// +/// Done: +/// * [x] Eev1-10 +/// * [x] Master period +/// * [x] Master CMP1-4 +/// * [x] Cmp2, Cmp4 +/// * [x] Timer Update +/// * [ ] Neighbor timers compare events +pub trait TimerResetEventSource { + const BITS: u32; +} diff --git a/src/event.rs_old b/src/event.rs_old new file mode 100644 index 0000000..65258c1 --- /dev/null +++ b/src/event.rs_old @@ -0,0 +1,619 @@ +use core::marker::PhantomData; + +use crate::stm32::{ + HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF, +}; + +use super::{compare_register::{HrCr1, HrCr2, HrCr3, HrCr4}, external_event_old::ExternalEventSource}; +use crate::hrtim::timer::HrTim; + +macro_rules! impl_into_es { + ($dst:ident: [$(($t:ty, $ES:ident),)*]) => {$( + impl_into_es!($dst, $t, $ES); + )*}; + + ($dst:ident, $t:ty, $ES:ident) => { + impl From<&$t> for EventSource { + fn from(_: &$t) -> Self { + EventSource::$ES{ _x: PhantomData } + } + } + }; + ($dst:ident) => { + impl_into_es! { + $dst: [ + (HrCr1<$dst, PSCL>, Cr1), + (HrCr2<$dst, PSCL>, Cr2), + (HrCr3<$dst, PSCL>, Cr3), + (HrCr4<$dst, PSCL>, Cr4), + (HrTim<$dst, PSCL>, Period), + + (HrCr1, MasterCr1), + (HrCr2, MasterCr2), + (HrCr3, MasterCr3), + (HrCr4, MasterCr4), + (HrTim, MasterPeriod), + ] + } + }; +} + +impl_into_es!(HRTIM_TIMA); +impl_into_es!(HRTIM_TIMB); +impl_into_es!(HRTIM_TIMC); +impl_into_es!(HRTIM_TIMD); +impl_into_es!(HRTIM_TIME); +impl_into_es!(HRTIM_TIMF); + +macro_rules! impl_into_neighbor_es { + ( + DST: $dst:ident: [ + ($src1:ident, $cr1:ident), + ($src2:ident, $cr2:ident), + ($src3:ident, $cr3:ident), + ($src4:ident, $cr4:ident), + ($src5:ident, $cr5:ident), + ($src6:ident, $cr6:ident), + ($src7:ident, $cr7:ident), + ($src8:ident, $cr8:ident), + ($src9:ident, $cr9:ident), + ] + ) => { + impl_into_neighbor_es!($dst, $src1, $cr1, TimEvent1); + impl_into_neighbor_es!($dst, $src2, $cr2, TimEvent2); + impl_into_neighbor_es!($dst, $src3, $cr3, TimEvent3); + impl_into_neighbor_es!($dst, $src4, $cr4, TimEvent4); + impl_into_neighbor_es!($dst, $src5, $cr5, TimEvent5); + impl_into_neighbor_es!($dst, $src6, $cr6, TimEvent6); + impl_into_neighbor_es!($dst, $src7, $cr7, TimEvent7); + impl_into_neighbor_es!($dst, $src8, $cr8, TimEvent8); + impl_into_neighbor_es!($dst, $src9, $cr9, TimEvent9); + }; + + ($dst:ident, $src:ident, $cr:ident, $TimEventX:ident) => { + impl From<&$cr<$src, PSCL>> for EventSource { + fn from(_: &$cr<$src, PSCL>) -> Self { + EventSource::NeighborTimer { + n: NeighborTimerEventSource::$TimEventX { _x: PhantomData }, + } + } + } + }; +} + +impl_into_neighbor_es! { + DST: HRTIM_TIMA: [ + // src + (HRTIM_TIMB, HrCr1), + (HRTIM_TIMB, HrCr2), + (HRTIM_TIMC, HrCr2), + (HRTIM_TIMC, HrCr3), + (HRTIM_TIMD, HrCr1), + (HRTIM_TIMD, HrCr2), + (HRTIM_TIME, HrCr3), + (HRTIM_TIME, HrCr4), + (HRTIM_TIMF, HrCr4), + ] +} + +impl_into_neighbor_es! { + DST: HRTIM_TIMB: [ + // src + (HRTIM_TIMA, HrCr1), + (HRTIM_TIMA, HrCr2), + (HRTIM_TIMC, HrCr3), + (HRTIM_TIMC, HrCr4), + (HRTIM_TIMD, HrCr3), + (HRTIM_TIMD, HrCr4), + (HRTIM_TIME, HrCr1), + (HRTIM_TIME, HrCr2), + (HRTIM_TIMF, HrCr3), + ] +} + +impl_into_neighbor_es! { + DST: HRTIM_TIMC: [ + // src + (HRTIM_TIMA, HrCr2), + (HRTIM_TIMA, HrCr3), + (HRTIM_TIMB, HrCr2), + (HRTIM_TIMB, HrCr3), + (HRTIM_TIMD, HrCr2), + (HRTIM_TIMD, HrCr4), + (HRTIM_TIME, HrCr3), + (HRTIM_TIME, HrCr4), + (HRTIM_TIMF, HrCr2), + ] +} + +// TODO: Continue for TIMD, TIME and TIMF, see RM0440 Table 218. 'Events mapping across timer A to F' + +pub enum EventSource { + /// Compare match with compare register 1 of this timer + Cr1 { _x: PhantomData<(PSCL, DST)> }, + + /// Compare match with compare register 2 of this timer + Cr2 { _x: PhantomData<(PSCL, DST)> }, + + /// Compare match with compare register 3 of this timer + Cr3 { _x: PhantomData<(PSCL, DST)> }, + + /// Compare match with compare register 4 of this timer + Cr4 { _x: PhantomData<(PSCL, DST)> }, + + /// On complete period + Period { _x: PhantomData<(PSCL, DST)> }, + + /// Compare match with compare register 1 of master timer + MasterCr1 { _x: PhantomData<(PSCL, DST)> }, + + /// Compare match with compare register 2 of master timer + MasterCr2 { _x: PhantomData<(PSCL, DST)> }, + + /// Compare match with compare register 3 of master timer + MasterCr3 { _x: PhantomData<(PSCL, DST)> }, + + /// Compare match with compare register 4 of master timer + MasterCr4 { _x: PhantomData<(PSCL, DST)> }, + + /// On complete master period + MasterPeriod { _x: PhantomData<(PSCL, DST)> }, + + ExternalEvent(ExternalEventSource), // This is fine + + NeighborTimer { + n: NeighborTimerEventSource, + }, +} + +/// Compare events from neighbor timers +/// +/// See RM0440 Table 218. 'Events mapping across timer A to F' +pub enum NeighborTimerEventSource { + /// Timer event 1 + /// + /// This is different depending on destination timer: + /// |dest | source | + /// |-----|--------| + /// |TimA | B CR1 | + /// |TimB | A CR1 | + /// |TimC | A CR2 | + /// |TimD | A CR1 | + /// |TimE | A CR4 | + /// |TimF | A CR3 | + TimEvent1 { + _x: PhantomData<(PSCL, DST)>, + }, + + /// Timer event x + /// + /// This is different depending on destination timer: + /// |dest | source | + /// |-----|--------| + /// |TimA | x CRy | + /// |TimB | x CRy | + /// |TimC | x CRy | + /// |TimD | x CRy | + /// |TimE | x CRy | + /// |TimF | x CRy | + //TimEventx, + + /// Timer event 2 + /// + /// This is different depending on destination timer: + /// |dest | source | + /// |-----|--------| + /// |TimA | B CR2 | + /// |TimB | A CR2 | + /// |TimC | A CR3 | + /// |TimD | A CR4 | + /// |TimE | B CR3 | + /// |TimF | B CR1 | + TimEvent2 { + _x: PhantomData<(PSCL, DST)>, + }, + + /// Timer event 3 + /// + /// This is different depending on destination timer: + /// |dest | source | + /// |-----|--------| + /// |TimA | C CR2 | + /// |TimB | C CR3 | + /// |TimC | B CR2 | + /// |TimD | B CR2 | + /// |TimE | B CR4 | + /// |TimF | B CR4 | + TimEvent3 { + _x: PhantomData<(PSCL, DST)>, + }, + + /// Timer event 4 + /// + /// This is different depending on destination timer: + /// |dest | source | + /// |-----|--------| + /// |TimA | C CR3 | + /// |TimB | C CR4 | + /// |TimC | B CR3 | + /// |TimD | B CR4 | + /// |TimE | C CR1 | + /// |TimF | C CR1 | + TimEvent4 { + _x: PhantomData<(PSCL, DST)>, + }, + // TODO: Document those + TimEvent5 { + _x: PhantomData<(PSCL, DST)>, + }, + TimEvent6 { + _x: PhantomData<(PSCL, DST)>, + }, + TimEvent7 { + _x: PhantomData<(PSCL, DST)>, + }, + TimEvent8 { + _x: PhantomData<(PSCL, DST)>, + }, + TimEvent9 { + _x: PhantomData<(PSCL, DST)>, + }, +} + +macro_rules! hr_timer_reset_event_source_common { + ($(#[$($attrss:tt)*])* pub enum $t:ident { [COMMON], $(#[$($attrss2:tt)*] $vals:tt = 1 << $x:literal,)*}) => { + $(#[$($attrss)*])* + pub enum $t { + $(#[$($attrss2)*] $vals = 1 << $x,)* + + /// The timer counter is reset upon external event 10. + Eevnt10 = 1 << 18, + + /// The timer counter is reset upon external event 9. + Eevnt9 = 1 << 17, + + /// The timer counter is reset upon external event 8. + Eevnt8 = 1 << 16, + + /// The timer counter is reset upon external event 7. + Eevnt7 = 1 << 15, + + /// The timer counter is reset upon external event 6. + Eevnt6 = 1 << 14, + + /// The timer counter is reset upon external event 5. + Eevnt5 = 1 << 13, + + /// The timer counter is reset upon external event 4. + Eevnt4 = 1 << 12, + + /// The timer counter is reset upon external event 3. + Eevnt3 = 1 << 11, + + /// The timer counter is reset upon external event 2. + Eevnt2 = 1 << 10, + + /// The timer counter is reset upon external event 1. + Eevnt1 = 1 << 9, + + /// The timer counter is reset upon master timer compare 4 event. + MasterCmp4 = 1 << 8, + + /// The timer counter is reset upon master timer compare 3 event. + MasterCmp3 = 1 << 7, + + /// The timer counter is reset upon master timer compare 2 event. + MasterCmp2 = 1 << 6, + + /// The timer counter is reset upon master timer compare 1 event. + MasterCmp1 = 1 << 5, + + /// The timer counter is reset upon master timer period event. + MasterPeriod = 1 << 4, + + /// The timer counter is reset upon timer its own compare 4 event + Cmp4 = 1 << 3, + + /// The timer counter is reset upon timer its own compare 2 event + Cmp2 = 1 << 2, + + /// The timer counter is reset upon update event. + Update = 1 << 1, + } + }; +} + +hr_timer_reset_event_source_common!( + /// A + pub enum TimerAResetEventSource { + [COMMON], + /// The timer counter is reset upon timer F compare 2 event. + TimFCmp2 = 1 << 31, + + /// The timer counter is reset upon timer E compare 4 event. + TimECmp4 = 1 << 30, + + /// The timer counter is reset upon timer E compare 2 event. + TimECmp2 = 1 << 29, + + /// The timer counter is reset upon timer E compare 1 event. + TimECmp1 = 1 << 28, + + /// The timer counter is reset upon timer D compare 4 event. + TimDCmp4 = 1 << 27, + + /// The timer counter is reset upon timer D compare 2 event. + TimDCmp2 = 1 << 26, + + /// The timer counter is reset upon timer D compare 1 event. + TimDCmp1 = 1 << 25, + + /// The timer counter is reset upon timer C compare 4 event. + TimCCmp4 = 1 << 24, + + /// The timer counter is reset upon timer C compare 2 event. + TimCCmp2 = 1 << 23, + + /// The timer counter is reset upon timer C compare 1 event. + TimCCmp1 = 1 << 22, + + /// The timer counter is reset upon timer B compare 4 event. + TimBCmp4 = 1 << 21, + + /// The timer counter is reset upon timer B compare 2 event. + TimBCmp2 = 1 << 20, + + /// The timer counter is reset upon timer B compare 1 event. + TimBCmp1 = 1 << 19, + + /// The timer counter is reset upon timer F compare 1 event. + TimFCmp1 = 1 << 0, + } +); + +hr_timer_reset_event_source_common!( + /// B + pub enum TimerBResetEventSource { + [COMMON], + + /// The timer counter is reset upon timer F compare 2 event. + TimFCmp2 = 1 << 31, + + /// The timer counter is reset upon timer E compare 4 event. + TimECmp4 = 1 << 30, + + /// The timer counter is reset upon timer E compare 2 event. + TimECmp2 = 1 << 29, + + /// The timer counter is reset upon timer E compare 1 event. + TimECmp1 = 1 << 28, + + /// The timer counter is reset upon timer D compare 4 event. + TimDCmp4 = 1 << 27, + + /// The timer counter is reset upon timer D compare 2 event. + TimDCmp2 = 1 << 26, + + /// The timer counter is reset upon timer D compare 1 event. + TimDCmp1 = 1 << 25, + + /// The timer counter is reset upon timer C compare 4 event. + TimCCmp4 = 1 << 24, + + /// The timer counter is reset upon timer C compare 2 event. + TimCCmp2 = 1 << 23, + + /// The timer counter is reset upon timer C compare 1 event. + TimCCmp1 = 1 << 22, + + /// The timer counter is reset upon timer A compare 4 event. + TimACmp4 = 1 << 21, + + /// The timer counter is reset upon timer A compare 2 event. + TimACmp2 = 1 << 20, + + /// The timer counter is reset upon timer A compare 1 event. + TimACmp1 = 1 << 19, + + /// The timer counter is reset upon timer F compare 1 event. + TimFCmp1 = 1 << 0, + } +); + +hr_timer_reset_event_source_common!( + /// C + pub enum TimerCResetEventSource { + [COMMON], + + /// The timer counter is reset upon timer F compare 2 event. + TimFCmp2 = 1 << 31, + + /// The timer counter is reset upon timer E compare 4 event. + TimECmp4 = 1 << 30, + + /// The timer counter is reset upon timer E compare 2 event. + TimECmp2 = 1 << 29, + + /// The timer counter is reset upon timer E compare 1 event. + TimECmp1 = 1 << 28, + + /// The timer counter is reset upon timer D compare 4 event. + TimDCmp4 = 1 << 27, + + /// The timer counter is reset upon timer D compare 2 event. + TimDCmp2 = 1 << 26, + + /// The timer counter is reset upon timer D compare 1 event. + TimDCmp1 = 1 << 25, + + /// The timer counter is reset upon timer B compare 4 event. + TimBCmp4 = 1 << 24, + + /// The timer counter is reset upon timer B compare 2 event. + TimBCmp2 = 1 << 23, + + /// The timer counter is reset upon timer B compare 1 event. + TimBCmp1 = 1 << 22, + + /// The timer counter is reset upon timer A compare 4 event. + TimACmp4 = 1 << 21, + + /// The timer counter is reset upon timer A compare 2 event. + TimACmp2 = 1 << 20, + + /// The timer counter is reset upon timer A compare 1 event. + TimACmp1 = 1 << 19, + + + /// The timer counter is reset upon timer F compare 1 event. + TimFCmp1 = 1 << 0, + } +); + +hr_timer_reset_event_source_common!( + /// D + pub enum TimerDResetEventSource { + [COMMON], + + /// The timer counter is reset upon timer F compare 2 event. + TimFCmp2 = 1 << 31, + + /// The timer counter is reset upon timer E compare 4 event. + TimECmp4 = 1 << 30, + + /// The timer counter is reset upon timer E compare 2 event. + TimECmp2 = 1 << 29, + + /// The timer counter is reset upon timer E compare 1 event. + TimECmp1 = 1 << 28, + + /// The timer counter is reset upon timer C compare 4 event. + TimCCmp4 = 1 << 27, + + /// The timer counter is reset upon timer C compare 2 event. + TimCCmp2 = 1 << 26, + + /// The timer counter is reset upon timer C compare 1 event. + TimCCmp1 = 1 << 25, + + /// The timer counter is reset upon timer B compare 4 event. + TimBCmp4 = 1 << 24, + + /// The timer counter is reset upon timer B compare 2 event. + TimBCmp2 = 1 << 23, + + /// The timer counter is reset upon timer B compare 1 event. + TimBCmp1 = 1 << 22, + + /// The timer counter is reset upon timer A compare 4 event. + TimACmp4 = 1 << 21, + + /// The timer counter is reset upon timer A compare 2 event. + TimACmp2 = 1 << 20, + + /// The timer counter is reset upon timer A compare 1 event. + TimACmp1 = 1 << 19, + + /// The timer counter is reset upon timer F compare 1 event. + TimFCmp1 = 1 << 0, + } +); + +hr_timer_reset_event_source_common!( + /// E + pub enum TimerEResetEventSource { + [COMMON], + + /// The timer counter is reset upon timer F compare 2 event. + TimFCmp2 = 1 << 31, + + /// The timer counter is reset upon timer D compare 4 event. + TimDCmp4 = 1 << 30, + + /// The timer counter is reset upon timer D compare 2 event. + TimDCmp2 = 1 << 29, + + /// The timer counter is reset upon timer D compare 1 event. + TimDCmp1 = 1 << 28, + + /// The timer counter is reset upon timer C compare 4 event. + TimCCmp4 = 1 << 27, + + /// The timer counter is reset upon timer C compare 2 event. + TimCCmp2 = 1 << 26, + + /// The timer counter is reset upon timer C compare 1 event. + TimCCmp1 = 1 << 25, + + /// The timer counter is reset upon timer B compare 4 event. + TimBCmp4 = 1 << 24, + + /// The timer counter is reset upon timer B compare 2 event. + TimBCmp2 = 1 << 23, + + /// The timer counter is reset upon timer B compare 1 event. + TimBCmp1 = 1 << 22, + + /// The timer counter is reset upon timer A compare 4 event. + TimACmp4 = 1 << 21, + + /// The timer counter is reset upon timer A compare 2 event. + TimACmp2 = 1 << 20, + + /// The timer counter is reset upon timer A compare 1 event. + TimACmp1 = 1 << 19, + + + /// The timer counter is reset upon timer F compare 1 event. + TimFCmp1 = 1 << 0, + } +); + +hr_timer_reset_event_source_common!( + /// F + pub enum TimerFResetEventSource { + [COMMON], + + /// The timer counter is reset upon timer E compare 2 event. + TimECmp2 = 1 << 31, + + /// The timer counter is reset upon timer D compare 4 event. + TimDCmp4 = 1 << 30, + + /// The timer counter is reset upon timer D compare 2 event. + TimDCmp2 = 1 << 29, + + /// The timer counter is reset upon timer D compare 1 event. + TimDCmp1 = 1 << 28, + + /// The timer counter is reset upon timer C compare 4 event. + TimCCmp4 = 1 << 27, + + /// The timer counter is reset upon timer C compare 2 event. + TimCCmp2 = 1 << 26, + + /// The timer counter is reset upon timer C compare 1 event. + TimCCmp1 = 1 << 25, + + /// The timer counter is reset upon timer B compare 4 event. + TimBCmp4 = 1 << 24, + + /// The timer counter is reset upon timer B compare 2 event. + TimBCmp2 = 1 << 23, + + /// The timer counter is reset upon timer B compare 1 event. + TimBCmp1 = 1 << 22, + + /// The timer counter is reset upon timer A compare 4 event. + TimACmp4 = 1 << 21, + + /// The timer counter is reset upon timer A compare 2 event. + TimACmp2 = 1 << 20, + + /// The timer counter is reset upon timer A compare 1 event. + TimACmp1 = 1 << 19, + + /// The timer counter is reset upon timer E compare 1 event. + TimECmp1 = 1 << 0, + } +); diff --git a/src/external_event.rs b/src/external_event.rs new file mode 100644 index 0000000..74b6a53 --- /dev/null +++ b/src/external_event.rs @@ -0,0 +1,367 @@ +use crate::comparator::{COMP1, COMP2, COMP3, COMP4, COMP5, COMP6, COMP7}; +use crate::gpio::gpiob::{PB3, PB4, PB5, PB6, PB7, PB8, PB9}; +use crate::gpio::gpioc::{PC11, PC12, PC5, PC6}; +use crate::gpio::{self, AF13, AF3}; +use crate::pwm::Polarity; +use crate::stm32::HRTIM_COMMON; + +use super::control::HrTimCalibrated; + +#[non_exhaustive] +#[derive(Copy, Clone, PartialEq)] +pub struct ExternalEventSource; + +pub struct EevInputs { + pub eev_input1: EevInput<1>, + pub eev_input2: EevInput<2>, + pub eev_input3: EevInput<3>, + pub eev_input4: EevInput<4>, + pub eev_input5: EevInput<5>, + pub eev_input6: EevInput<6>, + pub eev_input7: EevInput<7>, + pub eev_input8: EevInput<8>, + pub eev_input9: EevInput<9>, + pub eev_input10: EevInput<10>, +} + +impl EevInputs { + pub(crate) unsafe fn new() -> Self { + EevInputs { + eev_input1: EevInput, + eev_input2: EevInput, + eev_input3: EevInput, + eev_input4: EevInput, + eev_input5: EevInput, + eev_input6: EevInput, + eev_input7: EevInput, + eev_input8: EevInput, + eev_input9: EevInput, + eev_input10: EevInput, + } + } +} + +#[non_exhaustive] +pub struct EevInput; + +/// This is implemented for types that can be used as inputs to the eev +/// # Safety +/// Only implement for types that can be used as sources to eev number `EEV_N` with src bits `SRC_BITS` +pub unsafe trait EevSrcBits: Sized { + const SRC_BITS: u8; + fn cfg(self) {} +} + +macro_rules! impl_eev_input { + ($N:literal: COMP=[$compX:ident $(, ($compY:ident, $compY_src_bits:literal))*], PINS=[$(($pin:ident, $af:ident)),*]) => { + $(unsafe impl EevSrcBits<$N> for $pin>{ + const SRC_BITS: u8 = 0b00; + fn cfg(self) { + self.into_alternate::<$af>(); + } + })* + + unsafe impl EevSrcBits<$N> for &crate::comparator::Comparator<$compX, ED> + where ED: crate::comparator::EnabledState + { + const SRC_BITS: u8 = 0b01; + } + + $( + unsafe impl EevSrcBits<$N> for &crate::comparator::Comparator<$compY, ED> + where ED: crate::comparator::EnabledState + { + const SRC_BITS: u8 = $compY_src_bits; + } + )* + + impl EevInput<$N> { + pub fn bind(self, src: SRC) -> SourceBuilder<$N, IS_FAST> + where SRC: EevSrcBits<$N> + { + src.cfg(); + unsafe { SourceBuilder::new(SRC::SRC_BITS) } + } + } + }; +} + +impl_eev_input!(1: COMP = [COMP2], PINS = [(PC12, AF3)]); +impl_eev_input!(2: COMP = [COMP4], PINS = [(PC11, AF3)]); +impl_eev_input!(3: COMP = [COMP6], PINS = [(PB7, AF13)]); +impl_eev_input!(4: COMP = [COMP1, (COMP5, 0b10)], PINS = [(PB6, AF13)]); +impl_eev_input!(5: COMP = [COMP3, (COMP7, 0b10)], PINS = [(PB9, AF13)]); +impl_eev_input!(6: COMP = [COMP2, (COMP1, 0b10)], PINS = [(PB5, AF13)]); +impl_eev_input!(7: COMP = [COMP4], PINS = [(PB4, AF13)]); +impl_eev_input!(8: COMP = [COMP6, (COMP3, 0b10)], PINS = [(PB8, AF13)]); +impl_eev_input!(9: COMP = [COMP5, (COMP4, 0b11)], PINS = [(PB3, AF13)]); +impl_eev_input!(10: COMP = [COMP7], PINS = [(PC5, AF13), (PC6, AF3)]); + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum EdgeOrPolarity { + Edge(Edge), + Polarity(Polarity), +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum Edge { + Rising = 0b01, + Falling = 0b10, + Both = 0b11, +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum EevSamplingFilter { + /// No filtering, fault acts asynchronously + /// + /// Note that this bypasses any f_eevs (FaultSamplingClkDiv) + None = 0b0000, + + /// Sample directly at rate f_hrtim, with a count of 2 + /// + /// Note that this bypasses: any f_eevs (FaultSamplingClkDiv) + HrtimN2 = 0b0001, + + /// Sample directly at rate f_hrtim, with a count of 4 + /// + /// Note that this bypasses any f_eevs (FaultSamplingClkDiv) + HrtimN4 = 0b0010, + + /// Sample directly at rate f_hrtim, with a count of 8 + /// + /// Note that this bypasses any f_eevs (FaultSamplingClkDiv) + HrtimN8 = 0b0011, + + /// Sample at rate f_eevs / 2, with a count of 6 + EevsDiv2N6 = 0b0100, + + /// Sample at rate f_eevs / 2, with a count of 8 + EevsDiv2N8 = 0b0101, + + /// Sample at rate f_eevs / 4, with a count of 6 + EevsDiv4N6 = 0b0110, + + /// Sample at rate f_eevs / 4, with a count of 8 + EevsDiv4N8 = 0b0111, + + /// Sample at rate f_eevs / 8, with a count of 6 + EevsDiv8N6 = 0b1000, + + /// Sample at rate f_eevs / 8, with a count of 8 + EevsDiv8N8 = 0b1001, + + /// Sample at rate f_eevs / 16, with a count of 5 + EevsDiv16N5 = 0b1010, + + /// Sample at rate f_eevs / 16, with a count of 6 + EevsDiv16N6 = 0b1011, + + /// Sample at rate f_eevs / 16, with a count of 8 + EevsDiv16N8 = 0b1100, + + /// Sample at rate f_eevs / 32, with a count of 5 + EevsDiv32N5 = 0b1101, + + /// Sample at rate f_eevs / 32, with a count of 6 + EevsDiv32N6 = 0b1110, + + /// Sample at rate f_eevs / 32, with a count of 8 + EevsDiv32N8 = 0b1111, +} + +pub trait ExternalEventBuilder1To5 {} +pub trait ExternalEventBuilder6To10 {} +pub struct SourceBuilder { + /// EExSRC + src_bits: u8, + + /// EExSNS + edge_or_polarity_bits: u8, + + /// EExPOL + polarity_bit: bool, + + /// EExF + filter_bits: u8, +} + +impl SourceBuilder { + unsafe fn new(src_bits: u8) -> Self { + Self { + src_bits, + edge_or_polarity_bits: 0, // Level sensitive + polarity_bit: false, // Active high + filter_bits: 0, // No filter + } + } +} + +impl SourceBuilder { + pub fn edge_or_polarity(mut self, edge_or_polarity: EdgeOrPolarity) -> Self { + (self.edge_or_polarity_bits, self.polarity_bit) = match edge_or_polarity { + EdgeOrPolarity::Polarity(Polarity::ActiveHigh) => (0b00, false), + EdgeOrPolarity::Polarity(Polarity::ActiveLow) => (0b00, true), + EdgeOrPolarity::Edge(Edge::Rising) => (0b01, false), + EdgeOrPolarity::Edge(Edge::Falling) => (0b10, false), + EdgeOrPolarity::Edge(Edge::Both) => (0b11, false), + }; + + self + } +} + +impl SourceBuilder { + /// Edge sensitivity not available in fast mode + pub fn polarity(mut self, polarity: Polarity) -> Self { + (self.edge_or_polarity_bits, self.polarity_bit) = match polarity { + Polarity::ActiveHigh => (0b00, false), + Polarity::ActiveLow => (0b00, true), + }; + + self + } +} + +impl SourceBuilder +where + SourceBuilder: ExternalEventBuilder6To10, +{ + pub fn filter(mut self, filter: EevSamplingFilter) -> Self { + self.filter_bits = filter as _; + self + } +} + +pub trait ToExternalEventSource { + fn finalize(self, _calibrated: &mut HrTimCalibrated) -> ExternalEventSource; +} + +macro_rules! impl_eev1_5_to_es { + ($eev:ident, $N:literal, $eeXsrc:ident, $eeXpol:ident, $eeXsns:ident, $eeXfast:ident) => { + impl ExternalEventBuilder1To5 for SourceBuilder<$N, IS_FAST> {} + + impl SourceBuilder<$N, false> { + pub fn fast(self) -> SourceBuilder<$N, true> { + let SourceBuilder { + src_bits, + edge_or_polarity_bits, + polarity_bit, + filter_bits, + } = self; + + SourceBuilder { + src_bits, + edge_or_polarity_bits, + polarity_bit, + filter_bits, + } + } + } + + impl ToExternalEventSource<$N, IS_FAST> + for SourceBuilder<$N, IS_FAST> + { + fn finalize( + self, + _calibrated: &mut HrTimCalibrated, + ) -> ExternalEventSource<$N, IS_FAST> { + let SourceBuilder { + src_bits, + edge_or_polarity_bits, + polarity_bit, + filter_bits: _, + } = self; + + let common = unsafe { &*HRTIM_COMMON::ptr() }; + + // SAFETY: Thanks to, `HrTimCalibrated`, we know we have exclusive access to the register, + // we also know no timers are started. + unsafe { + common.eecr1().modify(|_r, w| { + w.$eeXsrc() + .bits(src_bits) + .$eeXpol() + .bit(polarity_bit) + .$eeXsns() + .bits(edge_or_polarity_bits) + .$eeXfast() + .bit(IS_FAST) + }); + } + + ExternalEventSource + } + } + + /// EEV$1 event + impl super::event::EventSource + for ExternalEventSource<$N, IS_FAST> + { + const BITS: u32 = 1 << ($N + 20); // EEV1 is at bit 21 + } + }; +} + +macro_rules! impl_eev6_10_to_es { + ($eev:ident, $N:literal, $eeXsrc:ident, $eeXpol:ident, $eeXsns:ident, $eeXf:ident) => { + impl ExternalEventBuilder6To10 for SourceBuilder<$N, false> {} + + impl ToExternalEventSource<$N, false> for SourceBuilder<$N, false> { + fn finalize(self, _calibrated: &mut HrTimCalibrated) -> ExternalEventSource<$N, false> { + let SourceBuilder { + src_bits, + edge_or_polarity_bits, + polarity_bit, + filter_bits, + } = self; + + let common = unsafe { &*HRTIM_COMMON::ptr() }; + + // SAFETY: Thanks to, `HrTimCalibrated`, we know we have exclusive access to the register, + // we also know no timers are started. + unsafe { + common.eecr2().modify(|_r, w| { + w.$eeXsrc() + .bits(src_bits) + .$eeXpol() + .bit(polarity_bit) + .$eeXsns() + .bits(edge_or_polarity_bits) + }); + common.eecr3().modify(|_r, w| w.$eeXf().bits(filter_bits)); + } + + ExternalEventSource + } + } + + /// EEV$1 event + impl super::event::EventSource for ExternalEventSource<$N, false> { + const BITS: u32 = 1 << ($N + 20); // EEV1 is at bit 21 + } + }; +} + +impl_eev1_5_to_es!(Eevnt1, 1, ee1src, ee1pol, ee1sns, ee1fast); +impl_eev1_5_to_es!(Eevnt2, 2, ee2src, ee2pol, ee2sns, ee2fast); +impl_eev1_5_to_es!(Eevnt3, 3, ee3src, ee3pol, ee3sns, ee3fast); +impl_eev1_5_to_es!(Eevnt4, 4, ee4src, ee4pol, ee4sns, ee4fast); +impl_eev1_5_to_es!(Eevnt5, 5, ee5src, ee5pol, ee5sns, ee5fast); + +impl_eev6_10_to_es!(Eevnt6, 6, ee6src, ee6pol, ee6sns, ee6f); +impl_eev6_10_to_es!(Eevnt7, 7, ee7src, ee7pol, ee7sns, ee7f); +impl_eev6_10_to_es!(Eevnt8, 8, ee8src, ee8pol, ee8sns, ee8f); +impl_eev6_10_to_es!(Eevnt9, 9, ee9src, ee9pol, ee9sns, ee9f); +impl_eev6_10_to_es!(Eevnt10, 10, ee10src, ee10pol, ee10sns, ee10f); + +impl super::capture::CaptureEvent + for ExternalEventSource +{ + const BITS: u32 = 1 << (N + 1); // EEV1 is at bit #2 etc +} + +impl super::event::TimerResetEventSource + for ExternalEventSource +{ + const BITS: u32 = 1 << (N + 8); // EEV1 is at bit 9 +} diff --git a/src/fault.rs b/src/fault.rs new file mode 100644 index 0000000..c425077 --- /dev/null +++ b/src/fault.rs @@ -0,0 +1,270 @@ +use crate::comparator::{COMP1, COMP2, COMP3, COMP4, COMP5, COMP6}; +use crate::gpio::gpioa::{PA12, PA15}; +use crate::gpio::gpiob::{PB0, PB10, PB11}; +use crate::gpio::gpioc::{PC10, PC7}; +use crate::gpio::{self, AF13, AF3}; +use crate::hrtim::control::HrPwmControl; +use crate::stm32::HRTIM_COMMON; + +use super::control::HrPwmCtrl; + +/// Allows a FaultMonitor to monitor faults +pub trait FaultMonitor { + fn enable_interrupt(&mut self, hr_control: &mut HrPwmCtrl); + + /// Returns true if a fault is preventing PWM output + fn is_fault_active(&self) -> bool; + + /// Clear the fault interrupt flag + /// + /// This will *NOT* resume normal PWM operation. The affected outputs need to be re-enabled to resume operation; + /// This will do nothing if the fault is still active. + fn clear_fault(&mut self); +} + +pub enum FaultAction { + /// Output never enters fault mode + None = 0b00, + + /// Output forced to `active` level on fault + ForceActive = 0b01, + + /// Output forced to `inactive` level on fault + ForceInactive = 0b10, + + /// The output is floating/tri stated on fault + Floating = 0b11, +} + +/// # Safety +/// Only implement for actual fault sources with correct `ENABLE_BITS` +pub unsafe trait FaultSource: Copy { + const ENABLE_BITS: u8; +} + +pub struct SourceBuilder { + _input: I, + src_bits: u8, + + /// FLTxP + is_active_high: bool, + + /// FLTxF[3:0] + filter_bits: u8, +} + +impl SourceBuilder { + unsafe fn new(input: I, src_bits: u8) -> Self { + SourceBuilder { + _input: input, + src_bits, + is_active_high: false, + filter_bits: 0b0000, + } + } +} + +macro_rules! impl_faults { + ($( + $input:ident => $source:ident: + PINS=[($pin:ident, $af:ident) $(,($pin_b:ident, $af_b:ident))*], + COMP=$compX:ident, $enable_bits:literal, + $fltinrZ:ident, $fltWsrc_0:ident, $fltWsrc_1:ident, $fltWp:ident, $fltWf:ident, $fltWe:ident, $fltWlck:ident, + )+) => {$( + + // This should NOT be Copy/Clone + #[non_exhaustive] + pub struct $input; + + #[non_exhaustive] + #[derive(Copy, Clone)] + pub struct $source; + + impl $input { + pub fn bind_pin(self, pin: $pin>) -> SourceBuilder<$input> { + pin.into_alternate::<$af>(); + unsafe { SourceBuilder::new(self, 0b00) } + } + + $( + // TODO: Is there a nicer way to do this? + pub fn bind_pin_b(self, pin: $pin_b>) -> SourceBuilder<$input> { + pin.into_alternate::<$af_b>(); + unsafe { SourceBuilder::new(self, 0b00) } + } + )* + + pub fn bind_comp(self, _comp: &crate::comparator::Comparator<$compX, crate::comparator::Enabled>) -> SourceBuilder<$input> { + unsafe { SourceBuilder::new(self, 0b01) } + } + + /*pub fn bind_external(?) { + SourceBuilder::new(self, 0b10); + }*/ + } + + impl SourceBuilder<$input> { + pub fn finalize(self, _control: &mut HrPwmControl) -> $source { + let SourceBuilder{ _input, src_bits, is_active_high, filter_bits } = self; + + // Setup fault source + unsafe { + let common = &*HRTIM_COMMON::ptr(); + + common.fltinr2().modify(|_r, w| w.$fltWsrc_1().bit(src_bits & 0b10 != 0)); + common.$fltinrZ().modify(|_r, w| w + .$fltWsrc_0().bit(src_bits & 0b01 != 0) + .$fltWp().bit(is_active_high) + .$fltWf().bits(filter_bits) + .$fltWe().set_bit() // Enable + ); + + // ... and lock configuration + common.$fltinrZ().modify(|_r, w| w.$fltWlck().set_bit()); + } + + $source + } + + pub fn polarity(mut self, polarity: super::Polarity) -> Self { + self.is_active_high = polarity == super::Polarity::ActiveHigh; + self + } + + // TODO: add more settings + /* pub fn blanking(?) -> Self */ + + pub fn filter(mut self, filter: FaultSamplingFilter) -> Self { + self.filter_bits = filter as u8; + self + } + } + + unsafe impl FaultSource for $source { + const ENABLE_BITS: u8 = $enable_bits; + } + )+} +} + +impl_faults!( + FaultInput1 => FaultSource1: PINS=[(PA12, AF13)], COMP=COMP2, 0b000001, fltinr1, flt1src, flt1src_1, flt1p, flt1f, flt1e, flt1lck, + FaultInput2 => FaultSource2: PINS=[(PA15, AF13)], COMP=COMP4, 0b000010, fltinr1, flt2src, flt2src_1, flt2p, flt2f, flt2e, flt2lck, + FaultInput3 => FaultSource3: PINS=[(PB10, AF13)], COMP=COMP6, 0b000100, fltinr1, flt3src, flt3src_1, flt3p, flt3f, flt3e, flt3lck, + FaultInput4 => FaultSource4: PINS=[(PB11, AF13)], COMP=COMP1, 0b001000, fltinr1, flt4src, flt4src_1, flt4p, flt4f, flt4e, flt4lck, + FaultInput5 => FaultSource5: PINS=[(PB0, AF13), (PC7, AF3)], COMP=COMP3, 0b010000, fltinr2, flt5src, flt5src_1, flt5p, flt5f, flt5e, flt5lck, + FaultInput6 => FaultSource6: PINS=[(PC10, AF13)], COMP=COMP5, 0b100000, fltinr2, flt6src, flt6src_1, flt6p, flt6f, flt6e, flt6lck, +); + +pub struct FaultInputs { + pub fault_input1: FaultInput1, + pub fault_input2: FaultInput2, + pub fault_input3: FaultInput3, + pub fault_input4: FaultInput4, + pub fault_input5: FaultInput5, + pub fault_input6: FaultInput6, +} + +impl FaultInputs { + pub(crate) unsafe fn new() -> Self { + FaultInputs { + fault_input1: FaultInput1, + fault_input2: FaultInput2, + fault_input3: FaultInput3, + fault_input4: FaultInput4, + fault_input5: FaultInput5, + fault_input6: FaultInput6, + } + } +} + +pub enum FaultSamplingFilter { + /// No filtering, fault acts asynchronously + /// + /// Note that this bypasses any f_flts (SamplingClkDiv) + None = 0b0000, + + /// Sample directly at rate f_hrtim, with a count of 2 + /// + /// Note that this bypasses: any f_flts (SamplingClkDiv) + HrtimN2 = 0b0001, + + /// Sample directly at rate f_hrtim, with a count of 4 + /// + /// Note that this bypasses any f_flts (SamplingClkDiv) + HrtimN4 = 0b0010, + + /// Sample directly at rate f_hrtim, with a count of 8 + /// + /// Note that this bypasses any f_flts (SamplingClkDiv) + HrtimN8 = 0b0011, + + /// Sample at rate f_flts / 2, with a count of 6 + FltsDiv2N6 = 0b0100, + + /// Sample at rate f_flts / 2, with a count of 8 + FltsDiv2N8 = 0b0101, + + /// Sample at rate f_flts / 4, with a count of 6 + FltsDiv4N6 = 0b0110, + + /// Sample at rate f_flts / 4, with a count of 8 + FltsDiv4N8 = 0b0111, + + /// Sample at rate f_flts / 8, with a count of 6 + FltsDiv8N6 = 0b1000, + + /// Sample at rate f_flts / 8, with a count of 8 + FltsDiv8N8 = 0b1001, + + /// Sample at rate f_flts / 16, with a count of 5 + FltsDiv16N5 = 0b1010, + + /// Sample at rate f_flts / 16, with a count of 6 + FltsDiv16N6 = 0b1011, + + /// Sample at rate f_flts / 16, with a count of 8 + FltsDiv16N8 = 0b1100, + + /// Sample at rate f_flts / 32, with a count of 5 + FltsDiv32N5 = 0b1101, + + /// Sample at rate f_flts / 32, with a count of 6 + FltsDiv32N6 = 0b1110, + + /// Sample at rate f_flts / 32, with a count of 8 + FltsDiv32N8 = 0b1111, +} + +macro_rules! impl_flt_monitor { + ($($t:ident: ($fltx:ident, $fltxc:ident, $fltxie:ident),)+) => {$( + #[non_exhaustive] + pub struct $t; + + impl FaultMonitor for $t { + fn enable_interrupt(&mut self, _hr_control: &mut HrPwmCtrl) { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + common.ier().modify(|_r, w| w.$fltxie().set_bit()); + } + + fn is_fault_active(&self) -> bool { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + common.isr().read().$fltx().bit() + } + + fn clear_fault(&mut self) { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + common.icr().write(|w| w.$fltxc().clear()); + } + } + )+}; +} + +impl_flt_monitor!( + FltMonitorSys: (sysflt, sysfltc, sysfltie), + FltMonitor1: (flt1, flt1c, flt1ie), + FltMonitor2: (flt2, flt2c, flt2ie), + FltMonitor3: (flt3, flt3c, flt3ie), + FltMonitor4: (flt4, flt4c, flt4ie), + FltMonitor5: (flt5, flt5c, flt5ie), + FltMonitor6: (flt6, flt6c, flt6ie), +); diff --git a/src/mod.rs b/src/mod.rs new file mode 100644 index 0000000..d07ef3c --- /dev/null +++ b/src/mod.rs @@ -0,0 +1,782 @@ +pub mod adc_trigger; +pub mod capture; +pub mod compare_register; +pub mod control; +pub mod deadtime; +pub mod event; +pub mod external_event; +pub mod fault; +pub mod output; +pub mod timer; +pub mod timer_eev_cfg; + +use core::marker::PhantomData; +use core::mem::MaybeUninit; + +use crate::hrtim::compare_register::{HrCr1, HrCr2, HrCr3, HrCr4}; +use crate::hrtim::fault::{FaultAction, FaultSource}; +use crate::hrtim::timer::HrTim; +use crate::stm32::{ + HRTIM_COMMON, HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, + HRTIM_TIMF, +}; +use capture::{HrCaptCh1, HrCaptCh2}; +use fugit::HertzU64; + +use self::control::HrPwmControl; + +use self::deadtime::DeadtimeConfig; +use self::output::ToHrOut; +use self::timer_eev_cfg::EevCfgs; + +use crate::pwm::{self, Alignment, Polarity, TimerType}; +use crate::rcc::{GetBusFreq, Rcc}; +use crate::time::Hertz; + +/// Internal enum that keeps track of the count settings before PWM is finalized +enum CountSettings { + Frequency(Hertz), + Period(u16), +} + +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum HrTimerMode { + SingleShotNonRetriggerable, + SingleShotRetriggerable, + Continuous, +} + +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum HrCountingDirection { + /// Asymetrical up counting mode + /// + /// + + /// * * + /// Counting up * | * | + /// * * + /// * | * | + /// * * + /// * | * | + /// * * + /// -------------------------------------- + /// + /// ```txt + /// | *-------* *------ + /// | | | + /// | | | | + /// | | | + /// ----------* *------------------* + /// ``` + /// + /// This is the most common mode with least amount of quirks + Up, + + /// Symmetrical up-down counting mode + /// + /// + /// ```txt + /// Period--> * Counting * + /// Counting up * | * Counting Up * | + /// * * down * + /// * | * * | + /// * * * + /// * | * * | + /// 0 -->* * + /// --------------------------------------------------------------------------- + /// | *---------------* | *---------------* + /// | | | | | | + /// | | | | | | + /// | | | | | | + /// ----------* *-------------------* *--- + /// ``` + /// + /// NOTE: This is incompatible with + /// * Auto-delay + /// * Balanded Idle + /// * Triggered-half mode + /// + /// There is also differences in (including but not limited to) the following areas: + /// * Counter roll over event + /// * The events registered with `enable_set_event` will work as normal wen counting up, however when counting down, they will work as rst events. + /// * The events registered with `enable_rst_event` will work as normal wen counting up, however when counting down, they will work as set events. + UpDown, +} + +// Needed to calculate frequency +impl From for pwm::Alignment { + fn from(val: HrCountingDirection) -> Self { + match val { + HrCountingDirection::Up => pwm::Alignment::Left, + HrCountingDirection::UpDown => pwm::Alignment::Center, + } + } +} + +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum InterleavedMode { + Disabled, + + /// Dual interleaved or Half mode + /// + /// Automatically force + /// * Cr1 to PERIOD / 2 (not visable through `get_duty`). + /// + /// Automatically updates when changing period + /// + /// NOTE: Affects Cr1 + Dual, + + /// Triple interleaved mode + /// + /// Automatically force + /// * Cr1 to 1 * PERIOD / 3 and + /// * Cr2 to 2 * PERIOD / 3 + /// + /// (not visable through `get_duty`). Automatically updates when changing period. + /// + /// NOTE: Must not be used simultaneously with other modes + /// using CMP2 (dual channel dac trigger and triggered-half modes). + Triple, + + /// Quad interleaved mode + /// + /// Automatically force + /// * Cr1 to 1 * PERIOD / 4, + /// * Cr2 to 2 * PERIOD / 4 and + /// * Cr3 to 3 * PERIOD / 4 + /// + /// (not visable through `get_duty`). Automatically updates when changing period. + /// + /// NOTE: Must not be used simultaneously with other modes + /// using CMP2 (dual channel dac trigger and triggered-half modes). + Quad, +} + +pub trait HrPwmAdvExt: Sized { + type PreloadSource; + + fn pwm_advanced( + self, + _pins: PINS, + rcc: &mut Rcc, + ) -> HrPwmBuilder + where + PINS: ToHrOut; +} + +/// HrPwmBuilder is used to configure advanced HrTim PWM features +pub struct HrPwmBuilder { + _tim: PhantomData, + _prescaler: PhantomData, + pins: PINS, + timer_mode: HrTimerMode, + counting_direction: HrCountingDirection, + base_freq: HertzU64, + count: CountSettings, + preload_source: Option, + fault_enable_bits: u8, + fault1_bits: u8, + fault2_bits: u8, + enable_push_pull: bool, + interleaved_mode: InterleavedMode, // Also includes half mode + repetition_counter: u8, + deadtime: Option, + enable_repetition_interrupt: bool, + eev_cfg: EevCfgs, + out1_polarity: Polarity, + out2_polarity: Polarity, +} + +pub struct HrParts { + pub timer: HrTim, HrCaptCh2>, + + pub cr1: HrCr1, + pub cr2: HrCr2, + pub cr3: HrCr3, + pub cr4: HrCr4, + + pub out: OUT, + pub dma_channel: timer::DmaChannel, +} + +pub enum PreloadSource { + /// Preloaded registers are updated on counter roll over or counter reset + OnCounterReset, + + /// Preloaded registers are updated by master timer update + OnMasterTimerUpdate, + + /// Prealoaded registers are updaten when the counter rolls over and the repetition counter is 0 + OnRepetitionUpdate, +} + +pub enum MasterPreloadSource { + /// Prealoaded registers are updaten when the master counter rolls over and the master repetition counter is 0 + OnMasterRepetitionUpdate, +} + +macro_rules! hrtim_finalize_body { + ($this:expr, $PreloadSource:ident, $TIMX:ident, $($out:ident)*) => {{ + let tim = unsafe { &*$TIMX::ptr() }; + let (period, prescaler_bits) = match $this.count { + CountSettings::Period(period) => (period as u32, PSCL::BITS as u16), + CountSettings::Frequency( freq ) => { + >::calculate_frequency($this.base_freq, freq, $this.counting_direction.into()) + }, + }; + + let (half, intlvd) = match $this.interleaved_mode { + InterleavedMode::Disabled => (false, 0b00), + InterleavedMode::Dual => (true, 0b00), + InterleavedMode::Triple => (false, 0b01), + InterleavedMode::Quad => (false, 0b10), + }; + + // Write prescaler and any special modes + tim.cr().modify(|_r, w| unsafe { + w + // Enable Continuous mode + .cont().bit($this.timer_mode == HrTimerMode::Continuous) + .retrig().bit($this.timer_mode == HrTimerMode::SingleShotRetriggerable) + + // TODO: add support for more modes + + // Interleaved mode + .intlvd().bits(intlvd) + + // half/double interleaved mode + .half().bit(half) + + // Set prescaler + .ckpsc().bits(prescaler_bits as u8) + }); + + $( + // Only available for timers with outputs(not HRTIM_MASTER) + #[allow(unused)] + let $out = (); + + tim.cr2().modify(|_r, w| + // Set counting direction + w.udm().bit($this.counting_direction == HrCountingDirection::UpDown) + ); + + tim.cr().modify(|_r, w| + // Push-Pull mode + w.pshpll().bit($this.enable_push_pull) + ); + )* + + // Write period + tim.perr().write(|w| unsafe { w.per().bits(period as u16) }); + + // Enable fault sources and lock configuration + $(unsafe { + // Only available for timers with outputs(not HRTIM_MASTER) + #[allow(unused)] + let $out = (); + + // Enable fault sources + let fault_enable_bits = $this.fault_enable_bits as u32; + tim.fltr().write(|w| w + .flt1en().bit(fault_enable_bits & (1 << 0) != 0) + .flt2en().bit(fault_enable_bits & (1 << 1) != 0) + .flt3en().bit(fault_enable_bits & (1 << 2) != 0) + .flt4en().bit(fault_enable_bits & (1 << 3) != 0) + .flt5en().bit(fault_enable_bits & (1 << 4) != 0) + .flt6en().bit(fault_enable_bits & (1 << 5) != 0) + ); + + // ... and lock configuration + tim.fltr().modify(|_r, w| w.fltlck().set_bit()); + + tim.outr().modify(|_r, w| w + // Set actions on fault for both outputs + .fault1().bits($this.fault1_bits) + .fault2().bits($this.fault2_bits) + + // Set output polarity for both outputs + .pol1().bit($this.out1_polarity == Polarity::ActiveLow) + .pol2().bit($this.out2_polarity == Polarity::ActiveLow) + ); + if let Some(deadtime) = $this.deadtime { + let DeadtimeConfig { + prescaler, + deadtime_rising_value, + deadtime_rising_sign, + deadtime_falling_value, + deadtime_falling_sign, + } = deadtime; + + // SAFETY: DeadtimeConfig makes sure rising and falling values are valid + // and DeadtimePrescaler has its own garantuee + tim.dtr().modify(|_r, w| w + .dtprsc().bits(prescaler as u8) + .dtr().bits(deadtime_rising_value) + .sdtr().bit(deadtime_rising_sign) + .dtf().bits(deadtime_falling_value) + .sdtf().bit(deadtime_falling_sign) + + // Lock configuration + .dtflk().set_bit() + .dtfslk().set_bit() + .dtrlk().set_bit() + .dtrslk().set_bit() + ); + tim.outr().modify(|_r, w| w.dten().set_bit()); + } + + // External event configs + let eev_cfg = $this.eev_cfg.clone(); + tim.eefr1().write(|w| w + .ee1ltch().bit(eev_cfg.eev1.latch_bit).ee1fltr().bits(eev_cfg.eev1.filter_bits) + .ee2ltch().bit(eev_cfg.eev2.latch_bit).ee2fltr().bits(eev_cfg.eev2.filter_bits) + .ee3ltch().bit(eev_cfg.eev3.latch_bit).ee3fltr().bits(eev_cfg.eev3.filter_bits) + .ee4ltch().bit(eev_cfg.eev4.latch_bit).ee4fltr().bits(eev_cfg.eev4.filter_bits) + .ee5ltch().bit(eev_cfg.eev5.latch_bit).ee5fltr().bits(eev_cfg.eev5.filter_bits) + ); + tim.eefr2().write(|w| w + .ee6ltch().bit(eev_cfg.eev6.latch_bit).ee6fltr().bits(eev_cfg.eev6.filter_bits) + .ee7ltch().bit(eev_cfg.eev7.latch_bit).ee7fltr().bits(eev_cfg.eev7.filter_bits) + .ee8ltch().bit(eev_cfg.eev8.latch_bit).ee8fltr().bits(eev_cfg.eev8.filter_bits) + .ee9ltch().bit(eev_cfg.eev9.latch_bit).ee9fltr().bits(eev_cfg.eev9.filter_bits) + .ee10ltch().bit(eev_cfg.eev10.latch_bit).ee10fltr().bits(eev_cfg.eev10.filter_bits) + ); + tim.eefr3().write(|w| w + .eevace().bit(eev_cfg.event_counter_enable_bit) + // External Event A Counter Reset"] + //.eevacres().bit() + .eevarstm().bit(eev_cfg.event_counter_reset_mode_bit) + .eevasel().bits(eev_cfg.event_counter_source_bits) + .eevacnt().bits(eev_cfg.event_counter_threshold_bits) + ); + })* + + + hrtim_finalize_body!($PreloadSource, $this, tim); + + // Set repetition counter + unsafe { tim.repr().write(|w| w.rep().bits($this.repetition_counter)); } + + // Enable interrupts + tim.dier().modify(|_r, w| w.repie().bit($this.enable_repetition_interrupt)); + + // Start timer + //let master = unsafe { &*HRTIM_MASTER::ptr() }; + //master.mcr.modify(|_r, w| { w.$tXcen().set_bit() }); + + // Connect pins and let HRTIM take over control over them + $this.pins.connect_to_hrtim(); + + unsafe { + MaybeUninit::uninit().assume_init() + } + }}; + + (PreloadSource, $this:expr, $tim:expr) => {{ + match $this.preload_source { + Some(PreloadSource::OnCounterReset) => { + $tim.cr().modify(|_r, w| w + .trstu().set_bit() + .preen().set_bit() + ); + }, + Some(PreloadSource::OnMasterTimerUpdate) => { + $tim.cr().modify(|_r, w| w + .mstu().set_bit() + .preen().set_bit() + ); + } + Some(PreloadSource::OnRepetitionUpdate) => { + $tim.cr().modify(|_r, w| w + .trepu().set_bit() + .preen().set_bit() + ); + } + None => () + } + }}; + + (MasterPreloadSource, $this:expr, $tim:expr) => {{ + match $this.preload_source { + Some(MasterPreloadSource::OnMasterRepetitionUpdate) => { + $tim.cr().modify(|_r, w| w + .mrepu().set_bit() + .preen().set_bit() + ); + } + None => () + } + }}; +} + +macro_rules! hrtim_common_methods { + ($TIMX:ident, $PS:ident) => { + /// 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. + pub fn frequency>(mut self, freq: T) -> Self { + self.count = CountSettings::Frequency(freq.into()); + + self + } + + /// Set the prescaler; PWM count runs at base_frequency/(prescaler+1) + pub fn prescaler

(self, _prescaler: P) -> HrPwmBuilder<$TIMX, P, $PS, PINS> + where + P: HrtimPrescaler, + { + let HrPwmBuilder { + _tim, + _prescaler: _, + pins, + timer_mode, + fault_enable_bits, + fault1_bits, + fault2_bits, + enable_push_pull, + interleaved_mode, + counting_direction, + base_freq, + count, + preload_source, + repetition_counter, + deadtime, + enable_repetition_interrupt, + eev_cfg, + out1_polarity, + out2_polarity, + } = self; + + let period = match count { + CountSettings::Frequency(_) => u16::MAX, + CountSettings::Period(period) => period, + }; + + let count = CountSettings::Period(period); + + HrPwmBuilder { + _tim, + _prescaler: PhantomData, + pins, + timer_mode, + fault_enable_bits, + fault1_bits, + fault2_bits, + enable_push_pull, + interleaved_mode, + counting_direction, + base_freq, + count, + preload_source, + repetition_counter, + deadtime, + enable_repetition_interrupt, + eev_cfg, + out1_polarity, + out2_polarity, + } + } + + pub fn timer_mode(mut self, timer_mode: HrTimerMode) -> Self { + self.timer_mode = timer_mode; + self + } + + // TODO: Allow setting multiple? + pub fn preload(mut self, preload_source: $PS) -> Self { + self.preload_source = Some(preload_source); + self + } + + /// Set the period; PWM count runs from 0 to period, repeating every (period+1) counts + pub fn period(mut self, period: u16) -> Self { + self.count = CountSettings::Period(period); + self + } + + /// Set repetition counter, useful to reduce interrupts generated + /// from timer by a factor (repetition_counter + 1) + pub fn repetition_counter(mut self, repetition_counter: u8) -> Self { + self.repetition_counter = repetition_counter; + self + } + + pub fn enable_repetition_interrupt(mut self) -> Self { + self.enable_repetition_interrupt = true; + self + } + + pub fn eev_cfg(mut self, eev_cfg: EevCfgs<$TIMX>) -> Self { + self.eev_cfg = eev_cfg; + self + } + }; +} + +// Implement PWM configuration for timer +macro_rules! hrtim_hal { + ($($TIMX:ident: $($out:ident)*,)+) => { + $( + impl HrPwmAdvExt for $TIMX { + type PreloadSource = PreloadSource; + + fn pwm_advanced( + self, + pins: PINS, + rcc: &mut Rcc, + ) -> HrPwmBuilder + where + PINS: ToHrOut<$TIMX>, + { + // TODO: That 32x factor... Is that included below, or should we + // do that? Also that will likely risk overflowing u32 since + // 170MHz * 32 = 5.44GHz > u32::MAX.Hz() + let clk = HertzU64::from(HRTIM_COMMON::get_timer_frequency(&rcc.clocks)) * 32; + + HrPwmBuilder { + _tim: PhantomData, + _prescaler: PhantomData, + pins, + timer_mode: HrTimerMode::Continuous, + fault_enable_bits: 0b000000, + fault1_bits: 0b00, + fault2_bits: 0b00, + counting_direction: HrCountingDirection::Up, + base_freq: clk, + count: CountSettings::Period(u16::MAX), + preload_source: None, + enable_push_pull: false, + interleaved_mode: InterleavedMode::Disabled, + repetition_counter: 0, + deadtime: None, + enable_repetition_interrupt: false, + eev_cfg: EevCfgs::default(), + out1_polarity: Polarity::ActiveHigh, + out2_polarity: Polarity::ActiveHigh, + } + } + } + + impl + HrPwmBuilder<$TIMX, PSCL, PreloadSource, PINS> + where + PSCL: HrtimPrescaler, + PINS: ToHrOut<$TIMX>, + { + pub fn finalize(self, _control: &mut HrPwmControl) -> HrParts<$TIMX, PSCL, PINS::Out> { + hrtim_finalize_body!( + self, PreloadSource, + $TIMX, $($out)* + ) + } + + hrtim_common_methods!($TIMX, PreloadSource); + + pub fn with_fault_source(mut self, _fault_source: FS) -> Self + where FS: FaultSource + { + self.fault_enable_bits |= FS::ENABLE_BITS; + + self + } + + pub fn fault_action1(mut self, fault_action1: FaultAction) -> Self { + self.fault1_bits = fault_action1 as _; + + self + } + + pub fn fault_action2(mut self, fault_action2: FaultAction) -> Self { + self.fault2_bits = fault_action2 as _; + + self + } + + pub fn out1_polarity(mut self, polarity: Polarity) -> Self { + self.out1_polarity = polarity; + + self + } + + pub fn out2_polarity(mut self, polarity: Polarity) -> Self { + self.out2_polarity = polarity; + + self + } + + /// Enable or disable Push-Pull mode + /// + /// Enabling Push-Pull mode will make output 1 and 2 + /// alternate every period with one being + /// inactive and the other getting to output its wave form + /// as normal + /// + /// ---- . ---- + ///out1 | | . | | + /// | | . | | + /// -------- ---------------------------- -------------------- + /// . ------ . ------ + ///out2 . | | . | | + /// . | | . | | + /// ------------------------ ---------------------------- -- + /// + /// NOTE: setting this will overide any 'Swap Mode' set + pub fn push_pull_mode(mut self, enable: bool) -> Self { + // TODO: add check for incompatible modes + self.enable_push_pull = enable; + + self + } + + /// Set counting direction + /// + /// See [`HrCountingDirection`] + pub fn counting_direction(mut self, counting_direction: HrCountingDirection) -> Self { + self.counting_direction = counting_direction; + + self + } + + /// Set interleaved or half modes + /// + /// NOTE: Check [`InterleavedMode`] for more info about special cases + pub fn interleaved_mode(mut self, mode: InterleavedMode) -> Self { + self.interleaved_mode = mode; + + self + } + + pub fn deadtime(mut self, deadtime: DeadtimeConfig) -> Self { + self.deadtime = Some(deadtime); + + self + } + + //pub fn swap_mode(mut self, enable: bool) -> Self + } + )+ + }; +} + +impl HrPwmAdvExt for HRTIM_MASTER { + type PreloadSource = MasterPreloadSource; + + fn pwm_advanced( + self, + pins: PINS, + rcc: &mut Rcc, + ) -> HrPwmBuilder + where + PINS: ToHrOut, + { + // TODO: That 32x factor... Is that included below, or should we + // do that? Also that will likely risk overflowing u32 since + // 170MHz * 32 = 5.44GHz > u32::MAX.Hz() + let clk = HertzU64::from(HRTIM_COMMON::get_timer_frequency(&rcc.clocks)) * 32; + + HrPwmBuilder { + _tim: PhantomData, + _prescaler: PhantomData, + pins, + timer_mode: HrTimerMode::Continuous, + fault_enable_bits: 0b000000, + fault1_bits: 0b00, + fault2_bits: 0b00, + counting_direction: HrCountingDirection::Up, + base_freq: clk, + count: CountSettings::Period(u16::MAX), + preload_source: None, + enable_push_pull: false, + interleaved_mode: InterleavedMode::Disabled, + repetition_counter: 0, + deadtime: None, + enable_repetition_interrupt: false, + eev_cfg: EevCfgs::default(), + out1_polarity: Polarity::ActiveHigh, + out2_polarity: Polarity::ActiveHigh, + } + } +} + +impl HrPwmBuilder +where + PSCL: HrtimPrescaler, + PINS: ToHrOut, +{ + pub fn finalize(self, _control: &mut HrPwmControl) -> HrParts { + hrtim_finalize_body!(self, MasterPreloadSource, HRTIM_MASTER,) + } + + hrtim_common_methods!(HRTIM_MASTER, MasterPreloadSource); +} + +hrtim_hal! { + HRTIM_TIMA: out, + HRTIM_TIMB: out, + HRTIM_TIMC: out, + HRTIM_TIMD: out, + HRTIM_TIME: out, + HRTIM_TIMF: out, +} + +/// # Safety +/// Only implement for valid prescalers with correct values +pub unsafe trait HrtimPrescaler: Default { + const BITS: u8; + const VALUE: u8; + + /// Minimum allowed value for compare registers used with the timer with this prescaler + /// + /// NOTE: That for CR1 and CR3, 0 is also allowed + const MIN_CR: u16; + + /// Maximum allowed value for compare registers used with the timer with this prescaler + const MAX_CR: u16; +} + +macro_rules! impl_pscl { + ($($t:ident => $b:literal, $v:literal, $min:literal, $max:literal)+) => {$( + #[derive(Copy, Clone, Default)] + pub struct $t; + unsafe impl HrtimPrescaler for $t { + const BITS: u8 = $b; + const VALUE: u8 = $v; + const MIN_CR: u16 = $min; + const MAX_CR: u16 = $max; + } + )+}; +} + +impl_pscl! { + Pscl1 => 0b000, 1, 0x0060, 0xFFDF + Pscl2 => 0b001, 2, 0x0030, 0xFFEF + Pscl4 => 0b010, 4, 0x0018, 0xFFF7 + Pscl8 => 0b011, 8, 0x000C, 0xFFFB + Pscl16 => 0b100, 16, 0x0006, 0xFFFD + Pscl32 => 0b101, 32, 0x0003, 0xFFFD + Pscl64 => 0b110, 64, 0x0003, 0xFFFD + Pscl128 => 0b111, 128, 0x0003, 0xFFFD +} + +/// HrTim timer +struct TimerHrTim(PhantomData); + +impl pwm::TimerType for TimerHrTim { + // Period calculator for 16-bit hrtimers + // + // NOTE: This function will panic if the calculated period can not fit into 16 bits + fn calculate_frequency(base_freq: HertzU64, freq: Hertz, alignment: Alignment) -> (u32, u16) { + let ideal_period = pwm::Timer32Bit::calculate_frequency(base_freq, freq, alignment).0 + 1; + + let prescale = u32::from(PSC::VALUE); + + // Round to the nearest period + let period = (ideal_period + (prescale >> 1)) / prescale - 1; + + // It IS possible to fail this assert + assert!(period <= 0xFFFF); + + (period, PSC::BITS.into()) + } +} diff --git a/src/output.rs b/src/output.rs new file mode 100644 index 0000000..6d80b78 --- /dev/null +++ b/src/output.rs @@ -0,0 +1,220 @@ +use crate::stm32::{HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF}; +use core::marker::PhantomData; + +use super::event::EventSource; +use crate::{ + gpio::{ + self, + gpioa::{PA10, PA11, PA8, PA9}, + gpiob::{PB12, PB13, PB14, PB15}, + gpioc::{PC6, PC7, PC8, PC9}, + Alternate, AF13, AF3, + }, + pwm::{ComplementaryImpossible, Pins}, + stm32::HRTIM_COMMON, +}; + +mod sealed { + pub trait Sealed {} +} + +macro_rules! hrtim_out { + ($($TIMX:ident: $out_type:ident: $tXYoen:ident, $tXYodis:ident, $tXYods:ident, $setXYr:ident, $rstXYr:ident,)+) => {$( + impl HrOutput<$TIMX, PSCL> for $out_type<$TIMX, PSCL> { + fn enable(&mut self) { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + common.oenr().write(|w| { w.$tXYoen().set_bit() }); + } + + fn disable(&mut self) { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + common.odisr().write(|w| { w.$tXYodis().set_bit() }); + } + + fn enable_set_event>(&mut self, _set_event: &ES) { + let tim = unsafe { &*$TIMX::ptr() }; + unsafe { tim.$setXYr().modify(|r, w| w.bits(r.bits() | ES::BITS)); } + } + fn disable_set_event>(&mut self, _set_event: &ES) { + let tim = unsafe { &*$TIMX::ptr() }; + unsafe { tim.$setXYr().modify(|r, w| w.bits(r.bits() & !ES::BITS)); } + } + + fn enable_rst_event>(&mut self, _reset_event: &ES) { + let tim = unsafe { &*$TIMX::ptr() }; + unsafe { tim.$rstXYr().modify(|r, w| w.bits(r.bits() | ES::BITS)); } + } + fn disable_rst_event>(&mut self, _reset_event: &ES) { + let tim = unsafe { &*$TIMX::ptr() }; + unsafe { tim.$rstXYr().modify(|r, w| w.bits(r.bits() & !ES::BITS)); } + } + + fn get_state(&self) -> State { + let ods; + let oen; + + unsafe { + let common = &*HRTIM_COMMON::ptr(); + ods = common.odsr().read().$tXYods().bit_is_set(); + oen = common.oenr().read().$tXYoen().bit_is_set(); + } + + match (oen, ods) { + (true, _) => State::Running, + (false, false) => State::Idle, + (false, true) => State::Fault + } + } + } + )+}; +} + +hrtim_out! { + HRTIM_TIMA: HrOut1: ta1oen, ta1odis, ta1ods, set1r, rst1r, + HRTIM_TIMA: HrOut2: ta2oen, ta2odis, ta2ods, set2r, rst2r, + + HRTIM_TIMB: HrOut1: tb1oen, tb1odis, tb1ods, set1r, rst1r, + HRTIM_TIMB: HrOut2: tb2oen, tb2odis, tb2ods, set2r, rst2r, + + HRTIM_TIMC: HrOut1: tc1oen, tc1odis, tc1ods, set1r, rst1r, + HRTIM_TIMC: HrOut2: tc2oen, tc2odis, tc2ods, set2r, rst2r, + + HRTIM_TIMD: HrOut1: td1oen, td1odis, td1ods, set1r, rst1r, + HRTIM_TIMD: HrOut2: td2oen, td2odis, td2ods, set2r, rst2r, + + HRTIM_TIME: HrOut1: te1oen, te1odis, te1ods, set1r, rst1r, + HRTIM_TIME: HrOut2: te2oen, te2odis, te2ods, set2r, rst2r, + + HRTIM_TIMF: HrOut1: tf1oen, tf1odis, tf1ods, set1r, rst1r, + HRTIM_TIMF: HrOut2: tf2oen, tf2odis, tf2ods, set2r, rst2r, +} + +pub trait HrOutput { + /// Enable this output + fn enable(&mut self); + + /// Disable this output + fn disable(&mut self); + + /// Set this output to active every time the specified event occurs + /// + /// NOTE: Enabling the same event for both SET and RESET + /// will make that event TOGGLE the output + fn enable_set_event>(&mut self, set_event: &ES); + + /// Stop listening to the specified event + fn disable_set_event>(&mut self, set_event: &ES); + + /// Set this output to *not* active every time the specified event occurs + /// + /// NOTE: Enabling the same event for both SET and RESET + /// will make that event TOGGLE the output + fn enable_rst_event>(&mut self, reset_event: &ES); + + /// Stop listening to the specified event + fn disable_rst_event>(&mut self, reset_event: &ES); + + /// Get current state of the output + fn get_state(&self) -> State; +} + +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum State { + Idle, + Running, + Fault, +} + +impl State { + pub fn is_idle(self) -> bool { + matches!(self, State::Idle) + } + + pub fn is_running(self) -> bool { + matches!(self, State::Running) + } + + pub fn is_fault(self) -> bool { + matches!(self, State::Fault) + } +} + +pub trait ToHrOut: sealed::Sealed { + type Out; + + fn connect_to_hrtim(self); +} + +impl sealed::Sealed for (PA, PB) +where + PA: ToHrOut, + PB: ToHrOut, +{ +} + +impl ToHrOut for (PA, PB) +where + PA: ToHrOut, + PB: ToHrOut, +{ + type Out = (PA::Out, PB::Out); + + fn connect_to_hrtim(self) { + self.0.connect_to_hrtim(); + self.1.connect_to_hrtim(); + } +} + +pub struct HrOut1(PhantomData<(TIM, PSCL)>); +pub struct HrOut2(PhantomData<(TIM, PSCL)>); + +macro_rules! pins { + ($($TIMX:ty: CH1: $CH1:ident<$CH1_AF:ident>, CH2: $CH2:ident<$CH2_AF:ident>)+) => { + $( + impl sealed::Sealed<$TIMX> for $CH1> {} + impl sealed::Sealed<$TIMX> for $CH2> {} + + impl ToHrOut<$TIMX> for $CH1> { + type Out = HrOut1<$TIMX, PSCL>; + + fn connect_to_hrtim(self) { + let _: $CH1> = self.into_alternate(); + } + } + + impl ToHrOut<$TIMX> for $CH2> { + type Out = HrOut2<$TIMX, PSCL>; + + fn connect_to_hrtim(self) { + let _: $CH2> = self.into_alternate(); + } + } + )+ + } +} + +pins! { + HRTIM_TIMA: CH1: PA8, CH2: PA9 + + HRTIM_TIMB: CH1: PA10, CH2: PA11 + HRTIM_TIMC: CH1: PB12, CH2: PB13 + HRTIM_TIMD: CH1: PB14, CH2: PB15 + + HRTIM_TIME: CH1: PC8, CH2: PC9 + HRTIM_TIMF: CH1: PC6, CH2: PC7 +} + +impl Pins for () { + type Channel = (); +} + +impl sealed::Sealed for () {} +impl ToHrOut for () { + type Out = (); + + fn connect_to_hrtim(self) {} +} + +pub struct CH1(PhantomData); +pub struct CH2(PhantomData); diff --git a/src/timer.rs b/src/timer.rs new file mode 100644 index 0000000..bbc5dc8 --- /dev/null +++ b/src/timer.rs @@ -0,0 +1,355 @@ +use crate::stm32::{ + HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF, +}; +use core::marker::PhantomData; + +use super::{ + capture::{self, HrCapt, HrCapture}, + control::HrPwmCtrl, + HrtimPrescaler, +}; + +pub struct HrTim { + _timer: PhantomData, + _prescaler: PhantomData, + capture_ch1: CPT1, + capture_ch2: CPT2, +} + +/// This is the DMA channel of a HRTIM timer +/// +/// Every HRTIM timer including the master timer has a DMA channel +pub struct DmaChannel { + _x: PhantomData, +} + +pub trait HrTimer { + type Timer; + type Prescaler: HrtimPrescaler; + + /// Get period of timer in number of ticks + /// + /// This is also the maximum duty usable for `HrCompareRegister::set_duty` + /// + /// NOTE: The effective period in number of ticks will be twice as large as + /// returned by this function when running in UpDown mode or PushPull mode. + /// 4 times as large when having both modes active + fn get_period(&self) -> u16; + + /// Set period of timer in number of ticks + /// + /// NOTE: This will affect the maximum duty usable for `HrCompareRegister::set_duty` + fn set_period(&mut self, period: u16); + + /// Start timer + fn start(&mut self, _hr_control: &mut HrPwmCtrl); + + /// Stop timer + fn stop(&mut self, _hr_control: &mut HrPwmCtrl); + + /// Stop timer and reset counter + fn stop_and_reset(&mut self, _hr_control: &mut HrPwmCtrl); + + fn clear_repetition_interrupt(&mut self); + + /// Make a handle to this timers reset/roll-over event to use as adc trigger + fn as_reset_adc_trigger(&self) -> super::adc_trigger::TimerReset; + + /// Make a handle to this timers period event to use as adc trigger + fn as_period_adc_trigger(&self) -> super::adc_trigger::TimerPeriod; + + /// Disable register updates + /// + /// Calling this function temporarily disables the transfer from preload to active registers, + /// whatever the selected update event. This allows to modify several registers. + /// The regular update event takes place once [`Self::enable_register_updates`] is called. + fn disable_register_updates(&mut self, _hr_control: &mut HrPwmCtrl); + + /// Enable register updates + /// + /// See [`Self::disable_register_updates`]. + /// + /// NOTE: Register updates are enabled by default, no need to call this + /// unless [`Self::disable_register_updates`] has been called. + fn enable_register_updates(&mut self, _hr_control: &mut HrPwmCtrl); +} + +pub trait HrSlaveTimer: HrTimer { + type CptCh1; + type CptCh2; + + /// Start listening to the specified event + fn enable_reset_event>( + &mut self, + _event: &E, + ); + + /// Stop listening to the specified event + fn disable_reset_event>( + &mut self, + _event: &E, + ); +} + +pub struct TimerSplitCapture { + pub timer: HrTim, + pub ch1: HrCapt, + pub ch2: HrCapt, +} + +/// Trait for unsplit slave timer which still contains its capture modules +pub trait HrSlaveTimerCpt: HrSlaveTimer { + type CaptureCh1: HrCapture; + type CaptureCh2: HrCapture; + + fn capture_ch1(&mut self) -> &mut ::CaptureCh1; + fn capture_ch2(&mut self) -> &mut ::CaptureCh2; + fn split_capture( + self, + ) -> TimerSplitCapture; +} + +macro_rules! hrtim_timer { + ($( + $TIMX:ident: + $tXcen:ident, + $tXudis:ident, + $(($rstXr:ident))*, + )+) => {$( + impl HrTimer for HrTim<$TIMX, PSCL, CPT1, CPT2> { + type Prescaler = PSCL; + type Timer = $TIMX; + + fn get_period(&self) -> u16 { + let tim = unsafe { &*$TIMX::ptr() }; + + tim.perr().read().per().bits() + } + fn set_period(&mut self, period: u16) { + let tim = unsafe { &*$TIMX::ptr() }; + + tim.perr().write(|w| unsafe { w.per().bits(period as u16) }); + } + + /// Start timer + fn start(&mut self, _hr_control: &mut HrPwmCtrl) { + // Start timer + + // SAFETY: Since we hold _hr_control there is no risk for a race condition + let master = unsafe { &*HRTIM_MASTER::ptr() }; + master.cr().modify(|_r, w| { w.$tXcen().set_bit() }); + } + + /// Stop timer + fn stop(&mut self, _hr_control: &mut HrPwmCtrl) { + // Stop counter + // SAFETY: Since we hold _hr_control there is no risk for a race condition + let master = unsafe { &*HRTIM_MASTER::ptr() }; + master.cr().modify(|_r, w| { w.$tXcen().set_bit() }); + } + + /// Stop timer and reset counter + fn stop_and_reset(&mut self, _hr_control: &mut HrPwmCtrl) { + self.stop(_hr_control); + + // Reset counter + let tim = unsafe { &*$TIMX::ptr() }; + unsafe { tim.cntr().write(|w| w.cnt().bits(0)); } + } + + /// Make a handle to this timers reset event to use as adc trigger + fn as_reset_adc_trigger(&self) -> super::adc_trigger::TimerReset { + super::adc_trigger::TimerReset(PhantomData) + } + + /// Make a handle to this timers period event to use as adc trigger + fn as_period_adc_trigger(&self) -> super::adc_trigger::TimerPeriod { + super::adc_trigger::TimerPeriod(PhantomData) + } + + fn clear_repetition_interrupt(&mut self) { + let tim = unsafe { &*$TIMX::ptr() }; + + tim.icr().write(|w| w.repc().clear()); + } + + /// Disable register updates + /// + /// Calling this function temporarily disables the transfer from preload to active registers, + /// whatever the selected update event. This allows to modify several registers. + /// The regular update event takes place once [`Self::enable_register_updates`] is called. + fn disable_register_updates(&mut self, _hr_control: &mut HrPwmCtrl) { + use super::HRTIM_COMMON; + let common = unsafe { &*HRTIM_COMMON::ptr() }; + common.cr1().modify(|_r, w| w.$tXudis().set_bit()); + } + + /// Enable register updates + /// + /// See [`Self::disable_register_updates`]. + /// + /// NOTE: Register updates are enabled by default, no need to call this + /// unless [`Self::disable_register_updates`] has been called. + fn enable_register_updates<'a>(&mut self, _hr_control: &mut HrPwmCtrl) { + use super::HRTIM_COMMON; + let common = unsafe { &*HRTIM_COMMON::ptr() }; + common.cr1().modify(|_r, w| w.$tXudis().clear_bit()); + } + } + + impl HrTim<$TIMX, PSCL, CPT1, CPT2> { + pub fn set_repetition_counter(&mut self, repetition_counter: u8) { + let tim = unsafe { &*$TIMX::ptr() }; + + unsafe { tim.repr().write(|w| w.rep().bits(repetition_counter)); } + } + + pub fn enable_repetition_interrupt(&mut self, enable: bool) { + let tim = unsafe { &*$TIMX::ptr() }; + + tim.dier().modify(|_r, w| w.repie().bit(enable)); + } + } + + $( + impl HrSlaveTimer for HrTim<$TIMX, PSCL, CPT1, CPT2> { + type CptCh1 = HrCapt; + type CptCh2 = HrCapt; + + /// Reset this timer every time the specified event occurs + /// + /// Behaviour depends on `timer_mode`: + /// + /// * `HrTimerMode::SingleShotNonRetriggable`: Enabling the timer enables it but does not start it. + /// A first reset event starts the counting and any subsequent reset is ignored until the counter + /// reaches the PER value. The PER event is then generated and the counter is stopped. A reset event + /// restarts the counting from 0x0000. + /// * `HrTimerMode:SingleShotRetriggable`: Enabling the timer enables it but does not start it. + /// A reset event starts the counting if the counter is stopped, otherwise it clears the counter. + /// When the counter reaches the PER value, the PER event is generated and the counter is stopped. + /// A reset event restarts the counting from 0x0000. + /// * `HrTimerMode::Continuous`: Enabling the timer enables and starts it simultaneously. + /// When the counter reaches the PER value, it rolls-over to 0x0000 and resumes counting. + /// The counter can be reset at any time + fn enable_reset_event>(&mut self, _event: &E) { + let tim = unsafe { &*$TIMX::ptr() }; + + unsafe { tim.$rstXr().modify(|r, w| w.bits(r.bits() | E::BITS)); } + } + + /// Stop listening to the specified event + fn disable_reset_event>(&mut self, _event: &E) { + let tim = unsafe { &*$TIMX::ptr() }; + + unsafe { tim.$rstXr().modify(|r, w| w.bits(r.bits() & !E::BITS)); } + } + } + + impl HrSlaveTimerCpt for HrTim<$TIMX, PSCL, HrCapt<$TIMX, PSCL, capture::Ch1, capture::NoDma>, HrCapt<$TIMX, PSCL, capture::Ch2, capture::NoDma>> { + type CaptureCh1 = ::CptCh1; + type CaptureCh2 = ::CptCh2; + + /// Access the timers first capture channel + fn capture_ch1(&mut self) -> &mut Self::CaptureCh1 { + &mut self.capture_ch1 + } + + /// Access the timers second capture channel + fn capture_ch2(&mut self) -> &mut Self::CaptureCh2 { + &mut self.capture_ch2 + } + + fn split_capture(self) -> TimerSplitCapture<$TIMX, PSCL, capture::Ch1, capture::Ch2> { + let HrTim{ + _timer, + _prescaler, + capture_ch1, + capture_ch2, + } = self; + + TimerSplitCapture { + timer: HrTim{ + _timer, + _prescaler, + capture_ch1: (), + capture_ch2: (), + }, + ch1: capture_ch1, + ch2: capture_ch2, + } + } + } + + /// Timer Period event + impl super::event::EventSource for HrTim<$TIMX, PSCL, CPT1, CPT2> { + // $rstXr + const BITS: u32 = 1 << 2; + } + + /// Timer Update event + impl super::capture::CaptureEvent<$TIMX, PSCL> for HrTim<$TIMX, PSCL, CPT1, CPT2> { + const BITS: u32 = 1 << 1; + } + )* + )+} +} + +macro_rules! hrtim_timer_adc_trigger { + ($($TIMX:ident: + [$(($AdcTrigger:ident: [ + $((PER: $adc_trigger_bits_period:expr),)* + $((RST: $adc_trigger_bits_reset:expr)),* + ])),+] + ),+) => { + $($( + $(impl $AdcTrigger for super::adc_trigger::TimerReset<$TIMX> { + const BITS: u32 = $adc_trigger_bits_reset; + })* + + $(impl $AdcTrigger for super::adc_trigger::TimerPeriod<$TIMX> { + const BITS: u32 = $adc_trigger_bits_period; + })* + )*)* + } +} + +use super::adc_trigger::Adc13Trigger as Adc13; +use super::adc_trigger::Adc24Trigger as Adc24; +use super::adc_trigger::Adc579Trigger as Adc579; +use super::adc_trigger::Adc6810Trigger as Adc6810; + +hrtim_timer! { + HRTIM_MASTER: mcen, mudis,, + + HRTIM_TIMA: tacen, taudis, (rstr), + HRTIM_TIMB: tbcen, tbudis, (rstr), + HRTIM_TIMC: tccen, tcudis, (rstr), + HRTIM_TIMD: tdcen, tdudis, (rstr), + HRTIM_TIME: tecen, teudis, (rstr), + HRTIM_TIMF: tfcen, tfudis, (rstr), +} + +hrtim_timer_adc_trigger! { + HRTIM_MASTER: [(Adc13: [(PER: 1 << 4),]), (Adc24: [(PER: 1 << 4),]), (Adc579: [(PER: 4),]), (Adc6810: [(PER: 4),])], + + HRTIM_TIMA: [(Adc13: [(PER: 1 << 13), (RST: 1 << 14)]), (Adc24: [(PER: 1 << 13), ]), (Adc579: [(PER: 12), (RST: 13)]), (Adc6810: [(PER: 12), ])], + HRTIM_TIMB: [(Adc13: [(PER: 1 << 18), (RST: 1 << 19)]), (Adc24: [(PER: 1 << 17), ]), (Adc579: [(PER: 16), (RST: 17)]), (Adc6810: [(PER: 15), ])], + HRTIM_TIMC: [(Adc13: [(PER: 1 << 23), ]), (Adc24: [(PER: 1 << 21), (RST: 1 << 22)]), (Adc579: [(PER: 20), ]), (Adc6810: [(PER: 18), (RST: 19)])], + HRTIM_TIMD: [(Adc13: [(PER: 1 << 27), ]), (Adc24: [(PER: 1 << 26), (RST: 1 << 27)]), (Adc579: [(PER: 23), ]), (Adc6810: [(PER: 22), (RST: 23)])], + HRTIM_TIME: [(Adc13: [(PER: 1 << 31), ]), (Adc24: [ (RST: 1 << 31)]), (Adc579: [(PER: 26), ]), (Adc6810: [ ])], + HRTIM_TIMF: [(Adc13: [(PER: 1 << 24), (RST: 1 << 28)]), (Adc24: [(PER: 1 << 24), ]), (Adc579: [(PER: 30), (RST: 31)]), (Adc6810: [(PER: 31), ])] +} + +/// Master Timer Period event +impl super::event::TimerResetEventSource + for HrTim +{ + const BITS: u32 = 1 << 4; // MSTPER +} + +/// Master Timer Period event +impl super::event::EventSource + for HrTim +{ + const BITS: u32 = 1 << 7; // MSTPER +} diff --git a/src/timer_eev_cfg.rs b/src/timer_eev_cfg.rs new file mode 100644 index 0000000..96f79bd --- /dev/null +++ b/src/timer_eev_cfg.rs @@ -0,0 +1,194 @@ +use core::marker::PhantomData; + +pub struct EevCfgs { + pub eev1: EevCfg, + pub eev2: EevCfg, + pub eev3: EevCfg, + pub eev4: EevCfg, + pub eev5: EevCfg, + pub eev6: EevCfg, + pub eev7: EevCfg, + pub eev8: EevCfg, + pub eev9: EevCfg, + pub eev10: EevCfg, + + // TODO: Expose these + // TODO: Note there are some peculiarities here with fast mode + // One way to prevent missuse would be to require a borrowed ExternalEventSource when setting + // filter/latching as well as the event_counter related settings below. + pub(crate) event_counter_enable_bit: bool, + pub(crate) event_counter_reset_mode_bit: bool, + pub(crate) event_counter_source_bits: u8, + pub(crate) event_counter_threshold_bits: u8, +} + +macro_rules! impl_setter { + ($eevX:ident) => { + pub fn $eevX(mut self, cfg: EevCfg) -> Self { + self.$eevX = cfg; + self + } + }; +} + +impl EevCfgs { + impl_setter!(eev1); + impl_setter!(eev2); + impl_setter!(eev3); + impl_setter!(eev4); + impl_setter!(eev5); + impl_setter!(eev6); + impl_setter!(eev7); + impl_setter!(eev8); + impl_setter!(eev9); + impl_setter!(eev10); +} + +impl Clone for EevCfgs { + fn clone(&self) -> Self { + Self { + eev1: self.eev1.clone(), + eev2: self.eev2.clone(), + eev3: self.eev3.clone(), + eev4: self.eev4.clone(), + eev5: self.eev5.clone(), + eev6: self.eev6.clone(), + eev7: self.eev7.clone(), + eev8: self.eev8.clone(), + eev9: self.eev9.clone(), + eev10: self.eev10.clone(), + event_counter_enable_bit: self.event_counter_enable_bit, + event_counter_reset_mode_bit: self.event_counter_reset_mode_bit, + event_counter_source_bits: self.event_counter_source_bits, + event_counter_threshold_bits: self.event_counter_threshold_bits, + } + } +} + +pub struct EevCfg { + _x: PhantomData, + pub(crate) filter_bits: u8, + pub(crate) latch_bit: bool, +} + +impl Clone for EevCfg { + fn clone(&self) -> Self { + Self { + _x: PhantomData, + filter_bits: self.filter_bits, + latch_bit: self.latch_bit, + } + } +} + +impl EevCfg { + /// NOTE: This can not be set if eev is in fast mode AND using `EevCfg::latching` + pub fn filter(mut self, filter: EventFilter) -> Self { + self.filter_bits = filter as u8; + self + } + + /// NOTE: This can not be set if eev is in fast mode AND using a `EevCfg::filter` + pub fn latching(mut self) -> Self { + self.latch_bit = true; + self + } +} + +/// Note: Whenever a compare register is used for filtering, the value must be strictly above 0. +pub enum EventFilter { + /// No filtering + None = 0b0000, + + /// Blanking from reset/rollover to Cmp1 + BlankingResetToCmp1 = 0b0001, + + /// This depends on counter mode: + /// * Up-counting mode: Blanking from reset/rollover to Cmp2 + /// * Up-down mode: Blanking from Cmp1 to Cmp2(only during up counting) + BlankingResetToCmp2OrCmp1ToCmp2InUdm = 0b0010, + + /// Blanking from reset/rollover to Cmp3 + BlankingResetToCmp3 = 0b0011, + + /// This depends on counter mode: + /// * Up-counting mode: Blanking from reset/rollover to Cmp4 + /// * Up-down mode: Blanking from Cmp3 to Cmp4(only during up counting) + BlankingResetToCmp4OrCmp3ToCmp4InUdm = 0b0100, + + /// (RM 0440 table 226 'Filtering signals mapping per timer') + BlankingSource1 = 0b0101, + + /// (RM 0440 table 226 'Filtering signals mapping per timer') + BlankingSource2 = 0b0110, + + /// (RM 0440 table 226 'Filtering signals mapping per timer') + BlankingSource3 = 0b0111, + + /// (RM 0440 table 226 'Filtering signals mapping per timer') + BlankingSource4 = 0b1000, + + /// (RM 0440 table 226 'Filtering signals mapping per timer') + BlankingSource5 = 0b1001, + + /// (RM 0440 table 226 'Filtering signals mapping per timer') + BlankingSource6 = 0b1010, + + /// (RM 0440 table 226 'Filtering signals mapping per timer') + BlankingSource7 = 0b1011, + + /// (RM 0440 table 226 'Filtering signals mapping per timer') + BlankingSource8 = 0b1100, + + /// This depends on counter mode: + /// * Up-counting mode: Windowing from reset/rollover to Cmp2 + /// * Up-down mode: Windowing from Cmp2 to Cmp3(only during up counting) + WindowingResetToCmp2OrCmp2ToCmp3InUdm = 0b1101, + + /// This depends on counter mode: + /// * Up-counting mode: Windowing from reset/rollover to Cmp3 + /// * Up-down mode: Windowing from Cmp2 to Cmp3(only during down counting) + WindowingResetToCmp3OrCmp2ToCmp3InUdm = 0b1110, + + /// This depends on counter mode: + /// * Up-counting mode: Windowing from reset/rollover to other timer `TIMWIN`'s Cmp2 event + /// * Up-down mode: Windowing from other timer `TIMWIN`'s Cmp2 during up counting to Cmp3 during down counting + /// + /// `TIMWIN` (RM 0440 table 227 'Windowing signals mapping per timer'): + /// + /// | Destination |`TIMA`|`TIMB`|`TIMC`|`TIMD`|`TIME`|`TIMF`| + /// |-------------|------|------|------|------|------|------| + /// | TIMWIN |`TIMB`|`TIMA`|`TIMD`|`TIMC`|`TIMF`|`TIME`| + WindowingResetToOtherCmp2OrCmp2UpToCmp3DownInUdm = 0b1111, +} + +impl Default for EevCfg { + fn default() -> Self { + Self { + _x: PhantomData, + filter_bits: EventFilter::None as u8, + latch_bit: false, + } + } +} + +impl Default for EevCfgs { + fn default() -> Self { + Self { + eev1: EevCfg::default(), + eev2: Default::default(), + eev3: Default::default(), + eev4: Default::default(), + eev5: Default::default(), + eev6: Default::default(), + eev7: Default::default(), + eev8: Default::default(), + eev9: Default::default(), + eev10: Default::default(), + event_counter_enable_bit: false, + event_counter_reset_mode_bit: false, + event_counter_source_bits: 0, + event_counter_threshold_bits: 0, + } + } +} From 3c1c3637d59b0bde3688a6b1a37fe320027e345b Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Tue, 3 Dec 2024 16:18:52 +0100 Subject: [PATCH 02/25] Update to work as stand alone lib --- src/capture.rs | 10 +- src/control.rs | 31 +-- src/event.rs_old | 619 ----------------------------------------- src/external_event.rs | 24 +- src/fault.rs | 19 +- src/{mod.rs => lib.rs} | 36 ++- src/output.rs | 25 +- src/stm32g4.rs | 13 + 8 files changed, 93 insertions(+), 684 deletions(-) delete mode 100644 src/event.rs_old rename src/{mod.rs => lib.rs} (97%) create mode 100644 src/stm32g4.rs diff --git a/src/capture.rs b/src/capture.rs index eb1d047..221364d 100644 --- a/src/capture.rs +++ b/src/capture.rs @@ -1,8 +1,10 @@ +use crate::{hal, stm32}; + use super::timer; -use crate::dma::mux::DmaMuxResources; -use crate::dma::traits::TargetAddress; -use crate::dma::PeripheralToMemory; -use crate::stm32::{HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF}; +use crate::mcu::DmaMuxResources; +use hal::dma::traits::TargetAddress; +use hal::dma::PeripheralToMemory; +use stm32::{HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF}; use core::marker::PhantomData; pub struct Ch1; diff --git a/src/control.rs b/src/control.rs index 57974d6..74257bd 100644 --- a/src/control.rs +++ b/src/control.rs @@ -1,10 +1,9 @@ -use crate::{ - hrtim::fault::{ - FltMonitor1, FltMonitor2, FltMonitor3, FltMonitor4, FltMonitor5, FltMonitor6, FltMonitorSys, - }, - rcc::{Enable, Rcc, Reset}, - stm32::{HRTIM_COMMON, RCC}, +use crate::fault::{ + FltMonitor1, FltMonitor2, FltMonitor3, FltMonitor4, FltMonitor5, FltMonitor6, FltMonitorSys, }; +use crate::{hal, stm32}; +use hal::rcc::{Enable, Rcc, Reset}; +use stm32::{HRTIM_COMMON, RCC}; use super::{external_event::EevInputs, fault::FaultInputs}; @@ -19,8 +18,8 @@ impl HrControltExt for HRTIM_COMMON { unsafe { let rcc_ptr = &*RCC::ptr(); - HRTIM_COMMON::enable(rcc_ptr); - HRTIM_COMMON::reset(rcc_ptr); + ::enable(rcc_ptr); + ::reset(rcc_ptr); } // Start calibration procedure @@ -257,15 +256,15 @@ macro_rules! impl_adc1234_trigger { } } - $(impl From<&$t> for crate::adc::config::ExternalTrigger12 { + $(impl From<&$t> for hal::adc::config::ExternalTrigger12 { fn from(_val: &$t) -> Self { - crate::adc::config::ExternalTrigger12::$variant12 + hal::adc::config::ExternalTrigger12::$variant12 } })* - impl From<&$t> for crate::adc::config::ExternalTrigger345 { + impl From<&$t> for hal::adc::config::ExternalTrigger345 { fn from(_val: &$t) -> Self { - crate::adc::config::ExternalTrigger345::$variant345 + hal::adc::config::ExternalTrigger345::$variant345 } } )*} @@ -285,15 +284,15 @@ macro_rules! impl_adc5678910_trigger { } } - impl From<&$t> for crate::adc::config::ExternalTrigger12 { + impl From<&$t> for hal::adc::config::ExternalTrigger12 { fn from(_val: &$t) -> Self { - crate::adc::config::ExternalTrigger12::$variant12 + hal::adc::config::ExternalTrigger12::$variant12 } } - impl From<&$t> for crate::adc::config::ExternalTrigger345 { + impl From<&$t> for hal::adc::config::ExternalTrigger345 { fn from(_val: &$t) -> Self { - crate::adc::config::ExternalTrigger345::$variant345 + hal::adc::config::ExternalTrigger345::$variant345 } } diff --git a/src/event.rs_old b/src/event.rs_old deleted file mode 100644 index 65258c1..0000000 --- a/src/event.rs_old +++ /dev/null @@ -1,619 +0,0 @@ -use core::marker::PhantomData; - -use crate::stm32::{ - HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF, -}; - -use super::{compare_register::{HrCr1, HrCr2, HrCr3, HrCr4}, external_event_old::ExternalEventSource}; -use crate::hrtim::timer::HrTim; - -macro_rules! impl_into_es { - ($dst:ident: [$(($t:ty, $ES:ident),)*]) => {$( - impl_into_es!($dst, $t, $ES); - )*}; - - ($dst:ident, $t:ty, $ES:ident) => { - impl From<&$t> for EventSource { - fn from(_: &$t) -> Self { - EventSource::$ES{ _x: PhantomData } - } - } - }; - ($dst:ident) => { - impl_into_es! { - $dst: [ - (HrCr1<$dst, PSCL>, Cr1), - (HrCr2<$dst, PSCL>, Cr2), - (HrCr3<$dst, PSCL>, Cr3), - (HrCr4<$dst, PSCL>, Cr4), - (HrTim<$dst, PSCL>, Period), - - (HrCr1, MasterCr1), - (HrCr2, MasterCr2), - (HrCr3, MasterCr3), - (HrCr4, MasterCr4), - (HrTim, MasterPeriod), - ] - } - }; -} - -impl_into_es!(HRTIM_TIMA); -impl_into_es!(HRTIM_TIMB); -impl_into_es!(HRTIM_TIMC); -impl_into_es!(HRTIM_TIMD); -impl_into_es!(HRTIM_TIME); -impl_into_es!(HRTIM_TIMF); - -macro_rules! impl_into_neighbor_es { - ( - DST: $dst:ident: [ - ($src1:ident, $cr1:ident), - ($src2:ident, $cr2:ident), - ($src3:ident, $cr3:ident), - ($src4:ident, $cr4:ident), - ($src5:ident, $cr5:ident), - ($src6:ident, $cr6:ident), - ($src7:ident, $cr7:ident), - ($src8:ident, $cr8:ident), - ($src9:ident, $cr9:ident), - ] - ) => { - impl_into_neighbor_es!($dst, $src1, $cr1, TimEvent1); - impl_into_neighbor_es!($dst, $src2, $cr2, TimEvent2); - impl_into_neighbor_es!($dst, $src3, $cr3, TimEvent3); - impl_into_neighbor_es!($dst, $src4, $cr4, TimEvent4); - impl_into_neighbor_es!($dst, $src5, $cr5, TimEvent5); - impl_into_neighbor_es!($dst, $src6, $cr6, TimEvent6); - impl_into_neighbor_es!($dst, $src7, $cr7, TimEvent7); - impl_into_neighbor_es!($dst, $src8, $cr8, TimEvent8); - impl_into_neighbor_es!($dst, $src9, $cr9, TimEvent9); - }; - - ($dst:ident, $src:ident, $cr:ident, $TimEventX:ident) => { - impl From<&$cr<$src, PSCL>> for EventSource { - fn from(_: &$cr<$src, PSCL>) -> Self { - EventSource::NeighborTimer { - n: NeighborTimerEventSource::$TimEventX { _x: PhantomData }, - } - } - } - }; -} - -impl_into_neighbor_es! { - DST: HRTIM_TIMA: [ - // src - (HRTIM_TIMB, HrCr1), - (HRTIM_TIMB, HrCr2), - (HRTIM_TIMC, HrCr2), - (HRTIM_TIMC, HrCr3), - (HRTIM_TIMD, HrCr1), - (HRTIM_TIMD, HrCr2), - (HRTIM_TIME, HrCr3), - (HRTIM_TIME, HrCr4), - (HRTIM_TIMF, HrCr4), - ] -} - -impl_into_neighbor_es! { - DST: HRTIM_TIMB: [ - // src - (HRTIM_TIMA, HrCr1), - (HRTIM_TIMA, HrCr2), - (HRTIM_TIMC, HrCr3), - (HRTIM_TIMC, HrCr4), - (HRTIM_TIMD, HrCr3), - (HRTIM_TIMD, HrCr4), - (HRTIM_TIME, HrCr1), - (HRTIM_TIME, HrCr2), - (HRTIM_TIMF, HrCr3), - ] -} - -impl_into_neighbor_es! { - DST: HRTIM_TIMC: [ - // src - (HRTIM_TIMA, HrCr2), - (HRTIM_TIMA, HrCr3), - (HRTIM_TIMB, HrCr2), - (HRTIM_TIMB, HrCr3), - (HRTIM_TIMD, HrCr2), - (HRTIM_TIMD, HrCr4), - (HRTIM_TIME, HrCr3), - (HRTIM_TIME, HrCr4), - (HRTIM_TIMF, HrCr2), - ] -} - -// TODO: Continue for TIMD, TIME and TIMF, see RM0440 Table 218. 'Events mapping across timer A to F' - -pub enum EventSource { - /// Compare match with compare register 1 of this timer - Cr1 { _x: PhantomData<(PSCL, DST)> }, - - /// Compare match with compare register 2 of this timer - Cr2 { _x: PhantomData<(PSCL, DST)> }, - - /// Compare match with compare register 3 of this timer - Cr3 { _x: PhantomData<(PSCL, DST)> }, - - /// Compare match with compare register 4 of this timer - Cr4 { _x: PhantomData<(PSCL, DST)> }, - - /// On complete period - Period { _x: PhantomData<(PSCL, DST)> }, - - /// Compare match with compare register 1 of master timer - MasterCr1 { _x: PhantomData<(PSCL, DST)> }, - - /// Compare match with compare register 2 of master timer - MasterCr2 { _x: PhantomData<(PSCL, DST)> }, - - /// Compare match with compare register 3 of master timer - MasterCr3 { _x: PhantomData<(PSCL, DST)> }, - - /// Compare match with compare register 4 of master timer - MasterCr4 { _x: PhantomData<(PSCL, DST)> }, - - /// On complete master period - MasterPeriod { _x: PhantomData<(PSCL, DST)> }, - - ExternalEvent(ExternalEventSource), // This is fine - - NeighborTimer { - n: NeighborTimerEventSource, - }, -} - -/// Compare events from neighbor timers -/// -/// See RM0440 Table 218. 'Events mapping across timer A to F' -pub enum NeighborTimerEventSource { - /// Timer event 1 - /// - /// This is different depending on destination timer: - /// |dest | source | - /// |-----|--------| - /// |TimA | B CR1 | - /// |TimB | A CR1 | - /// |TimC | A CR2 | - /// |TimD | A CR1 | - /// |TimE | A CR4 | - /// |TimF | A CR3 | - TimEvent1 { - _x: PhantomData<(PSCL, DST)>, - }, - - /// Timer event x - /// - /// This is different depending on destination timer: - /// |dest | source | - /// |-----|--------| - /// |TimA | x CRy | - /// |TimB | x CRy | - /// |TimC | x CRy | - /// |TimD | x CRy | - /// |TimE | x CRy | - /// |TimF | x CRy | - //TimEventx, - - /// Timer event 2 - /// - /// This is different depending on destination timer: - /// |dest | source | - /// |-----|--------| - /// |TimA | B CR2 | - /// |TimB | A CR2 | - /// |TimC | A CR3 | - /// |TimD | A CR4 | - /// |TimE | B CR3 | - /// |TimF | B CR1 | - TimEvent2 { - _x: PhantomData<(PSCL, DST)>, - }, - - /// Timer event 3 - /// - /// This is different depending on destination timer: - /// |dest | source | - /// |-----|--------| - /// |TimA | C CR2 | - /// |TimB | C CR3 | - /// |TimC | B CR2 | - /// |TimD | B CR2 | - /// |TimE | B CR4 | - /// |TimF | B CR4 | - TimEvent3 { - _x: PhantomData<(PSCL, DST)>, - }, - - /// Timer event 4 - /// - /// This is different depending on destination timer: - /// |dest | source | - /// |-----|--------| - /// |TimA | C CR3 | - /// |TimB | C CR4 | - /// |TimC | B CR3 | - /// |TimD | B CR4 | - /// |TimE | C CR1 | - /// |TimF | C CR1 | - TimEvent4 { - _x: PhantomData<(PSCL, DST)>, - }, - // TODO: Document those - TimEvent5 { - _x: PhantomData<(PSCL, DST)>, - }, - TimEvent6 { - _x: PhantomData<(PSCL, DST)>, - }, - TimEvent7 { - _x: PhantomData<(PSCL, DST)>, - }, - TimEvent8 { - _x: PhantomData<(PSCL, DST)>, - }, - TimEvent9 { - _x: PhantomData<(PSCL, DST)>, - }, -} - -macro_rules! hr_timer_reset_event_source_common { - ($(#[$($attrss:tt)*])* pub enum $t:ident { [COMMON], $(#[$($attrss2:tt)*] $vals:tt = 1 << $x:literal,)*}) => { - $(#[$($attrss)*])* - pub enum $t { - $(#[$($attrss2)*] $vals = 1 << $x,)* - - /// The timer counter is reset upon external event 10. - Eevnt10 = 1 << 18, - - /// The timer counter is reset upon external event 9. - Eevnt9 = 1 << 17, - - /// The timer counter is reset upon external event 8. - Eevnt8 = 1 << 16, - - /// The timer counter is reset upon external event 7. - Eevnt7 = 1 << 15, - - /// The timer counter is reset upon external event 6. - Eevnt6 = 1 << 14, - - /// The timer counter is reset upon external event 5. - Eevnt5 = 1 << 13, - - /// The timer counter is reset upon external event 4. - Eevnt4 = 1 << 12, - - /// The timer counter is reset upon external event 3. - Eevnt3 = 1 << 11, - - /// The timer counter is reset upon external event 2. - Eevnt2 = 1 << 10, - - /// The timer counter is reset upon external event 1. - Eevnt1 = 1 << 9, - - /// The timer counter is reset upon master timer compare 4 event. - MasterCmp4 = 1 << 8, - - /// The timer counter is reset upon master timer compare 3 event. - MasterCmp3 = 1 << 7, - - /// The timer counter is reset upon master timer compare 2 event. - MasterCmp2 = 1 << 6, - - /// The timer counter is reset upon master timer compare 1 event. - MasterCmp1 = 1 << 5, - - /// The timer counter is reset upon master timer period event. - MasterPeriod = 1 << 4, - - /// The timer counter is reset upon timer its own compare 4 event - Cmp4 = 1 << 3, - - /// The timer counter is reset upon timer its own compare 2 event - Cmp2 = 1 << 2, - - /// The timer counter is reset upon update event. - Update = 1 << 1, - } - }; -} - -hr_timer_reset_event_source_common!( - /// A - pub enum TimerAResetEventSource { - [COMMON], - /// The timer counter is reset upon timer F compare 2 event. - TimFCmp2 = 1 << 31, - - /// The timer counter is reset upon timer E compare 4 event. - TimECmp4 = 1 << 30, - - /// The timer counter is reset upon timer E compare 2 event. - TimECmp2 = 1 << 29, - - /// The timer counter is reset upon timer E compare 1 event. - TimECmp1 = 1 << 28, - - /// The timer counter is reset upon timer D compare 4 event. - TimDCmp4 = 1 << 27, - - /// The timer counter is reset upon timer D compare 2 event. - TimDCmp2 = 1 << 26, - - /// The timer counter is reset upon timer D compare 1 event. - TimDCmp1 = 1 << 25, - - /// The timer counter is reset upon timer C compare 4 event. - TimCCmp4 = 1 << 24, - - /// The timer counter is reset upon timer C compare 2 event. - TimCCmp2 = 1 << 23, - - /// The timer counter is reset upon timer C compare 1 event. - TimCCmp1 = 1 << 22, - - /// The timer counter is reset upon timer B compare 4 event. - TimBCmp4 = 1 << 21, - - /// The timer counter is reset upon timer B compare 2 event. - TimBCmp2 = 1 << 20, - - /// The timer counter is reset upon timer B compare 1 event. - TimBCmp1 = 1 << 19, - - /// The timer counter is reset upon timer F compare 1 event. - TimFCmp1 = 1 << 0, - } -); - -hr_timer_reset_event_source_common!( - /// B - pub enum TimerBResetEventSource { - [COMMON], - - /// The timer counter is reset upon timer F compare 2 event. - TimFCmp2 = 1 << 31, - - /// The timer counter is reset upon timer E compare 4 event. - TimECmp4 = 1 << 30, - - /// The timer counter is reset upon timer E compare 2 event. - TimECmp2 = 1 << 29, - - /// The timer counter is reset upon timer E compare 1 event. - TimECmp1 = 1 << 28, - - /// The timer counter is reset upon timer D compare 4 event. - TimDCmp4 = 1 << 27, - - /// The timer counter is reset upon timer D compare 2 event. - TimDCmp2 = 1 << 26, - - /// The timer counter is reset upon timer D compare 1 event. - TimDCmp1 = 1 << 25, - - /// The timer counter is reset upon timer C compare 4 event. - TimCCmp4 = 1 << 24, - - /// The timer counter is reset upon timer C compare 2 event. - TimCCmp2 = 1 << 23, - - /// The timer counter is reset upon timer C compare 1 event. - TimCCmp1 = 1 << 22, - - /// The timer counter is reset upon timer A compare 4 event. - TimACmp4 = 1 << 21, - - /// The timer counter is reset upon timer A compare 2 event. - TimACmp2 = 1 << 20, - - /// The timer counter is reset upon timer A compare 1 event. - TimACmp1 = 1 << 19, - - /// The timer counter is reset upon timer F compare 1 event. - TimFCmp1 = 1 << 0, - } -); - -hr_timer_reset_event_source_common!( - /// C - pub enum TimerCResetEventSource { - [COMMON], - - /// The timer counter is reset upon timer F compare 2 event. - TimFCmp2 = 1 << 31, - - /// The timer counter is reset upon timer E compare 4 event. - TimECmp4 = 1 << 30, - - /// The timer counter is reset upon timer E compare 2 event. - TimECmp2 = 1 << 29, - - /// The timer counter is reset upon timer E compare 1 event. - TimECmp1 = 1 << 28, - - /// The timer counter is reset upon timer D compare 4 event. - TimDCmp4 = 1 << 27, - - /// The timer counter is reset upon timer D compare 2 event. - TimDCmp2 = 1 << 26, - - /// The timer counter is reset upon timer D compare 1 event. - TimDCmp1 = 1 << 25, - - /// The timer counter is reset upon timer B compare 4 event. - TimBCmp4 = 1 << 24, - - /// The timer counter is reset upon timer B compare 2 event. - TimBCmp2 = 1 << 23, - - /// The timer counter is reset upon timer B compare 1 event. - TimBCmp1 = 1 << 22, - - /// The timer counter is reset upon timer A compare 4 event. - TimACmp4 = 1 << 21, - - /// The timer counter is reset upon timer A compare 2 event. - TimACmp2 = 1 << 20, - - /// The timer counter is reset upon timer A compare 1 event. - TimACmp1 = 1 << 19, - - - /// The timer counter is reset upon timer F compare 1 event. - TimFCmp1 = 1 << 0, - } -); - -hr_timer_reset_event_source_common!( - /// D - pub enum TimerDResetEventSource { - [COMMON], - - /// The timer counter is reset upon timer F compare 2 event. - TimFCmp2 = 1 << 31, - - /// The timer counter is reset upon timer E compare 4 event. - TimECmp4 = 1 << 30, - - /// The timer counter is reset upon timer E compare 2 event. - TimECmp2 = 1 << 29, - - /// The timer counter is reset upon timer E compare 1 event. - TimECmp1 = 1 << 28, - - /// The timer counter is reset upon timer C compare 4 event. - TimCCmp4 = 1 << 27, - - /// The timer counter is reset upon timer C compare 2 event. - TimCCmp2 = 1 << 26, - - /// The timer counter is reset upon timer C compare 1 event. - TimCCmp1 = 1 << 25, - - /// The timer counter is reset upon timer B compare 4 event. - TimBCmp4 = 1 << 24, - - /// The timer counter is reset upon timer B compare 2 event. - TimBCmp2 = 1 << 23, - - /// The timer counter is reset upon timer B compare 1 event. - TimBCmp1 = 1 << 22, - - /// The timer counter is reset upon timer A compare 4 event. - TimACmp4 = 1 << 21, - - /// The timer counter is reset upon timer A compare 2 event. - TimACmp2 = 1 << 20, - - /// The timer counter is reset upon timer A compare 1 event. - TimACmp1 = 1 << 19, - - /// The timer counter is reset upon timer F compare 1 event. - TimFCmp1 = 1 << 0, - } -); - -hr_timer_reset_event_source_common!( - /// E - pub enum TimerEResetEventSource { - [COMMON], - - /// The timer counter is reset upon timer F compare 2 event. - TimFCmp2 = 1 << 31, - - /// The timer counter is reset upon timer D compare 4 event. - TimDCmp4 = 1 << 30, - - /// The timer counter is reset upon timer D compare 2 event. - TimDCmp2 = 1 << 29, - - /// The timer counter is reset upon timer D compare 1 event. - TimDCmp1 = 1 << 28, - - /// The timer counter is reset upon timer C compare 4 event. - TimCCmp4 = 1 << 27, - - /// The timer counter is reset upon timer C compare 2 event. - TimCCmp2 = 1 << 26, - - /// The timer counter is reset upon timer C compare 1 event. - TimCCmp1 = 1 << 25, - - /// The timer counter is reset upon timer B compare 4 event. - TimBCmp4 = 1 << 24, - - /// The timer counter is reset upon timer B compare 2 event. - TimBCmp2 = 1 << 23, - - /// The timer counter is reset upon timer B compare 1 event. - TimBCmp1 = 1 << 22, - - /// The timer counter is reset upon timer A compare 4 event. - TimACmp4 = 1 << 21, - - /// The timer counter is reset upon timer A compare 2 event. - TimACmp2 = 1 << 20, - - /// The timer counter is reset upon timer A compare 1 event. - TimACmp1 = 1 << 19, - - - /// The timer counter is reset upon timer F compare 1 event. - TimFCmp1 = 1 << 0, - } -); - -hr_timer_reset_event_source_common!( - /// F - pub enum TimerFResetEventSource { - [COMMON], - - /// The timer counter is reset upon timer E compare 2 event. - TimECmp2 = 1 << 31, - - /// The timer counter is reset upon timer D compare 4 event. - TimDCmp4 = 1 << 30, - - /// The timer counter is reset upon timer D compare 2 event. - TimDCmp2 = 1 << 29, - - /// The timer counter is reset upon timer D compare 1 event. - TimDCmp1 = 1 << 28, - - /// The timer counter is reset upon timer C compare 4 event. - TimCCmp4 = 1 << 27, - - /// The timer counter is reset upon timer C compare 2 event. - TimCCmp2 = 1 << 26, - - /// The timer counter is reset upon timer C compare 1 event. - TimCCmp1 = 1 << 25, - - /// The timer counter is reset upon timer B compare 4 event. - TimBCmp4 = 1 << 24, - - /// The timer counter is reset upon timer B compare 2 event. - TimBCmp2 = 1 << 23, - - /// The timer counter is reset upon timer B compare 1 event. - TimBCmp1 = 1 << 22, - - /// The timer counter is reset upon timer A compare 4 event. - TimACmp4 = 1 << 21, - - /// The timer counter is reset upon timer A compare 2 event. - TimACmp2 = 1 << 20, - - /// The timer counter is reset upon timer A compare 1 event. - TimACmp1 = 1 << 19, - - /// The timer counter is reset upon timer E compare 1 event. - TimECmp1 = 1 << 0, - } -); diff --git a/src/external_event.rs b/src/external_event.rs index 74b6a53..5f2f25a 100644 --- a/src/external_event.rs +++ b/src/external_event.rs @@ -1,9 +1,11 @@ -use crate::comparator::{COMP1, COMP2, COMP3, COMP4, COMP5, COMP6, COMP7}; -use crate::gpio::gpiob::{PB3, PB4, PB5, PB6, PB7, PB8, PB9}; -use crate::gpio::gpioc::{PC11, PC12, PC5, PC6}; -use crate::gpio::{self, AF13, AF3}; -use crate::pwm::Polarity; -use crate::stm32::HRTIM_COMMON; +use crate::{hal, stm32}; + +use hal::comparator::{COMP1, COMP2, COMP3, COMP4, COMP5, COMP6, COMP7}; +use hal::gpio::gpiob::{PB3, PB4, PB5, PB6, PB7, PB8, PB9}; +use hal::gpio::gpioc::{PC11, PC12, PC5, PC6}; +use hal::gpio::{self, AF13, AF3}; +use hal::pwm::Polarity; +use stm32::HRTIM_COMMON; use super::control::HrTimCalibrated; @@ -61,15 +63,15 @@ macro_rules! impl_eev_input { } })* - unsafe impl EevSrcBits<$N> for &crate::comparator::Comparator<$compX, ED> - where ED: crate::comparator::EnabledState + unsafe impl EevSrcBits<$N> for &hal::comparator::Comparator<$compX, ED> + where ED: hal::comparator::EnabledState { const SRC_BITS: u8 = 0b01; } $( - unsafe impl EevSrcBits<$N> for &crate::comparator::Comparator<$compY, ED> - where ED: crate::comparator::EnabledState + unsafe impl EevSrcBits<$N> for &hal::comparator::Comparator<$compY, ED> + where ED: hal::comparator::EnabledState { const SRC_BITS: u8 = $compY_src_bits; } @@ -97,7 +99,7 @@ impl_eev_input!(8: COMP = [COMP6, (COMP3, 0b10)], PINS = [(PB8, AF13)]); impl_eev_input!(9: COMP = [COMP5, (COMP4, 0b11)], PINS = [(PB3, AF13)]); impl_eev_input!(10: COMP = [COMP7], PINS = [(PC5, AF13), (PC6, AF3)]); -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(/*Copy, Clone, Debug, PartialEq*/ )] pub enum EdgeOrPolarity { Edge(Edge), Polarity(Polarity), diff --git a/src/fault.rs b/src/fault.rs index c425077..3b6f39d 100644 --- a/src/fault.rs +++ b/src/fault.rs @@ -1,10 +1,11 @@ -use crate::comparator::{COMP1, COMP2, COMP3, COMP4, COMP5, COMP6}; -use crate::gpio::gpioa::{PA12, PA15}; -use crate::gpio::gpiob::{PB0, PB10, PB11}; -use crate::gpio::gpioc::{PC10, PC7}; -use crate::gpio::{self, AF13, AF3}; -use crate::hrtim::control::HrPwmControl; -use crate::stm32::HRTIM_COMMON; +use crate::control::HrPwmControl; +use crate::hal; +use hal::comparator::{COMP1, COMP2, COMP3, COMP4, COMP5, COMP6}; +use hal::gpio::gpioa::{PA12, PA15}; +use hal::gpio::gpiob::{PB0, PB10, PB11}; +use hal::gpio::gpioc::{PC10, PC7}; +use hal::gpio::{self, AF13, AF3}; +use hal::stm32::HRTIM_COMMON; use super::control::HrPwmCtrl; @@ -94,7 +95,7 @@ macro_rules! impl_faults { } )* - pub fn bind_comp(self, _comp: &crate::comparator::Comparator<$compX, crate::comparator::Enabled>) -> SourceBuilder<$input> { + pub fn bind_comp(self, _comp: &hal::comparator::Comparator<$compX, hal::comparator::Enabled>) -> SourceBuilder<$input> { unsafe { SourceBuilder::new(self, 0b01) } } @@ -127,7 +128,7 @@ macro_rules! impl_faults { } pub fn polarity(mut self, polarity: super::Polarity) -> Self { - self.is_active_high = polarity == super::Polarity::ActiveHigh; + self.is_active_high = matches!(polarity, super::Polarity::ActiveHigh); self } diff --git a/src/mod.rs b/src/lib.rs similarity index 97% rename from src/mod.rs rename to src/lib.rs index d07ef3c..2215b5b 100644 --- a/src/mod.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![no_std] + pub mod adc_trigger; pub mod capture; pub mod compare_register; @@ -10,12 +12,24 @@ pub mod output; pub mod timer; pub mod timer_eev_cfg; +#[cfg(any(feature = "stm32f3"))] +pub use stm32f3xx_hal as hal; + +#[cfg(any(feature = "stm32h7"))] +pub use stm32h7xx_hal as hal; + +#[cfg(any(feature = "stm32g4"))] +#[path = "stm32g4.rs"]mod mcu; + +pub use mcu::{hal, hal::stm32}; + + use core::marker::PhantomData; use core::mem::MaybeUninit; -use crate::hrtim::compare_register::{HrCr1, HrCr2, HrCr3, HrCr4}; -use crate::hrtim::fault::{FaultAction, FaultSource}; -use crate::hrtim::timer::HrTim; +use crate::compare_register::{HrCr1, HrCr2, HrCr3, HrCr4}; +use crate::fault::{FaultAction, FaultSource}; +use crate::timer::HrTim; use crate::stm32::{ HRTIM_COMMON, HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF, @@ -29,9 +43,9 @@ use self::deadtime::DeadtimeConfig; use self::output::ToHrOut; use self::timer_eev_cfg::EevCfgs; -use crate::pwm::{self, Alignment, Polarity, TimerType}; -use crate::rcc::{GetBusFreq, Rcc}; -use crate::time::Hertz; +use hal::pwm::{self, Polarity}; +use hal::rcc::{GetBusFreq, Rcc}; +use hal::time::Hertz; /// Internal enum that keeps track of the count settings before PWM is finalized enum CountSettings { @@ -221,8 +235,8 @@ macro_rules! hrtim_finalize_body { let tim = unsafe { &*$TIMX::ptr() }; let (period, prescaler_bits) = match $this.count { CountSettings::Period(period) => (period as u32, PSCL::BITS as u16), - CountSettings::Frequency( freq ) => { - >::calculate_frequency($this.base_freq, freq, $this.counting_direction.into()) + CountSettings::Frequency(_freq) => { + todo!()//>::calculate_frequency($this.base_freq, freq, $this.counting_direction.into()) }, }; @@ -297,8 +311,8 @@ macro_rules! hrtim_finalize_body { .fault2().bits($this.fault2_bits) // Set output polarity for both outputs - .pol1().bit($this.out1_polarity == Polarity::ActiveLow) - .pol2().bit($this.out2_polarity == Polarity::ActiveLow) + .pol1().bit(matches!($this.out1_polarity, Polarity::ActiveLow)) + .pol2().bit(matches!($this.out2_polarity, Polarity::ActiveLow)) ); if let Some(deadtime) = $this.deadtime { let DeadtimeConfig { @@ -759,6 +773,7 @@ impl_pscl! { Pscl128 => 0b111, 128, 0x0003, 0xFFFD } +/* /// HrTim timer struct TimerHrTim(PhantomData); @@ -780,3 +795,4 @@ impl pwm::TimerType for TimerHrTim { (period, PSC::BITS.into()) } } +*/ \ No newline at end of file diff --git a/src/output.rs b/src/output.rs index 6d80b78..01b2042 100644 --- a/src/output.rs +++ b/src/output.rs @@ -1,17 +1,16 @@ -use crate::stm32::{HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF}; +use crate::{ + hal, + stm32::{HRTIM_COMMON, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF}, +}; use core::marker::PhantomData; use super::event::EventSource; -use crate::{ - gpio::{ - self, - gpioa::{PA10, PA11, PA8, PA9}, - gpiob::{PB12, PB13, PB14, PB15}, - gpioc::{PC6, PC7, PC8, PC9}, - Alternate, AF13, AF3, - }, - pwm::{ComplementaryImpossible, Pins}, - stm32::HRTIM_COMMON, +use hal::gpio::{ + self, + gpioa::{PA10, PA11, PA8, PA9}, + gpiob::{PB12, PB13, PB14, PB15}, + gpioc::{PC6, PC7, PC8, PC9}, + Alternate, AF13, AF3, }; mod sealed { @@ -205,10 +204,6 @@ pins! { HRTIM_TIMF: CH1: PC6, CH2: PC7 } -impl Pins for () { - type Channel = (); -} - impl sealed::Sealed for () {} impl ToHrOut for () { type Out = (); diff --git a/src/stm32g4.rs b/src/stm32g4.rs new file mode 100644 index 0000000..a0de127 --- /dev/null +++ b/src/stm32g4.rs @@ -0,0 +1,13 @@ + +pub use stm32g4xx_hal as hal; + +#[allow(non_camel_case_types, dead_code)] +pub enum DmaMuxResources { + HRTIM_MASTER = 95, + HRTIM_TIMA = 96, + HRTIM_TIMB = 97, + HRTIM_TIMC = 98, + HRTIM_TIMD = 99, + HRTIM_TIME = 100, + HRTIM_TIMF = 101, +} \ No newline at end of file From 46b09416b038246e06c94a4ba432af9f22d3f720 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Tue, 3 Dec 2024 16:19:14 +0100 Subject: [PATCH 03/25] Update Cargo.toml --- Cargo.toml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e5eb5c9..4c9b5fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,13 +4,14 @@ version = "0.1.0" edition = "2021" [dependencies] -stm32f3 = { version = "0.15.1", optional = true } -stm32h7 = { version = "0.15.1", optional = true } -stm32g4 = { version = "0.19.0", package = "stm32g4-staging", optional = true } stm32f3xx-hal = { version = "0.10.0", optional = true } stm32h7xx-hal = { version = "0.16.0", optional = true } -stm32g4xx-hal = { version = "0.0.1", optional = true } +#stm32g4xx-hal = { version = "0.0.1", optional = true } +#stm32g4xx-hal = { git = "https://github.com/stm32-rs/stm32g4xx-hal", branch = "staged-pac", optional = true } +stm32g4xx-hal = { path = "../stm32g4xx-hal", optional = true } +defmt = { version = "0.3.10", optional = true } +fugit = "0.3.7" [features] default = [] @@ -19,6 +20,10 @@ hrtim_v1 = [] hrtim_v1_1 = [] hrtim_v2 = [] +stm32f3 = [] +stm32h7 = [] +stm32g4 = [] + stm32f334x4 = ["stm32f3", "stm32f3xx-hal/stm32f334x4", "hrtim_v1"] stm32f334x6 = ["stm32f3", "stm32f3xx-hal/stm32f334x6", "hrtim_v1"] stm32f334x8 = ["stm32f3", "stm32f3xx-hal/stm32f334x8", "hrtim_v1"] @@ -33,4 +38,5 @@ stm32h753 = ["stm32h7", "stm32h7xx-hal/stm32h753", "hrtim_v1_1"] #stm32h757 = ["stm32h7", "stm32h7xx-hal/stm32h757", "hrtim_v1_1"] stm32g474 = ["stm32g4", "stm32g4xx-hal/stm32g474", "hrtim_v2"] -stm32g484 = ["stm32g4", "stm32g4xx-hal/stm32g484", "hrtim_v2"] \ No newline at end of file +stm32g484 = ["stm32g4", "stm32g4xx-hal/stm32g484", "hrtim_v2"] +defmt = ["dep:defmt", "fugit/defmt"] From 45a68a65f70ce0a7af7c9224ce98435e341b7baa Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 4 Dec 2024 18:01:54 +0100 Subject: [PATCH 04/25] Try to support stm32f334 --- Cargo.toml | 6 +- src/adc_trigger.rs | 4 ++ src/capture.rs | 33 +++++++-- src/compare_register.rs | 18 ++++- src/control.rs | 74 +++++++++++++++++++- src/external_event.rs | 58 +++++++++------- src/fault.rs | 41 +++++++++--- src/lib.rs | 120 +++++++++++++++++++++------------ src/output.rs | 145 ++++++++++++++++++++++++++++++---------- src/stm32f3.rs | 18 +++++ src/stm32g4.rs | 10 ++- src/timer.rs | 13 +++- src/timer_eev_cfg.rs | 12 ++++ 13 files changed, 428 insertions(+), 124 deletions(-) create mode 100644 src/stm32f3.rs diff --git a/Cargo.toml b/Cargo.toml index 4c9b5fd..c0a4e94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,10 @@ edition = "2021" [dependencies] +stm32f3 = { git = "https://github.com/stm32-rs/stm32-rs-nightlies", optional = true } +#stm32h7 = { git = "", optional = true } +#stm32g4 = { git = "", optional = true } + stm32f3xx-hal = { version = "0.10.0", optional = true } stm32h7xx-hal = { version = "0.16.0", optional = true } #stm32g4xx-hal = { version = "0.0.1", optional = true } @@ -20,7 +24,7 @@ hrtim_v1 = [] hrtim_v1_1 = [] hrtim_v2 = [] -stm32f3 = [] +stm32f3 = ["stm32f3/stm32f3x4"] stm32h7 = [] stm32g4 = [] diff --git a/src/adc_trigger.rs b/src/adc_trigger.rs index 6238501..133a42b 100644 --- a/src/adc_trigger.rs +++ b/src/adc_trigger.rs @@ -1,17 +1,21 @@ use core::marker::PhantomData; +#[cfg(feature = "stm32g4")] pub trait Adc13Trigger { const BITS: u32; } +#[cfg(feature = "stm32g4")] pub trait Adc24Trigger { const BITS: u32; } +#[cfg(feature = "stm32g4")] pub trait Adc579Trigger { const BITS: u32; } +#[cfg(feature = "stm32g4")] pub trait Adc6810Trigger { const BITS: u32; } diff --git a/src/capture.rs b/src/capture.rs index 221364d..7e37828 100644 --- a/src/capture.rs +++ b/src/capture.rs @@ -1,11 +1,16 @@ -use crate::{hal, stm32}; +use crate::stm32; use super::timer; + +#[cfg(feature = "stm32g4")] use crate::mcu::DmaMuxResources; -use hal::dma::traits::TargetAddress; -use hal::dma::PeripheralToMemory; -use stm32::{HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF}; +#[cfg(feature = "stm32g4")] +use crate::hal::dma::PeripheralToMemory; + use core::marker::PhantomData; +#[cfg(feature = "hrtim_v2")] +use stm32::HRTIM_TIMF; +use stm32::{HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME}; pub struct Ch1; pub struct Ch2; @@ -27,6 +32,7 @@ pub struct HrCapt { #[derive(Copy, Clone, Debug)] pub enum CountingDirection { Up = 0, + #[cfg(feature = "hrtim_v2")] Down = 1, } @@ -129,6 +135,7 @@ pub trait HrCapture { // The capture counter always counts up and restarts at period match dir { CountingDirection::Up => i32::from(value), + #[cfg(feature = "hrtim_v2")] CountingDirection::Down => i32::from(value) - i32::from(period), } } @@ -140,10 +147,14 @@ pub trait HrCapture { pub fn dma_value_to_dir_and_value(x: u32) -> (u16, CountingDirection) { let value = (x & 0xFFFF) as u16; + #[cfg(feature = "hrtim_v2")] match x & (1 << 16) != 0 { true => (value, CountingDirection::Down), false => (value, CountingDirection::Up), } + + #[cfg(any(feature = "hrtim_v1", feature = "hrtim_v1_1"))] + (value, CountingDirection::Up) } pub fn dma_value_to_signed(x: u32, period: u16) -> i32 { @@ -152,6 +163,7 @@ pub fn dma_value_to_signed(x: u32, period: u16) -> i32 { // The capture counter always counts up and restarts at period match dir { CountingDirection::Up => i32::from(value), + #[cfg(feature = "hrtim_v2")] CountingDirection::Down => i32::from(value) - i32::from(period), } } @@ -219,10 +231,14 @@ macro_rules! impl_capture { let tim = unsafe { &*$TIMX::ptr() }; let data = tim.$cptXr().read(); + #[cfg(feature = "hrtim_v2")] let dir = match data.dir().bit() { true => CountingDirection::Down, false => CountingDirection::Up, }; + #[cfg(any(feature = "hrtim_v1", feature = "hrtim_v1_1"))] + let dir = CountingDirection::Up; + let value = data.cpt().bits(); (value, dir) @@ -243,7 +259,8 @@ macro_rules! impl_capture { } } - unsafe impl TargetAddress for HrCapt<$TIMX, PSCL, $CH, Dma> { + #[cfg(feature = "stm32g4")] + unsafe impl crate::hal::dma::traits::TargetAddress for HrCapt<$TIMX, PSCL, $CH, Dma> { #[inline(always)] fn address(&self) -> u32 { let tim = unsafe { &*$TIMX::ptr() }; @@ -262,6 +279,10 @@ impl_capture! { HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, - HRTIM_TIME, + HRTIM_TIME +} + +#[cfg(feature = "hrtim_v2")] +impl_capture! { HRTIM_TIMF } diff --git a/src/compare_register.rs b/src/compare_register.rs index 0b54c74..2d6f1d5 100644 --- a/src/compare_register.rs +++ b/src/compare_register.rs @@ -1,8 +1,10 @@ use core::marker::PhantomData; use crate::stm32::{ - HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF, + HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, }; +#[cfg(feature = "hrtim_v2")] +use crate::stm32::HRTIM_TIMF; pub trait HrCompareRegister { fn get_duty(&self) -> u16; @@ -14,11 +16,16 @@ pub struct HrCr2(PhantomData<(TIM, PSCL)>); pub struct HrCr3(PhantomData<(TIM, PSCL)>); pub struct HrCr4(PhantomData<(TIM, PSCL)>); +#[cfg(feature = "stm32g4")] use super::adc_trigger::Adc13Trigger as Adc13; +#[cfg(feature = "stm32g4")] use super::adc_trigger::Adc24Trigger as Adc24; +#[cfg(feature = "stm32g4")] use super::adc_trigger::Adc579Trigger as Adc579; +#[cfg(feature = "stm32g4")] use super::adc_trigger::Adc6810Trigger as Adc6810; +#[cfg(feature = "stm32g4")] macro_rules! hrtim_cr_helper { (HRTIM_MASTER: $cr_type:ident: $cmpXYr:ident, @@ -71,6 +78,7 @@ macro_rules! hrtim_cr_helper { }; } +#[cfg(feature = "stm32g4")] macro_rules! hrtim_cr { ($($TIMX:ident: [ [$(($cr1_trigger:ident: $cr1_trigger_bits:expr)),*], [$(($cr1_event_dst:ident, $cr1_tim_event_index:expr)),*], @@ -86,6 +94,7 @@ macro_rules! hrtim_cr { } // See RM0440 Table 218. 'Events mapping across timer A to F' +#[cfg(feature = "stm32g4")] hrtim_cr! { HRTIM_MASTER: [ [(Adc13: 1 << 0), (Adc24: 1 << 0), (Adc579: 0), (Adc6810: 0) ], [], @@ -179,8 +188,11 @@ hrtim_timer_rst! { HRTIM_TIMD: HrCr4: 3, HRTIM_TIME: HrCr2: 2, - HRTIM_TIME: HrCr4: 3, + HRTIM_TIME: HrCr4: 3 +} +#[cfg(feature = "hrtim_v2")] +hrtim_timer_rst! { HRTIM_TIMF: HrCr2: 2, HRTIM_TIMF: HrCr4: 3 -} +} \ No newline at end of file diff --git a/src/control.rs b/src/control.rs index 74257bd..763f78c 100644 --- a/src/control.rs +++ b/src/control.rs @@ -1,6 +1,9 @@ use crate::fault::{ - FltMonitor1, FltMonitor2, FltMonitor3, FltMonitor4, FltMonitor5, FltMonitor6, FltMonitorSys, + FltMonitor1, FltMonitor2, FltMonitor3, FltMonitor4, FltMonitor5, FltMonitorSys, }; +#[cfg(feature = "hrtim_v2")] +use crate::fault::FltMonitor6; + use crate::{hal, stm32}; use hal::rcc::{Enable, Rcc, Reset}; use stm32::{HRTIM_COMMON, RCC}; @@ -16,8 +19,12 @@ impl HrControltExt for HRTIM_COMMON { let common = unsafe { &*HRTIM_COMMON::ptr() }; unsafe { + #[cfg(feature = "stm32g4")] let rcc_ptr = &*RCC::ptr(); + #[cfg(feature = "stm32f3")] + let rcc_ptr = &mut *RCC::ptr(); + ::enable(rcc_ptr); ::reset(rcc_ptr); } @@ -28,16 +35,26 @@ impl HrControltExt for HRTIM_COMMON { .write(|w| w.cal().set_bit().calen().clear_bit()); HrTimOngoingCalibration { + #[cfg(feature = "stm32g4")] adc_trigger1_postscaler: AdcTriggerPostscaler::None, + #[cfg(feature = "stm32g4")] adc_trigger2_postscaler: AdcTriggerPostscaler::None, + #[cfg(feature = "stm32g4")] adc_trigger3_postscaler: AdcTriggerPostscaler::None, + #[cfg(feature = "stm32g4")] adc_trigger4_postscaler: AdcTriggerPostscaler::None, + #[cfg(feature = "stm32g4")] adc_trigger5_postscaler: AdcTriggerPostscaler::None, + #[cfg(feature = "stm32g4")] adc_trigger6_postscaler: AdcTriggerPostscaler::None, + #[cfg(feature = "stm32g4")] adc_trigger7_postscaler: AdcTriggerPostscaler::None, + #[cfg(feature = "stm32g4")] adc_trigger8_postscaler: AdcTriggerPostscaler::None, + #[cfg(feature = "stm32g4")] adc_trigger9_postscaler: AdcTriggerPostscaler::None, + #[cfg(feature = "stm32g4")] adc_trigger10_postscaler: AdcTriggerPostscaler::None, flt_divider: SamplingClkDiv::None, @@ -47,16 +64,26 @@ impl HrControltExt for HRTIM_COMMON { } pub struct HrTimOngoingCalibration { + #[cfg(feature = "stm32g4")] adc_trigger1_postscaler: AdcTriggerPostscaler, + #[cfg(feature = "stm32g4")] adc_trigger2_postscaler: AdcTriggerPostscaler, + #[cfg(feature = "stm32g4")] adc_trigger3_postscaler: AdcTriggerPostscaler, + #[cfg(feature = "stm32g4")] adc_trigger4_postscaler: AdcTriggerPostscaler, + #[cfg(feature = "stm32g4")] adc_trigger5_postscaler: AdcTriggerPostscaler, + #[cfg(feature = "stm32g4")] adc_trigger6_postscaler: AdcTriggerPostscaler, + #[cfg(feature = "stm32g4")] adc_trigger7_postscaler: AdcTriggerPostscaler, + #[cfg(feature = "stm32g4")] adc_trigger8_postscaler: AdcTriggerPostscaler, + #[cfg(feature = "stm32g4")] adc_trigger9_postscaler: AdcTriggerPostscaler, + #[cfg(feature = "stm32g4")] adc_trigger10_postscaler: AdcTriggerPostscaler, flt_divider: SamplingClkDiv, @@ -69,16 +96,26 @@ impl HrTimOngoingCalibration { let common = unsafe { &*HRTIM_COMMON::ptr() }; let Self { + #[cfg(feature = "stm32g4")] adc_trigger1_postscaler, + #[cfg(feature = "stm32g4")] adc_trigger2_postscaler, + #[cfg(feature = "stm32g4")] adc_trigger3_postscaler, + #[cfg(feature = "stm32g4")] adc_trigger4_postscaler, + #[cfg(feature = "stm32g4")] adc_trigger5_postscaler, + #[cfg(feature = "stm32g4")] adc_trigger6_postscaler, + #[cfg(feature = "stm32g4")] adc_trigger7_postscaler, + #[cfg(feature = "stm32g4")] adc_trigger8_postscaler, + #[cfg(feature = "stm32g4")] adc_trigger9_postscaler, + #[cfg(feature = "stm32g4")] adc_trigger10_postscaler, flt_divider, @@ -97,6 +134,7 @@ impl HrTimOngoingCalibration { .write(|w| w.fltsd().bits(flt_divider as u8)); common.eecr3().write(|w| w.eevsd().bits(eev_divider as u8)); + #[cfg(feature = "stm32g4")] common.adcps1().write(|w| { w.adc1psc() .bits(adc_trigger1_postscaler as u8) @@ -110,6 +148,7 @@ impl HrTimOngoingCalibration { .bits(adc_trigger5_postscaler as u8) }); + #[cfg(feature = "stm32g4")] common.adcps2().write(|w| { w.adc6psc() .bits(adc_trigger6_postscaler as u8) @@ -141,21 +180,25 @@ impl HrTimOngoingCalibration { }) } + #[cfg(feature = "stm32g4")] pub fn set_adc1_trigger_psc(mut self, post_scaler: AdcTriggerPostscaler) -> Self { self.adc_trigger1_postscaler = post_scaler; self } + #[cfg(feature = "stm32g4")] pub fn set_adc2_trigger_psc(mut self, post_scaler: AdcTriggerPostscaler) -> Self { self.adc_trigger2_postscaler = post_scaler; self } + #[cfg(feature = "stm32g4")] pub fn set_adc3_trigger_psc(mut self, post_scaler: AdcTriggerPostscaler) -> Self { self.adc_trigger3_postscaler = post_scaler; self } + #[cfg(feature = "stm32g4")] pub fn set_adc4_trigger_psc(mut self, post_scaler: AdcTriggerPostscaler) -> Self { self.adc_trigger4_postscaler = post_scaler; self @@ -188,17 +231,28 @@ impl HrTimCalibrated { fault_3: FltMonitor3, fault_4: FltMonitor4, fault_5: FltMonitor5, + #[cfg(feature = "hrtim_v2")] fault_6: FltMonitor6, + #[cfg(feature = "stm32g4")] adc_trigger1: Adc1Trigger, + #[cfg(feature = "stm32g4")] adc_trigger2: Adc2Trigger, + #[cfg(feature = "stm32g4")] adc_trigger3: Adc3Trigger, + #[cfg(feature = "stm32g4")] adc_trigger4: Adc4Trigger, + #[cfg(feature = "stm32g4")] adc_trigger5: Adc5Trigger, + #[cfg(feature = "stm32g4")] adc_trigger6: Adc6Trigger, + #[cfg(feature = "stm32g4")] adc_trigger7: Adc7Trigger, + #[cfg(feature = "stm32g4")] adc_trigger8: Adc8Trigger, + #[cfg(feature = "stm32g4")] adc_trigger9: Adc9Trigger, + #[cfg(feature = "stm32g4")] adc_trigger10: Adc10Trigger, } } @@ -227,21 +281,33 @@ pub struct HrPwmControl { pub fault_3: FltMonitor3, pub fault_4: FltMonitor4, pub fault_5: FltMonitor5, + #[cfg(feature = "stm32g4")] pub fault_6: FltMonitor6, + #[cfg(feature = "stm32g4")] pub adc_trigger1: Adc1Trigger, + #[cfg(feature = "stm32g4")] pub adc_trigger2: Adc2Trigger, + #[cfg(feature = "stm32g4")] pub adc_trigger3: Adc3Trigger, + #[cfg(feature = "stm32g4")] pub adc_trigger4: Adc4Trigger, + #[cfg(feature = "stm32g4")] pub adc_trigger5: Adc5Trigger, + #[cfg(feature = "stm32g4")] pub adc_trigger6: Adc6Trigger, + #[cfg(feature = "stm32g4")] pub adc_trigger7: Adc7Trigger, + #[cfg(feature = "stm32g4")] pub adc_trigger8: Adc8Trigger, + #[cfg(feature = "stm32g4")] pub adc_trigger9: Adc9Trigger, + #[cfg(feature = "stm32g4")] pub adc_trigger10: Adc10Trigger, } +#[cfg(feature = "stm32g4")] macro_rules! impl_adc1234_trigger { ($($t:ident: [$trait_:ident, $adcXr:ident, $variant345:ident $(, $variant12:ident)*]),*) => {$( #[non_exhaustive] @@ -270,6 +336,7 @@ macro_rules! impl_adc1234_trigger { )*} } +#[cfg(feature = "stm32g4")] macro_rules! impl_adc5678910_trigger { ($($t:ident: [$trait_:ident, $adcXtrg:ident, $variant345:ident, $variant12:ident]),*) => {$( #[non_exhaustive] @@ -298,7 +365,7 @@ macro_rules! impl_adc5678910_trigger { )*} } - +#[cfg(feature = "stm32g4")] impl_adc1234_trigger! {// reg adc345, adc12 Adc1Trigger: [Adc13Trigger, adc1r, Hrtim_adc_trg_1, Hrtim_adc_trg_1], Adc2Trigger: [Adc24Trigger, adc2r, Hrtim_adc_trg_2], @@ -306,6 +373,7 @@ impl_adc1234_trigger! {// reg adc345, adc12 Adc4Trigger: [Adc24Trigger, adc4r, Hrtim_adc_trg_4] } +#[cfg(feature = "stm32g4")] impl_adc5678910_trigger! { Adc5Trigger: [Adc579Trigger, adc5trg, Hrtim_adc_trg_5, Hrtim_adc_trg_5], Adc6Trigger: [Adc6810Trigger, adc6trg, Hrtim_adc_trg_6, Hrtim_adc_trg_6], @@ -315,8 +383,10 @@ impl_adc5678910_trigger! { Adc10Trigger: [Adc6810Trigger, adc10trg, Hrtim_adc_trg_10, Hrtim_adc_trg_10] } +#[cfg(feature = "stm32g4")] use super::adc_trigger::{Adc13Trigger, Adc24Trigger, Adc579Trigger, Adc6810Trigger}; +#[cfg(feature = "stm32g4")] pub enum AdcTriggerPostscaler { None = 0, Div2 = 1, diff --git a/src/external_event.rs b/src/external_event.rs index 5f2f25a..49df65f 100644 --- a/src/external_event.rs +++ b/src/external_event.rs @@ -1,10 +1,14 @@ -use crate::{hal, stm32}; - -use hal::comparator::{COMP1, COMP2, COMP3, COMP4, COMP5, COMP6, COMP7}; -use hal::gpio::gpiob::{PB3, PB4, PB5, PB6, PB7, PB8, PB9}; -use hal::gpio::gpioc::{PC11, PC12, PC5, PC6}; -use hal::gpio::{self, AF13, AF3}; -use hal::pwm::Polarity; +use crate::stm32; + +use crate::Polarity; +#[cfg(feature = "stm32g4")] +use crate::hal::comparator::{COMP1, COMP2, COMP3, COMP4, COMP5, COMP6, COMP7}; +#[cfg(feature = "stm32g4")] +use crate::hal::gpio::gpiob::{PB3, PB4, PB5, PB6, PB7, PB8, PB9}; +#[cfg(feature = "stm32g4")] +use crate::hal::gpio::gpioc::{PC11, PC12, PC5, PC6}; +#[cfg(feature = "stm32g4")] +use crate::hal::gpio::{self, AF13, AF3}; use stm32::HRTIM_COMMON; use super::control::HrTimCalibrated; @@ -54,8 +58,9 @@ pub unsafe trait EevSrcBits: Sized { fn cfg(self) {} } +#[cfg(feature = "stm32g4")] macro_rules! impl_eev_input { - ($N:literal: COMP=[$compX:ident $(, ($compY:ident, $compY_src_bits:literal))*], PINS=[$(($pin:ident, $af:ident)),*]) => { + ($($N:literal: COMP=[$compX:ident $(, ($compY:ident, $compY_src_bits:literal))*], PINS=[$(($pin:ident, $af:ident)),*])*) => {$( $(unsafe impl EevSrcBits<$N> for $pin>{ const SRC_BITS: u8 = 0b00; fn cfg(self) { @@ -63,15 +68,15 @@ macro_rules! impl_eev_input { } })* - unsafe impl EevSrcBits<$N> for &hal::comparator::Comparator<$compX, ED> - where ED: hal::comparator::EnabledState + unsafe impl EevSrcBits<$N> for &crate::hal::comparator::Comparator<$compX, ED> + where ED: crate::hal::comparator::EnabledState { const SRC_BITS: u8 = 0b01; } $( - unsafe impl EevSrcBits<$N> for &hal::comparator::Comparator<$compY, ED> - where ED: hal::comparator::EnabledState + unsafe impl EevSrcBits<$N> for &crate::hal::comparator::Comparator<$compY, ED> + where ED: crate::hal::comparator::EnabledState { const SRC_BITS: u8 = $compY_src_bits; } @@ -85,21 +90,24 @@ macro_rules! impl_eev_input { unsafe { SourceBuilder::new(SRC::SRC_BITS) } } } - }; + )*}; +} + +#[cfg(feature = "stm32g4")] +impl_eev_input! { + 1: COMP = [COMP2], PINS = [(PC12, AF3)] + 2: COMP = [COMP4], PINS = [(PC11, AF3)] + 3: COMP = [COMP6], PINS = [(PB7, AF13)] + 4: COMP = [COMP1, (COMP5, 0b10)], PINS = [(PB6, AF13)] + 5: COMP = [COMP3, (COMP7, 0b10)], PINS = [(PB9, AF13)] + 6: COMP = [COMP2, (COMP1, 0b10)], PINS = [(PB5, AF13)] + 7: COMP = [COMP4], PINS = [(PB4, AF13)] + 8: COMP = [COMP6, (COMP3, 0b10)], PINS = [(PB8, AF13)] + 9: COMP = [COMP5, (COMP4, 0b11)], PINS = [(PB3, AF13)] + 10: COMP = [COMP7], PINS = [(PC5, AF13), (PC6, AF3)] } -impl_eev_input!(1: COMP = [COMP2], PINS = [(PC12, AF3)]); -impl_eev_input!(2: COMP = [COMP4], PINS = [(PC11, AF3)]); -impl_eev_input!(3: COMP = [COMP6], PINS = [(PB7, AF13)]); -impl_eev_input!(4: COMP = [COMP1, (COMP5, 0b10)], PINS = [(PB6, AF13)]); -impl_eev_input!(5: COMP = [COMP3, (COMP7, 0b10)], PINS = [(PB9, AF13)]); -impl_eev_input!(6: COMP = [COMP2, (COMP1, 0b10)], PINS = [(PB5, AF13)]); -impl_eev_input!(7: COMP = [COMP4], PINS = [(PB4, AF13)]); -impl_eev_input!(8: COMP = [COMP6, (COMP3, 0b10)], PINS = [(PB8, AF13)]); -impl_eev_input!(9: COMP = [COMP5, (COMP4, 0b11)], PINS = [(PB3, AF13)]); -impl_eev_input!(10: COMP = [COMP7], PINS = [(PC5, AF13), (PC6, AF3)]); - -#[derive(/*Copy, Clone, Debug, PartialEq*/ )] +#[derive()] pub enum EdgeOrPolarity { Edge(Edge), Polarity(Polarity), diff --git a/src/fault.rs b/src/fault.rs index 3b6f39d..25733b8 100644 --- a/src/fault.rs +++ b/src/fault.rs @@ -1,11 +1,17 @@ +#[cfg(feature = "stm32g4")] use crate::control::HrPwmControl; -use crate::hal; -use hal::comparator::{COMP1, COMP2, COMP3, COMP4, COMP5, COMP6}; -use hal::gpio::gpioa::{PA12, PA15}; -use hal::gpio::gpiob::{PB0, PB10, PB11}; -use hal::gpio::gpioc::{PC10, PC7}; -use hal::gpio::{self, AF13, AF3}; -use hal::stm32::HRTIM_COMMON; +use crate::stm32; + +#[cfg(feature = "stm32g4")] +use crate::hal::comparator::{COMP1, COMP2, COMP3, COMP4, COMP5, COMP6}; +#[cfg(feature = "stm32g4")] +use crate::hal::gpio::{ + self, AF13, AF3, + gpioa::{PA12, PA15}, + gpiob::{PB0, PB10, PB11}, + gpioc::{PC10, PC7}, +}; +use stm32::HRTIM_COMMON; use super::control::HrPwmCtrl; @@ -65,6 +71,7 @@ impl SourceBuilder { } } +#[cfg(feature = "stm32g4")] macro_rules! impl_faults { ($( $input:ident => $source:ident: @@ -95,7 +102,8 @@ macro_rules! impl_faults { } )* - pub fn bind_comp(self, _comp: &hal::comparator::Comparator<$compX, hal::comparator::Enabled>) -> SourceBuilder<$input> { + #[cfg(feature = "stm32g4")] + pub fn bind_comp(self, _comp: &crate::hal::comparator::Comparator<$compX, crate::hal::comparator::Enabled>) -> SourceBuilder<$input> { unsafe { SourceBuilder::new(self, 0b01) } } @@ -147,6 +155,7 @@ macro_rules! impl_faults { )+} } +#[cfg(feature = "stm32g4")] impl_faults!( FaultInput1 => FaultSource1: PINS=[(PA12, AF13)], COMP=COMP2, 0b000001, fltinr1, flt1src, flt1src_1, flt1p, flt1f, flt1e, flt1lck, FaultInput2 => FaultSource2: PINS=[(PA15, AF13)], COMP=COMP4, 0b000010, fltinr1, flt2src, flt2src_1, flt2p, flt2f, flt2e, flt2lck, @@ -157,22 +166,34 @@ impl_faults!( ); pub struct FaultInputs { + #[cfg(feature = "stm32g4")] pub fault_input1: FaultInput1, + #[cfg(feature = "stm32g4")] pub fault_input2: FaultInput2, + #[cfg(feature = "stm32g4")] pub fault_input3: FaultInput3, + #[cfg(feature = "stm32g4")] pub fault_input4: FaultInput4, + #[cfg(feature = "stm32g4")] pub fault_input5: FaultInput5, + #[cfg(feature = "stm32g4")] pub fault_input6: FaultInput6, } impl FaultInputs { pub(crate) unsafe fn new() -> Self { FaultInputs { + #[cfg(feature = "stm32g4")] fault_input1: FaultInput1, + #[cfg(feature = "stm32g4")] fault_input2: FaultInput2, + #[cfg(feature = "stm32g4")] fault_input3: FaultInput3, + #[cfg(feature = "stm32g4")] fault_input4: FaultInput4, + #[cfg(feature = "stm32g4")] fault_input5: FaultInput5, + #[cfg(feature = "stm32g4")] fault_input6: FaultInput6, } } @@ -267,5 +288,9 @@ impl_flt_monitor!( FltMonitor3: (flt3, flt3c, flt3ie), FltMonitor4: (flt4, flt4c, flt4ie), FltMonitor5: (flt5, flt5c, flt5ie), +); + +#[cfg(feature = "hrtim_v2")] +impl_flt_monitor!( FltMonitor6: (flt6, flt6c, flt6ie), ); diff --git a/src/lib.rs b/src/lib.rs index 2215b5b..93f5416 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,40 +12,40 @@ pub mod output; pub mod timer; pub mod timer_eev_cfg; -#[cfg(any(feature = "stm32f3"))] -pub use stm32f3xx_hal as hal; +#[cfg(feature = "stm32f3")] +#[path = "stm32f3.rs"] +mod mcu; -#[cfg(any(feature = "stm32h7"))] +#[cfg(feature = "stm32h7")] pub use stm32h7xx_hal as hal; -#[cfg(any(feature = "stm32g4"))] -#[path = "stm32g4.rs"]mod mcu; - -pub use mcu::{hal, hal::stm32}; +#[cfg(feature = "stm32g4")] +#[path = "stm32g4.rs"] +mod mcu; +pub use mcu::{hal, stm32, Polarity}; use core::marker::PhantomData; use core::mem::MaybeUninit; use crate::compare_register::{HrCr1, HrCr2, HrCr3, HrCr4}; use crate::fault::{FaultAction, FaultSource}; -use crate::timer::HrTim; +#[cfg(feature = "hrtim_v2")] +use crate::stm32::HRTIM_TIMF; use crate::stm32::{ HRTIM_COMMON, HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, - HRTIM_TIMF, }; +use crate::timer::HrTim; + use capture::{HrCaptCh1, HrCaptCh2}; -use fugit::HertzU64; use self::control::HrPwmControl; use self::deadtime::DeadtimeConfig; use self::output::ToHrOut; use self::timer_eev_cfg::EevCfgs; - -use hal::pwm::{self, Polarity}; -use hal::rcc::{GetBusFreq, Rcc}; -use hal::time::Hertz; +use fugit::HertzU32 as Hertz; +use hal::rcc::Rcc; /// Internal enum that keeps track of the count settings before PWM is finalized enum CountSettings { @@ -65,7 +65,6 @@ pub enum HrCountingDirection { /// Asymetrical up counting mode /// /// - /// * * /// Counting up * | * | /// * * @@ -86,6 +85,7 @@ pub enum HrCountingDirection { /// This is the most common mode with least amount of quirks Up, + #[cfg(feature = "hrtim_v2")] /// Symmetrical up-down counting mode /// /// @@ -118,11 +118,12 @@ pub enum HrCountingDirection { } // Needed to calculate frequency -impl From for pwm::Alignment { +impl From for crate::mcu::Alignment { fn from(val: HrCountingDirection) -> Self { match val { - HrCountingDirection::Up => pwm::Alignment::Left, - HrCountingDirection::UpDown => pwm::Alignment::Center, + HrCountingDirection::Up => crate::mcu::Alignment::Left, + #[cfg(feature = "hrtim_v2")] + HrCountingDirection::UpDown => crate::mcu::Alignment::Center, } } } @@ -186,7 +187,7 @@ pub struct HrPwmBuilder { pins: PINS, timer_mode: HrTimerMode, counting_direction: HrCountingDirection, - base_freq: HertzU64, + //base_freq: HertzU64, count: CountSettings, preload_source: Option, fault_enable_bits: u8, @@ -231,7 +232,7 @@ pub enum MasterPreloadSource { } macro_rules! hrtim_finalize_body { - ($this:expr, $PreloadSource:ident, $TIMX:ident, $($out:ident)*) => {{ + ($this:expr, $PreloadSource:ident, $TIMX:ident, [$($out:ident)*], $($moder:ident, $otyper:ident, $afr:ident)*) => {{ let tim = unsafe { &*$TIMX::ptr() }; let (period, prescaler_bits) = match $this.count { CountSettings::Period(period) => (period as u32, PSCL::BITS as u16), @@ -256,9 +257,6 @@ macro_rules! hrtim_finalize_body { // TODO: add support for more modes - // Interleaved mode - .intlvd().bits(intlvd) - // half/double interleaved mode .half().bit(half) @@ -266,11 +264,19 @@ macro_rules! hrtim_finalize_body { .ckpsc().bits(prescaler_bits as u8) }); + #[cfg(feature = "hrtim_v2")] + tim.cr().modify(|_r, w| unsafe { + // Interleaved mode + #[cfg(feature = "hrtim_v2")] + w.intlvd().bits(intlvd) + }); + $( // Only available for timers with outputs(not HRTIM_MASTER) #[allow(unused)] let $out = (); + #[cfg(feature = "hrtim_v2")] tim.cr2().modify(|_r, w| // Set counting direction w.udm().bit($this.counting_direction == HrCountingDirection::UpDown) @@ -299,8 +305,9 @@ macro_rules! hrtim_finalize_body { .flt3en().bit(fault_enable_bits & (1 << 2) != 0) .flt4en().bit(fault_enable_bits & (1 << 3) != 0) .flt5en().bit(fault_enable_bits & (1 << 4) != 0) - .flt6en().bit(fault_enable_bits & (1 << 5) != 0) ); + #[cfg(feature = "hrtim_v2")] + tim.fltr().modify(|_, w| w.flt6en().bit(fault_enable_bits & (1 << 5) != 0)); // ... and lock configuration tim.fltr().modify(|_r, w| w.fltlck().set_bit()); @@ -357,6 +364,7 @@ macro_rules! hrtim_finalize_body { .ee9ltch().bit(eev_cfg.eev9.latch_bit).ee9fltr().bits(eev_cfg.eev9.filter_bits) .ee10ltch().bit(eev_cfg.eev10.latch_bit).ee10fltr().bits(eev_cfg.eev10.filter_bits) ); + #[cfg(feature = "hrtim_v2")] tim.eefr3().write(|w| w .eevace().bit(eev_cfg.event_counter_enable_bit) // External Event A Counter Reset"] @@ -381,7 +389,7 @@ macro_rules! hrtim_finalize_body { //master.mcr.modify(|_r, w| { w.$tXcen().set_bit() }); // Connect pins and let HRTIM take over control over them - $this.pins.connect_to_hrtim(); + $this.pins.connect_to_hrtim($($moder, $otyper, $afr)*); unsafe { MaybeUninit::uninit().assume_init() @@ -451,7 +459,7 @@ macro_rules! hrtim_common_methods { enable_push_pull, interleaved_mode, counting_direction, - base_freq, + //base_freq, count, preload_source, repetition_counter, @@ -480,7 +488,7 @@ macro_rules! hrtim_common_methods { enable_push_pull, interleaved_mode, counting_direction, - base_freq, + //base_freq, count, preload_source, repetition_counter, @@ -538,7 +546,7 @@ macro_rules! hrtim_hal { fn pwm_advanced( self, pins: PINS, - rcc: &mut Rcc, + _rcc: &mut Rcc, ) -> HrPwmBuilder where PINS: ToHrOut<$TIMX>, @@ -546,7 +554,7 @@ macro_rules! hrtim_hal { // TODO: That 32x factor... Is that included below, or should we // do that? Also that will likely risk overflowing u32 since // 170MHz * 32 = 5.44GHz > u32::MAX.Hz() - let clk = HertzU64::from(HRTIM_COMMON::get_timer_frequency(&rcc.clocks)) * 32; + //let clk = HertzU64::from(HRTIM_COMMON::get_timer_frequency(&rcc.clocks)) * 32; HrPwmBuilder { _tim: PhantomData, @@ -557,7 +565,7 @@ macro_rules! hrtim_hal { fault1_bits: 0b00, fault2_bits: 0b00, counting_direction: HrCountingDirection::Up, - base_freq: clk, + //base_freq: clk, count: CountSettings::Period(u16::MAX), preload_source: None, enable_push_pull: false, @@ -578,11 +586,24 @@ macro_rules! hrtim_hal { PSCL: HrtimPrescaler, PINS: ToHrOut<$TIMX>, { - pub fn finalize(self, _control: &mut HrPwmControl) -> HrParts<$TIMX, PSCL, PINS::Out> { - hrtim_finalize_body!( - self, PreloadSource, - $TIMX, $($out)* - ) + pub fn finalize(self, _control: &mut HrPwmControl, + #[cfg(feature = "stm32f3")] + moder: &mut ::MODER, + #[cfg(feature = "stm32f3")] + otyper: &mut ::OTYPER, + #[cfg(feature = "stm32f3")] + afr: &mut PINS::Afr + ) -> HrParts<$TIMX, PSCL, PINS::Out> { + #[cfg(feature = "stm32f3")] { + hrtim_finalize_body!( + self, PreloadSource, + $TIMX, [$($out)*], moder, otyper, afr + ) + } + + #[cfg(feature = "stm32g4")] { + hrtim_finalize_body!(self, PreloadSource, $TIMX, [$($out)*],) + } } hrtim_common_methods!($TIMX, PreloadSource); @@ -679,7 +700,7 @@ impl HrPwmAdvExt for HRTIM_MASTER { fn pwm_advanced( self, pins: PINS, - rcc: &mut Rcc, + _rcc: &mut Rcc, ) -> HrPwmBuilder where PINS: ToHrOut, @@ -687,7 +708,7 @@ impl HrPwmAdvExt for HRTIM_MASTER { // TODO: That 32x factor... Is that included below, or should we // do that? Also that will likely risk overflowing u32 since // 170MHz * 32 = 5.44GHz > u32::MAX.Hz() - let clk = HertzU64::from(HRTIM_COMMON::get_timer_frequency(&rcc.clocks)) * 32; + //let clk = HertzU64::from(HRTIM_COMMON::get_timer_frequency(&rcc.clocks)) * 32; HrPwmBuilder { _tim: PhantomData, @@ -698,7 +719,7 @@ impl HrPwmAdvExt for HRTIM_MASTER { fault1_bits: 0b00, fault2_bits: 0b00, counting_direction: HrCountingDirection::Up, - base_freq: clk, + //base_freq: clk, count: CountSettings::Period(u16::MAX), preload_source: None, enable_push_pull: false, @@ -718,8 +739,21 @@ where PSCL: HrtimPrescaler, PINS: ToHrOut, { - pub fn finalize(self, _control: &mut HrPwmControl) -> HrParts { - hrtim_finalize_body!(self, MasterPreloadSource, HRTIM_MASTER,) + pub fn finalize(self, _control: &mut HrPwmControl, + #[cfg(feature = "stm32f3")] + moder: &mut ::MODER, + #[cfg(feature = "stm32f3")] + otyper: &mut ::OTYPER, + #[cfg(feature = "stm32f3")] + afr: &mut PINS::Afr + ) -> HrParts { + #[cfg(feature = "stm32f3")]{ + hrtim_finalize_body!(self, MasterPreloadSource, HRTIM_MASTER, [], moder, otyper, afr) + } + + #[cfg(feature = "stm32g4")] { + hrtim_finalize_body!(self, MasterPreloadSource, HRTIM_MASTER, [],) + } } hrtim_common_methods!(HRTIM_MASTER, MasterPreloadSource); @@ -731,6 +765,10 @@ hrtim_hal! { HRTIM_TIMC: out, HRTIM_TIMD: out, HRTIM_TIME: out, +} + +#[cfg(feature = "hrtim_v2")] +hrtim_hal! { HRTIM_TIMF: out, } @@ -795,4 +833,4 @@ impl pwm::TimerType for TimerHrTim { (period, PSC::BITS.into()) } } -*/ \ No newline at end of file +*/ diff --git a/src/output.rs b/src/output.rs index 01b2042..a6e8f3c 100644 --- a/src/output.rs +++ b/src/output.rs @@ -1,18 +1,23 @@ + +#[cfg(feature = "hrtim_v2")] +use crate::stm32::HRTIM_TIMF; use crate::{ hal, - stm32::{HRTIM_COMMON, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF}, + mcu::GpioInputMode, + stm32::{HRTIM_COMMON, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME}, }; use core::marker::PhantomData; use super::event::EventSource; use hal::gpio::{ - self, gpioa::{PA10, PA11, PA8, PA9}, gpiob::{PB12, PB13, PB14, PB15}, - gpioc::{PC6, PC7, PC8, PC9}, - Alternate, AF13, AF3, + gpioc::{PC8, PC9}, }; +#[cfg(feature = "stm32g4")] +use hal::gpio::gpioc::{PC6, PC7}; + mod sealed { pub trait Sealed {} } @@ -83,7 +88,10 @@ hrtim_out! { HRTIM_TIME: HrOut1: te1oen, te1odis, te1ods, set1r, rst1r, HRTIM_TIME: HrOut2: te2oen, te2odis, te2ods, set2r, rst2r, +} +#[cfg(feature = "hrtim_v2")] +hrtim_out! { HRTIM_TIMF: HrOut1: tf1oen, tf1odis, tf1ods, set1r, rst1r, HRTIM_TIMF: HrOut2: tf2oen, tf2odis, tf2ods, set2r, rst2r, } @@ -142,7 +150,19 @@ impl State { pub trait ToHrOut: sealed::Sealed { type Out; - fn connect_to_hrtim(self); + #[cfg(feature = "stm32f3")] + type GpioX: hal::gpio::marker::GpioStatic; + #[cfg(feature = "stm32f3")] + type Afr; + + fn connect_to_hrtim(self, + #[cfg(feature = "stm32f3")] + moder: &mut ::MODER, + #[cfg(feature = "stm32f3")] + otyper: &mut ::OTYPER, + #[cfg(feature = "stm32f3")] + afr: &mut Self::Afr + ); } impl sealed::Sealed for (PA, PB) @@ -152,6 +172,30 @@ where { } +#[cfg(feature = "stm32f3")] +impl ToHrOut for (PA, PB) +where + PA: ToHrOut, + PB: ToHrOut, +{ + type Out = (PA::Out, PB::Out); + type GpioX = PA::GpioX; + type Afr = PA::Afr; + + fn connect_to_hrtim(self, + + moder: &mut ::MODER, + + otyper: &mut ::OTYPER, + + afr: &mut Self::Afr + ) { + self.0.connect_to_hrtim(moder, otyper, afr); + self.1.connect_to_hrtim(moder, otyper, afr); + } +} + +#[cfg(feature = "stm32g4")] impl ToHrOut for (PA, PB) where PA: ToHrOut, @@ -168,47 +212,78 @@ where pub struct HrOut1(PhantomData<(TIM, PSCL)>); pub struct HrOut2(PhantomData<(TIM, PSCL)>); -macro_rules! pins { - ($($TIMX:ty: CH1: $CH1:ident<$CH1_AF:ident>, CH2: $CH2:ident<$CH2_AF:ident>)+) => { - $( - impl sealed::Sealed<$TIMX> for $CH1> {} - impl sealed::Sealed<$TIMX> for $CH2> {} - - impl ToHrOut<$TIMX> for $CH1> { - type Out = HrOut1<$TIMX, PSCL>; - - fn connect_to_hrtim(self) { - let _: $CH1> = self.into_alternate(); - } +macro_rules! pins_helper { + ($TIMX:ty, $HrOutY:ident, $CHY:ident<$CHY_AF:literal>, $GpioX:ident) => { + impl sealed::Sealed<$TIMX> for $CHY {} + + impl ToHrOut<$TIMX> for $CHY { + type Out = $HrOutY<$TIMX, PSCL>; + + #[cfg(feature = "stm32f3")] + type GpioX = hal::gpio::$GpioX; + #[cfg(feature = "stm32f3")] + type Afr = >::AFR; + + // Pin> + fn connect_to_hrtim( + self, + #[cfg(feature = "stm32f3")] + moder: &mut ::MODER, + #[cfg(feature = "stm32f3")] + otyper: &mut ::OTYPER, + #[cfg(feature = "stm32f3")] + afr: &mut Self::Afr + ) { + #[allow(non_snake_case, unused_variables)] + let $GpioX = (); + + #[cfg(feature = "stm32f3")] + let _: $CHY> = self.into_af_push_pull(moder, otyper, afr); + + #[cfg(feature = "stm32g4")] + let _: $CHY> = self.into_alternate(); } + } + }; +} - impl ToHrOut<$TIMX> for $CH2> { - type Out = HrOut2<$TIMX, PSCL>; - - fn connect_to_hrtim(self) { - let _: $CH2> = self.into_alternate(); - } - } - )+ - } +macro_rules! pins { + ($($TIMX:ty: CH1: $CH1:ident<$CH1_AF:literal>, CH2: $CH2:ident<$CH2_AF:literal>, $GpioX:ident)+) => {$( + pins_helper!($TIMX, HrOut1, $CH1<$CH1_AF>, $GpioX); + pins_helper!($TIMX, HrOut2, $CH2<$CH2_AF>, $GpioX); + )+}; } +#[cfg(any(feature = "stm32g4", feature = "stm32f3"))] pins! { - HRTIM_TIMA: CH1: PA8, CH2: PA9 - - HRTIM_TIMB: CH1: PA10, CH2: PA11 - HRTIM_TIMC: CH1: PB12, CH2: PB13 - HRTIM_TIMD: CH1: PB14, CH2: PB15 + HRTIM_TIMA: CH1: PA8<13>, CH2: PA9<13>, Gpioa + HRTIM_TIMB: CH1: PA10<13>, CH2: PA11<13>, Gpioa + HRTIM_TIMC: CH1: PB12<13>, CH2: PB13<13>, Gpiob + HRTIM_TIMD: CH1: PB14<13>, CH2: PB15<13>, Gpiob + HRTIM_TIME: CH1: PC8<3>, CH2: PC9<3>, Gpioc +} - HRTIM_TIME: CH1: PC8, CH2: PC9 - HRTIM_TIMF: CH1: PC6, CH2: PC7 +#[cfg(feature = "stm32g4")] +pins! { + HRTIM_TIMF: CH1: PC6<13>, CH2: PC7<13>, Gpioc } impl sealed::Sealed for () {} impl ToHrOut for () { type Out = (); - - fn connect_to_hrtim(self) {} + #[cfg(feature = "stm32f3")] + type GpioX = hal::gpio::Gpioa; + #[cfg(feature = "stm32f3")] + type Afr = (); + + fn connect_to_hrtim(self, + #[cfg(feature = "stm32f3")] + _moder: &mut ::MODER, + #[cfg(feature = "stm32f3")] + _otyper: &mut ::OTYPER, + #[cfg(feature = "stm32f3")] + _afr: &mut Self::Afr + ) {} } pub struct CH1(PhantomData); diff --git a/src/stm32f3.rs b/src/stm32f3.rs new file mode 100644 index 0000000..b322544 --- /dev/null +++ b/src/stm32f3.rs @@ -0,0 +1,18 @@ + +pub use stm32f3xx_hal as hal; +//pub use hal::pac as stm32; +pub use stm32f3::stm32f3x4 as stm32; + +#[allow(non_camel_case_types, dead_code)] +pub enum DmaMuxResources { + +} + +pub type GpioInputMode = hal::gpio::Input; + +pub enum Alignment { Left } +#[cfg(feature = "stm32f3")] +pub enum Polarity { + ActiveHigh, + ActiveLow, +} \ No newline at end of file diff --git a/src/stm32g4.rs b/src/stm32g4.rs index a0de127..f3683ab 100644 --- a/src/stm32g4.rs +++ b/src/stm32g4.rs @@ -1,5 +1,6 @@ pub use stm32g4xx_hal as hal; +pub use hal::stm32; #[allow(non_camel_case_types, dead_code)] pub enum DmaMuxResources { @@ -10,4 +11,11 @@ pub enum DmaMuxResources { HRTIM_TIMD = 99, HRTIM_TIME = 100, HRTIM_TIMF = 101, -} \ No newline at end of file +} + +pub type GpioInputMode = hal::gpio::Input; + +pub use hal::pwm::Alignment; + +#[cfg(feature = "stm32g4")] +pub use hal::pwm::Polarity; \ No newline at end of file diff --git a/src/timer.rs b/src/timer.rs index bbc5dc8..01f090c 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,6 +1,8 @@ use crate::stm32::{ - HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF, + HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, }; +#[cfg(feature = "hrtim_v2")] +use crate::stm32::HRTIM_TIMF; use core::marker::PhantomData; use super::{ @@ -294,6 +296,7 @@ macro_rules! hrtim_timer { )+} } +#[cfg(feature = "stm32g4")] macro_rules! hrtim_timer_adc_trigger { ($($TIMX:ident: [$(($AdcTrigger:ident: [ @@ -313,9 +316,13 @@ macro_rules! hrtim_timer_adc_trigger { } } +#[cfg(feature = "stm32g4")] use super::adc_trigger::Adc13Trigger as Adc13; +#[cfg(feature = "stm32g4")] use super::adc_trigger::Adc24Trigger as Adc24; +#[cfg(feature = "stm32g4")] use super::adc_trigger::Adc579Trigger as Adc579; +#[cfg(feature = "stm32g4")] use super::adc_trigger::Adc6810Trigger as Adc6810; hrtim_timer! { @@ -326,9 +333,11 @@ hrtim_timer! { HRTIM_TIMC: tccen, tcudis, (rstr), HRTIM_TIMD: tdcen, tdudis, (rstr), HRTIM_TIME: tecen, teudis, (rstr), - HRTIM_TIMF: tfcen, tfudis, (rstr), } +#[cfg(feature = "hrtim_v2")] +hrtim_timer! {HRTIM_TIMF: tfcen, tfudis, (rstr),} +#[cfg(feature = "stm32g4")] hrtim_timer_adc_trigger! { HRTIM_MASTER: [(Adc13: [(PER: 1 << 4),]), (Adc24: [(PER: 1 << 4),]), (Adc579: [(PER: 4),]), (Adc6810: [(PER: 4),])], diff --git a/src/timer_eev_cfg.rs b/src/timer_eev_cfg.rs index 96f79bd..545a84a 100644 --- a/src/timer_eev_cfg.rs +++ b/src/timer_eev_cfg.rs @@ -16,9 +16,13 @@ pub struct EevCfgs { // TODO: Note there are some peculiarities here with fast mode // One way to prevent missuse would be to require a borrowed ExternalEventSource when setting // filter/latching as well as the event_counter related settings below. + #[cfg(feature = "hrtim_v2")] pub(crate) event_counter_enable_bit: bool, + #[cfg(feature = "hrtim_v2")] pub(crate) event_counter_reset_mode_bit: bool, + #[cfg(feature = "hrtim_v2")] pub(crate) event_counter_source_bits: u8, + #[cfg(feature = "hrtim_v2")] pub(crate) event_counter_threshold_bits: u8, } @@ -57,9 +61,13 @@ impl Clone for EevCfgs { eev8: self.eev8.clone(), eev9: self.eev9.clone(), eev10: self.eev10.clone(), + #[cfg(feature = "hrtim_v2")] event_counter_enable_bit: self.event_counter_enable_bit, + #[cfg(feature = "hrtim_v2")] event_counter_reset_mode_bit: self.event_counter_reset_mode_bit, + #[cfg(feature = "hrtim_v2")] event_counter_source_bits: self.event_counter_source_bits, + #[cfg(feature = "hrtim_v2")] event_counter_threshold_bits: self.event_counter_threshold_bits, } } @@ -185,9 +193,13 @@ impl Default for EevCfgs { eev8: Default::default(), eev9: Default::default(), eev10: Default::default(), + #[cfg(feature = "hrtim_v2")] event_counter_enable_bit: false, + #[cfg(feature = "hrtim_v2")] event_counter_reset_mode_bit: false, + #[cfg(feature = "hrtim_v2")] event_counter_source_bits: 0, + #[cfg(feature = "hrtim_v2")] event_counter_threshold_bits: 0, } } From 481c3f3ad825d84edb37127882bfe25c0d9fd013 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 4 Dec 2024 18:04:51 +0100 Subject: [PATCH 05/25] CI --- .github/workflows/ci.yml | 54 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..f9733d2 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,54 @@ +on: + pull_request: + +name: Continuous integration + +# Make sure CI fails on all warnings, including Clippy lints +env: + RUSTFLAGS: "-Dwarnings" + +jobs: + ci: + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - stable + device: + - stm32f334x4 + - stm32f334x6 + - stm32f334x8 + + #- stm32h742 + #- stm32h743 + ##- stm32h745 + ##- stm32h747 + #- stm32h750 + #- stm32h753 + ##- stm32h755 + ##- stm32h757 + + - stm32g474 + - stm32g484 + features: + - log-rtt,defmt + # TODO: -log-rtt # log-rtt without defmt, more combos? + - log-itm + - log-semihost + - cordic,log-rtt,defmt + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + target: thumbv7em-none-eabihf + override: true + + - name: Regular build + run: cargo check --features ${{ matrix.device }} --features ${{ matrix.features }} + - name: Build examples + run: cargo check --examples --features ${{ matrix.device }} --features ${{ matrix.features }} + - name: Clippy + run: cargo clippy --examples --features ${{ matrix.device }} --features ${{ matrix.features }} From 22e8de9c6cfb37dd4ba16f05f739f613fb995a0a Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 4 Dec 2024 18:06:26 +0100 Subject: [PATCH 06/25] CI --- .github/workflows/ci.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f9733d2..57a8de9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,11 +31,7 @@ jobs: - stm32g474 - stm32g484 features: - - log-rtt,defmt - # TODO: -log-rtt # log-rtt without defmt, more combos? - - log-itm - - log-semihost - - cordic,log-rtt,defmt + - defmt steps: - uses: actions/checkout@v2 From fd57d0e3da7cd27fa58932e79e89bc60b3edf991 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 4 Dec 2024 18:07:14 +0100 Subject: [PATCH 07/25] fmt --- src/capture.rs | 4 ++-- src/compare_register.rs | 6 ++---- src/control.rs | 4 ++-- src/external_event.rs | 2 +- src/fault.rs | 3 ++- src/lib.rs | 23 ++++++++++++++++------ src/output.rs | 43 +++++++++++++++++++++-------------------- src/stm32f3.rs | 11 +++++------ src/stm32g4.rs | 5 ++--- src/timer.rs | 4 +--- 10 files changed, 56 insertions(+), 49 deletions(-) diff --git a/src/capture.rs b/src/capture.rs index 7e37828..52c5dd2 100644 --- a/src/capture.rs +++ b/src/capture.rs @@ -2,10 +2,10 @@ use crate::stm32; use super::timer; -#[cfg(feature = "stm32g4")] -use crate::mcu::DmaMuxResources; #[cfg(feature = "stm32g4")] use crate::hal::dma::PeripheralToMemory; +#[cfg(feature = "stm32g4")] +use crate::mcu::DmaMuxResources; use core::marker::PhantomData; #[cfg(feature = "hrtim_v2")] diff --git a/src/compare_register.rs b/src/compare_register.rs index 2d6f1d5..1afa31f 100644 --- a/src/compare_register.rs +++ b/src/compare_register.rs @@ -1,10 +1,8 @@ use core::marker::PhantomData; -use crate::stm32::{ - HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, -}; #[cfg(feature = "hrtim_v2")] use crate::stm32::HRTIM_TIMF; +use crate::stm32::{HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME}; pub trait HrCompareRegister { fn get_duty(&self) -> u16; @@ -195,4 +193,4 @@ hrtim_timer_rst! { hrtim_timer_rst! { HRTIM_TIMF: HrCr2: 2, HRTIM_TIMF: HrCr4: 3 -} \ No newline at end of file +} diff --git a/src/control.rs b/src/control.rs index 763f78c..1d264b8 100644 --- a/src/control.rs +++ b/src/control.rs @@ -1,8 +1,8 @@ +#[cfg(feature = "hrtim_v2")] +use crate::fault::FltMonitor6; use crate::fault::{ FltMonitor1, FltMonitor2, FltMonitor3, FltMonitor4, FltMonitor5, FltMonitorSys, }; -#[cfg(feature = "hrtim_v2")] -use crate::fault::FltMonitor6; use crate::{hal, stm32}; use hal::rcc::{Enable, Rcc, Reset}; diff --git a/src/external_event.rs b/src/external_event.rs index 49df65f..c08f3cb 100644 --- a/src/external_event.rs +++ b/src/external_event.rs @@ -1,6 +1,5 @@ use crate::stm32; -use crate::Polarity; #[cfg(feature = "stm32g4")] use crate::hal::comparator::{COMP1, COMP2, COMP3, COMP4, COMP5, COMP6, COMP7}; #[cfg(feature = "stm32g4")] @@ -9,6 +8,7 @@ use crate::hal::gpio::gpiob::{PB3, PB4, PB5, PB6, PB7, PB8, PB9}; use crate::hal::gpio::gpioc::{PC11, PC12, PC5, PC6}; #[cfg(feature = "stm32g4")] use crate::hal::gpio::{self, AF13, AF3}; +use crate::Polarity; use stm32::HRTIM_COMMON; use super::control::HrTimCalibrated; diff --git a/src/fault.rs b/src/fault.rs index 25733b8..59493db 100644 --- a/src/fault.rs +++ b/src/fault.rs @@ -6,10 +6,11 @@ use crate::stm32; use crate::hal::comparator::{COMP1, COMP2, COMP3, COMP4, COMP5, COMP6}; #[cfg(feature = "stm32g4")] use crate::hal::gpio::{ - self, AF13, AF3, + self, gpioa::{PA12, PA15}, gpiob::{PB0, PB10, PB11}, gpioc::{PC10, PC7}, + AF13, AF3, }; use stm32::HRTIM_COMMON; diff --git a/src/lib.rs b/src/lib.rs index 93f5416..8ccd470 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -739,19 +739,30 @@ where PSCL: HrtimPrescaler, PINS: ToHrOut, { - pub fn finalize(self, _control: &mut HrPwmControl, + pub fn finalize( + self, + _control: &mut HrPwmControl, #[cfg(feature = "stm32f3")] moder: &mut ::MODER, #[cfg(feature = "stm32f3")] otyper: &mut ::OTYPER, - #[cfg(feature = "stm32f3")] - afr: &mut PINS::Afr + #[cfg(feature = "stm32f3")] afr: &mut PINS::Afr, ) -> HrParts { - #[cfg(feature = "stm32f3")]{ - hrtim_finalize_body!(self, MasterPreloadSource, HRTIM_MASTER, [], moder, otyper, afr) + #[cfg(feature = "stm32f3")] + { + hrtim_finalize_body!( + self, + MasterPreloadSource, + HRTIM_MASTER, + [], + moder, + otyper, + afr + ) } - #[cfg(feature = "stm32g4")] { + #[cfg(feature = "stm32g4")] + { hrtim_finalize_body!(self, MasterPreloadSource, HRTIM_MASTER, [],) } } diff --git a/src/output.rs b/src/output.rs index a6e8f3c..2b06f7f 100644 --- a/src/output.rs +++ b/src/output.rs @@ -1,4 +1,3 @@ - #[cfg(feature = "hrtim_v2")] use crate::stm32::HRTIM_TIMF; use crate::{ @@ -155,13 +154,13 @@ pub trait ToHrOut: sealed::Sealed { #[cfg(feature = "stm32f3")] type Afr; - fn connect_to_hrtim(self, + fn connect_to_hrtim( + self, #[cfg(feature = "stm32f3")] moder: &mut ::MODER, #[cfg(feature = "stm32f3")] otyper: &mut ::OTYPER, - #[cfg(feature = "stm32f3")] - afr: &mut Self::Afr + #[cfg(feature = "stm32f3")] afr: &mut Self::Afr, ); } @@ -176,22 +175,23 @@ where impl ToHrOut for (PA, PB) where PA: ToHrOut, - PB: ToHrOut, + PB: ToHrOut, { type Out = (PA::Out, PB::Out); type GpioX = PA::GpioX; type Afr = PA::Afr; - fn connect_to_hrtim(self, - + fn connect_to_hrtim( + self, + moder: &mut ::MODER, - + otyper: &mut ::OTYPER, - - afr: &mut Self::Afr + + afr: &mut Self::Afr, ) { - self.0.connect_to_hrtim(moder, otyper, afr); - self.1.connect_to_hrtim(moder, otyper, afr); + self.0.connect_to_hrtim(moder, otyper, afr); + self.1.connect_to_hrtim(moder, otyper, afr); } } @@ -222,7 +222,7 @@ macro_rules! pins_helper { #[cfg(feature = "stm32f3")] type GpioX = hal::gpio::$GpioX; #[cfg(feature = "stm32f3")] - type Afr = >::AFR; + type Afr = >::AFR; // Pin> fn connect_to_hrtim( @@ -231,17 +231,17 @@ macro_rules! pins_helper { moder: &mut ::MODER, #[cfg(feature = "stm32f3")] otyper: &mut ::OTYPER, - #[cfg(feature = "stm32f3")] - afr: &mut Self::Afr + #[cfg(feature = "stm32f3")] afr: &mut Self::Afr, ) { #[allow(non_snake_case, unused_variables)] let $GpioX = (); #[cfg(feature = "stm32f3")] - let _: $CHY> = self.into_af_push_pull(moder, otyper, afr); + let _: $CHY> = + self.into_af_push_pull(moder, otyper, afr); #[cfg(feature = "stm32g4")] - let _: $CHY> = self.into_alternate(); + let _: $CHY> = self.into_alternate(); } } }; @@ -276,14 +276,15 @@ impl ToHrOut for () { #[cfg(feature = "stm32f3")] type Afr = (); - fn connect_to_hrtim(self, + fn connect_to_hrtim( + self, #[cfg(feature = "stm32f3")] _moder: &mut ::MODER, #[cfg(feature = "stm32f3")] _otyper: &mut ::OTYPER, - #[cfg(feature = "stm32f3")] - _afr: &mut Self::Afr - ) {} + #[cfg(feature = "stm32f3")] _afr: &mut Self::Afr, + ) { + } } pub struct CH1(PhantomData); diff --git a/src/stm32f3.rs b/src/stm32f3.rs index b322544..1ca5c39 100644 --- a/src/stm32f3.rs +++ b/src/stm32f3.rs @@ -1,18 +1,17 @@ - pub use stm32f3xx_hal as hal; //pub use hal::pac as stm32; pub use stm32f3::stm32f3x4 as stm32; #[allow(non_camel_case_types, dead_code)] -pub enum DmaMuxResources { - -} +pub enum DmaMuxResources {} pub type GpioInputMode = hal::gpio::Input; -pub enum Alignment { Left } +pub enum Alignment { + Left, +} #[cfg(feature = "stm32f3")] pub enum Polarity { ActiveHigh, ActiveLow, -} \ No newline at end of file +} diff --git a/src/stm32g4.rs b/src/stm32g4.rs index f3683ab..a42b791 100644 --- a/src/stm32g4.rs +++ b/src/stm32g4.rs @@ -1,6 +1,5 @@ - -pub use stm32g4xx_hal as hal; pub use hal::stm32; +pub use stm32g4xx_hal as hal; #[allow(non_camel_case_types, dead_code)] pub enum DmaMuxResources { @@ -18,4 +17,4 @@ pub type GpioInputMode = hal::gpio::Input; pub use hal::pwm::Alignment; #[cfg(feature = "stm32g4")] -pub use hal::pwm::Polarity; \ No newline at end of file +pub use hal::pwm::Polarity; diff --git a/src/timer.rs b/src/timer.rs index 01f090c..d03ed0d 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,8 +1,6 @@ -use crate::stm32::{ - HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, -}; #[cfg(feature = "hrtim_v2")] use crate::stm32::HRTIM_TIMF; +use crate::stm32::{HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME}; use core::marker::PhantomData; use super::{ From 6add5b80b271eb585047bfba9f51876774551ddf Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 4 Dec 2024 18:24:23 +0100 Subject: [PATCH 08/25] Dont use local hal --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c0a4e94..cf41e1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,8 +12,8 @@ stm32f3 = { git = "https://github.com/stm32-rs/stm32-rs-nightlies", optional = t stm32f3xx-hal = { version = "0.10.0", optional = true } stm32h7xx-hal = { version = "0.16.0", optional = true } #stm32g4xx-hal = { version = "0.0.1", optional = true } -#stm32g4xx-hal = { git = "https://github.com/stm32-rs/stm32g4xx-hal", branch = "staged-pac", optional = true } -stm32g4xx-hal = { path = "../stm32g4xx-hal", optional = true } +stm32g4xx-hal = { git = "https://github.com/stm32-rs/stm32g4xx-hal", branch = "staged-pac", optional = true } +#stm32g4xx-hal = { path = "../stm32g4xx-hal", optional = true } defmt = { version = "0.3.10", optional = true } fugit = "0.3.7" From 3426821fcde3bde29126d41243fb58b1e0e75fea Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 4 Dec 2024 20:46:15 +0100 Subject: [PATCH 09/25] Fix some warnings --- src/capture.rs | 4 ++-- src/control.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/capture.rs b/src/capture.rs index 52c5dd2..96bef80 100644 --- a/src/capture.rs +++ b/src/capture.rs @@ -129,7 +129,7 @@ pub trait HrCapture { /// <-------------- 0 --------------> t /// Negative result | positive result /// ``` - fn get_last_signed(&self, period: u16) -> i32 { + fn get_last_signed(&self, #[allow(unused_variables)] period: u16) -> i32 { let (value, dir) = self.get_last(); // The capture counter always counts up and restarts at period @@ -157,7 +157,7 @@ pub fn dma_value_to_dir_and_value(x: u32) -> (u16, CountingDirection) { (value, CountingDirection::Up) } -pub fn dma_value_to_signed(x: u32, period: u16) -> i32 { +pub fn dma_value_to_signed(x: u32, #[allow(unused_variables)] period: u16) -> i32 { let (value, dir) = dma_value_to_dir_and_value(x); // The capture counter always counts up and restarts at period diff --git a/src/control.rs b/src/control.rs index 1d264b8..372caec 100644 --- a/src/control.rs +++ b/src/control.rs @@ -6,7 +6,7 @@ use crate::fault::{ use crate::{hal, stm32}; use hal::rcc::{Enable, Rcc, Reset}; -use stm32::{HRTIM_COMMON, RCC}; +use stm32::HRTIM_COMMON; use super::{external_event::EevInputs, fault::FaultInputs}; @@ -15,15 +15,15 @@ pub trait HrControltExt { } impl HrControltExt for HRTIM_COMMON { - fn hr_control(self, _rcc: &mut Rcc) -> HrTimOngoingCalibration { + fn hr_control(self, #[allow(unused_variables)] rcc: &mut Rcc) -> HrTimOngoingCalibration { let common = unsafe { &*HRTIM_COMMON::ptr() }; unsafe { #[cfg(feature = "stm32g4")] - let rcc_ptr = &*RCC::ptr(); + let rcc_ptr = &*stm32::RCC::ptr(); #[cfg(feature = "stm32f3")] - let rcc_ptr = &mut *RCC::ptr(); + let rcc_ptr = &mut rcc.apb2; ::enable(rcc_ptr); ::reset(rcc_ptr); From 14d7f874624fbc58682c9eda91ea3df3689eff76 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 4 Dec 2024 20:46:38 +0100 Subject: [PATCH 10/25] Dont use local hal --- Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cf41e1e..a92f84f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,8 @@ stm32f3 = { git = "https://github.com/stm32-rs/stm32-rs-nightlies", optional = t #stm32h7 = { git = "", optional = true } #stm32g4 = { git = "", optional = true } -stm32f3xx-hal = { version = "0.10.0", optional = true } +#stm32f3xx-hal = { version = "0.10.0", optional = true } +stm32f3xx-hal = { git = "https://github.com/usbalbin/stm32f3xx-hal", branch = "update_for_new_pac", optional = true } stm32h7xx-hal = { version = "0.16.0", optional = true } #stm32g4xx-hal = { version = "0.0.1", optional = true } stm32g4xx-hal = { git = "https://github.com/stm32-rs/stm32g4xx-hal", branch = "staged-pac", optional = true } From 1104866c7775ebc7d63ed1862080aa2d45a51fee Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 4 Dec 2024 21:04:36 +0100 Subject: [PATCH 11/25] Fix more warnings --- src/control.rs | 19 +++++++++++-------- src/external_event.rs | 1 + src/fault.rs | 2 ++ src/lib.rs | 9 ++++++--- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/control.rs b/src/control.rs index 372caec..03bfc33 100644 --- a/src/control.rs +++ b/src/control.rs @@ -18,16 +18,19 @@ impl HrControltExt for HRTIM_COMMON { fn hr_control(self, #[allow(unused_variables)] rcc: &mut Rcc) -> HrTimOngoingCalibration { let common = unsafe { &*HRTIM_COMMON::ptr() }; - unsafe { - #[cfg(feature = "stm32g4")] - let rcc_ptr = &*stm32::RCC::ptr(); + let rcc_ptr = { + #[cfg(feature = "stm32g4")] unsafe { + &*stm32::RCC::ptr() + } - #[cfg(feature = "stm32f3")] - let rcc_ptr = &mut rcc.apb2; + #[cfg(feature = "stm32f3")] { + &mut rcc.apb2 + } + }; - ::enable(rcc_ptr); - ::reset(rcc_ptr); - } + ::enable(rcc_ptr); + ::reset(rcc_ptr); + // Start calibration procedure common diff --git a/src/external_event.rs b/src/external_event.rs index c08f3cb..ceea360 100644 --- a/src/external_event.rs +++ b/src/external_event.rs @@ -195,6 +195,7 @@ pub struct SourceBuilder { filter_bits: u8, } +#[cfg(feature = "stm32g4")] impl SourceBuilder { unsafe fn new(src_bits: u8) -> Self { Self { diff --git a/src/fault.rs b/src/fault.rs index 59493db..6cd2cef 100644 --- a/src/fault.rs +++ b/src/fault.rs @@ -50,6 +50,7 @@ pub unsafe trait FaultSource: Copy { const ENABLE_BITS: u8; } +#[cfg(feature = "stm32g4")] pub struct SourceBuilder { _input: I, src_bits: u8, @@ -61,6 +62,7 @@ pub struct SourceBuilder { filter_bits: u8, } +#[cfg(feature = "stm32g4")] impl SourceBuilder { unsafe fn new(input: I, src_bits: u8) -> Self { SourceBuilder { diff --git a/src/lib.rs b/src/lib.rs index 8ccd470..8f66a9a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -142,6 +142,7 @@ pub enum InterleavedMode { /// NOTE: Affects Cr1 Dual, + #[cfg(feature = "hrtim_v2")] /// Triple interleaved mode /// /// Automatically force @@ -154,6 +155,7 @@ pub enum InterleavedMode { /// using CMP2 (dual channel dac trigger and triggered-half modes). Triple, + #[cfg(feature = "hrtim_v2")] /// Quad interleaved mode /// /// Automatically force @@ -241,10 +243,12 @@ macro_rules! hrtim_finalize_body { }, }; - let (half, intlvd) = match $this.interleaved_mode { + let (half, _intlvd) = match $this.interleaved_mode { InterleavedMode::Disabled => (false, 0b00), InterleavedMode::Dual => (true, 0b00), + #[cfg(feature = "hrtim_v2")] InterleavedMode::Triple => (false, 0b01), + #[cfg(feature = "hrtim_v2")] InterleavedMode::Quad => (false, 0b10), }; @@ -267,8 +271,7 @@ macro_rules! hrtim_finalize_body { #[cfg(feature = "hrtim_v2")] tim.cr().modify(|_r, w| unsafe { // Interleaved mode - #[cfg(feature = "hrtim_v2")] - w.intlvd().bits(intlvd) + w.intlvd().bits(_intlvd) }); $( From e9921b71dcdfc802763c0d6631809aa04d8748a5 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 4 Dec 2024 23:14:04 +0100 Subject: [PATCH 12/25] Add and fix examples --- Cargo.toml | 51 ++++++++++ examples/stm32g4/adc-trigger.rs | 160 ++++++++++++++++++++++++++++++++ examples/stm32g4/capture-dma.rs | 136 +++++++++++++++++++++++++++ examples/stm32g4/capture.rs | 116 +++++++++++++++++++++++ examples/stm32g4/eev-comp.rs | 137 +++++++++++++++++++++++++++ examples/stm32g4/eev.rs | 105 +++++++++++++++++++++ examples/stm32g4/flt-comp.rs | 152 ++++++++++++++++++++++++++++++ examples/stm32g4/flt.rs | 120 ++++++++++++++++++++++++ examples/stm32g4/hrtim.rs | 101 ++++++++++++++++++++ examples/stm32g4/master.rs | 130 ++++++++++++++++++++++++++ 10 files changed, 1208 insertions(+) create mode 100644 examples/stm32g4/adc-trigger.rs create mode 100644 examples/stm32g4/capture-dma.rs create mode 100644 examples/stm32g4/capture.rs create mode 100644 examples/stm32g4/eev-comp.rs create mode 100644 examples/stm32g4/eev.rs create mode 100644 examples/stm32g4/flt-comp.rs create mode 100644 examples/stm32g4/flt.rs create mode 100644 examples/stm32g4/hrtim.rs create mode 100644 examples/stm32g4/master.rs diff --git a/Cargo.toml b/Cargo.toml index a92f84f..405b137 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,12 @@ stm32g4xx-hal = { git = "https://github.com/stm32-rs/stm32g4xx-hal", branch = "s defmt = { version = "0.3.10", optional = true } fugit = "0.3.7" +[dev-dependencies] +cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } +defmt-rtt = "0.4.0" +cortex-m-rt = "0.7.2" +panic-probe = { version = "0.3.0", features = ["print-defmt"] } + [features] default = [] @@ -45,3 +51,48 @@ stm32h753 = ["stm32h7", "stm32h7xx-hal/stm32h753", "hrtim_v1_1"] stm32g474 = ["stm32g4", "stm32g4xx-hal/stm32g474", "hrtim_v2"] stm32g484 = ["stm32g4", "stm32g4xx-hal/stm32g484", "hrtim_v2"] defmt = ["dep:defmt", "fugit/defmt"] + +[[example]] +name = "stm32g4-adc-trigger" +required-features = ["stm32g4"] +path = "examples/stm32g4/adc-trigger.rs" + +[[example]] +name = "stm32g4-capture" +required-features = ["stm32g4"] +path = "examples/stm32g4/capture.rs" + +[[example]] +name = "stm32g4-capture-dma" +required-features = ["stm32g4"] +path = "examples/stm32g4/capture-dma.rs" + +[[example]] +name = "stm32g4-eev-comp" +required-features = ["stm32g4"] +path = "examples/stm32g4/eev-comp.rs" + +[[example]] +name = "stm32g4-eev" +required-features = ["stm32g4"] +path = "examples/stm32g4/eev.rs" + +[[example]] +name = "stm32g4-flt-comp" +required-features = ["stm32g4"] +path = "examples/stm32g4/flt-comp.rs" + +[[example]] +name = "stm32g4-flt" +required-features = ["stm32g4"] +path = "examples/stm32g4/flt.rs" + +[[example]] +name = "stm32g4" +required-features = ["stm32g4"] +path = "examples/stm32g4/hrtim.rs" + +[[example]] +name = "stm32g4-master" +required-features = ["stm32g4"] +path = "examples/stm32g4/master.rs" \ No newline at end of file diff --git a/examples/stm32g4/adc-trigger.rs b/examples/stm32g4/adc-trigger.rs new file mode 100644 index 0000000..9d511b1 --- /dev/null +++ b/examples/stm32g4/adc-trigger.rs @@ -0,0 +1,160 @@ +#![no_std] +#![no_main] + +/// Example showcasing the use of the HRTIM peripheral to trigger the ADC at various points of the switch cycle off HRTIM_TIMA +use cortex_m_rt::entry; +use panic_probe as _; +use stm32_hrtim::{ + compare_register::HrCompareRegister, control::HrControltExt, output::HrOutput, timer::HrTimer, + HrParts, HrPwmAdvExt, Pscl4, +}; +use stm32g4xx_hal::{ + adc::{self, AdcClaim, ClockSource, Temperature, Vref}, + delay::SYSTDelayExt, + dma::{self, channel::DMAExt, config::DmaConfig, TransferExt}, + gpio::GpioExt, + pwr::PwrExt, + rcc::{self, RccExt}, + stm32::{CorePeripherals, Peripherals}, +}; + +#[entry] +fn main() -> ! { + const VREF: f32 = 3.3; + + defmt::info!("start"); + + let dp = Peripherals::take().unwrap(); + let cp = CorePeripherals::take().expect("cannot take core peripherals"); + + // Set system frequency to 16MHz * 15/1/2 = 120MHz + // This would lead to HrTim running at 120MHz * 32 = 3.84... + defmt::info!("rcc"); + let pwr = dp.PWR.constrain().freeze(); + let mut rcc = dp.RCC.freeze( + rcc::Config::pll().pll_cfg(rcc::PllConfig { + mux: rcc::PllSrc::HSI, + n: rcc::PllNMul::MUL_15, + m: rcc::PllMDiv::DIV_1, + r: Some(rcc::PllRDiv::DIV_2), + + ..Default::default() + }), + pwr, + ); + + let mut delay = cp.SYST.delay(&rcc.clocks); + + let dma::channel::Channels { ch1: dma1ch1, .. } = dp.DMA1.split(&rcc); + let config = DmaConfig::default() + .transfer_complete_interrupt(true) + .circular_buffer(true) + .memory_increment(true); + + defmt::info!("Setup Gpio"); + let gpioa = dp.GPIOA.split(&mut rcc); + let pa0 = gpioa.pa0.into_analog(); + + let pin_a = gpioa.pa8; + let pin_b = gpioa.pa9; + + // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 960MHz + // With max the max period set, this would be 960MHz/2^16 ~= 15kHz... + let prescaler = Pscl4; + + // . . + // . 50% . + // ------ ------ + //out1 | | | | + // | | | | + // -------- ---------- -------- + // . ^ ^ + // . | | + //AD samlp pa0 temp + let period = 0xFFFF; + let (hr_control, ..) = dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + let mut hr_control = hr_control.constrain(); + let HrParts { + mut timer, + mut cr1, + mut cr3, + mut cr4, + out: (mut out1, mut out2), + .. + } = dp + .HRTIM_TIMA + .pwm_advanced((pin_a, pin_b), &mut rcc) + .prescaler(prescaler) + .period(period) + .finalize(&mut hr_control); + + cr1.set_duty(period / 2); + cr3.set_duty(period / 3); + cr4.set_duty((2 * u32::from(period) / 3) as u16); + + hr_control.adc_trigger1.enable_source(&cr3); + hr_control.adc_trigger1.enable_source(&cr4); + + out1.enable_rst_event(&cr1); // Set low on compare match with cr1 + out2.enable_rst_event(&cr1); + + out1.enable_set_event(&timer); // Set high at new period + out2.enable_set_event(&timer); + + defmt::info!("Setup Adc1"); + let mut adc = dp + .ADC1 + .claim(ClockSource::SystemClock, &rcc, &mut delay, true); + + // TODO: Add the three lines below once the hal has been updated or this example will not work + //adc.set_external_trigger(( + // adc::config::TriggerMode::RisingEdge, + // &hr_control.adc_trigger1, + //)); + adc.enable_temperature(&dp.ADC12_COMMON); + adc.set_continuous(adc::config::Continuous::Discontinuous); + adc.reset_sequence(); + adc.configure_channel( + &pa0, + adc::config::Sequence::One, + adc::config::SampleTime::Cycles_640_5, + ); + adc.configure_channel( + &Temperature, + adc::config::Sequence::Two, + adc::config::SampleTime::Cycles_640_5, + ); + + defmt::info!("Setup DMA"); + let first_buffer = cortex_m::singleton!(: [u16; 10] = [0; 10]).unwrap(); + + let mut transfer = dma1ch1.into_circ_peripheral_to_memory_transfer( + adc.enable_dma(adc::config::Dma::Continuous), + &mut first_buffer[..], + config, + ); + + transfer.start(|adc| adc.start_conversion()); + + out1.enable(); + out2.enable(); + + timer.start(&mut hr_control.control); + + loop { + let mut b = [0_u16; 4]; + let r = transfer.read_exact(&mut b); + + defmt::info!("read: {}", r); + assert!(r == b.len()); + + let millivolts = Vref::sample_to_millivolts((b[0] + b[2]) / 2); + defmt::info!("pa3: {}mV", millivolts); + let temp = Temperature::temperature_to_degrees_centigrade( + (b[1] + b[3]) / 2, + VREF, + adc::config::Resolution::Twelve, + ); + defmt::info!("temp: {}℃C", temp); + } +} diff --git a/examples/stm32g4/capture-dma.rs b/examples/stm32g4/capture-dma.rs new file mode 100644 index 0000000..d8486ae --- /dev/null +++ b/examples/stm32g4/capture-dma.rs @@ -0,0 +1,136 @@ +#![no_std] +#![no_main] + +/// Example showcasing the use of the HRTIM peripheral's capture function to detect phase shift between a digital event and the output of HRTIM_TIMA +use cortex_m_rt::entry; +use panic_probe as _; +use stm32_hrtim::{ + capture, + compare_register::HrCompareRegister, + control::HrControltExt, + external_event::{self, ToExternalEventSource}, + output::HrOutput, + timer::{HrSlaveTimerCpt, HrTimer, TimerSplitCapture}, + HrParts, HrPwmAdvExt, Pscl128, +}; +use stm32g4xx_hal::{ + dma::{channel::DMAExt, config::DmaConfig, TransferExt}, + gpio::GpioExt, + pwr::PwrExt, + rcc::{self, RccExt}, + stm32::Peripherals, +}; + +#[entry] +fn main() -> ! { + defmt::info!("start"); + + let dp = Peripherals::take().unwrap(); + + // Set system frequency to 16MHz * 15/1/2 = 120MHz + // This would lead to HrTim running at 120MHz * 32 = 3.84... + defmt::info!("rcc"); + let pwr = dp.PWR.constrain().freeze(); + let mut rcc = dp.RCC.freeze( + rcc::Config::pll().pll_cfg(rcc::PllConfig { + mux: rcc::PllSrc::HSI, + n: rcc::PllNMul::MUL_15, + m: rcc::PllMDiv::DIV_1, + r: Some(rcc::PllRDiv::DIV_2), + + ..Default::default() + }), + pwr, + ); + + defmt::info!("Setup Gpio"); + let gpioa = dp.GPIOA.split(&mut rcc); + let gpiob = dp.GPIOB.split(&mut rcc); + + // PA8 (D7 on Nucleo G474RE) + let pin_a = gpioa.pa8; + + // PB5 (D4 on Nucleo G474RE) + let input = gpiob.pb5.into_pull_down_input(); + + // ...with a prescaler of 128 this gives us a HrTimer with a tick rate of 30MHz + // With max the max period set, this would be 30MHz/2^16 ~= 458Hz... + let prescaler = Pscl128; + + // t1 t2 . + // | | . + // v v . + // . . + // . 50% . + // ------ ------ + //out1 | | | | + // | | | | + // -------- ---------- -------- + let period = 0xFFFF; + let (mut hr_control, _flt_inputs, eev_inputs) = + dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + + let eev_input6 = eev_inputs + .eev_input6 + .bind(input) + .edge_or_polarity(external_event::EdgeOrPolarity::Edge( + external_event::Edge::Both, + )) + .finalize(&mut hr_control); + + let mut hr_control = hr_control.constrain(); + let HrParts { + timer, + mut cr1, + out: mut out1, + dma_channel, + .. + } = dp + .HRTIM_TIMA + .pwm_advanced(pin_a, &mut rcc) + .prescaler(prescaler) + .period(period) + .finalize(&mut hr_control); + out1.enable_rst_event(&cr1); // Set low on compare match with cr1 + out1.enable_set_event(&timer); // Set high at new period + cr1.set_duty(period / 2); + + let TimerSplitCapture { + mut timer, + ch1: mut capture, + .. + } = timer.split_capture(); + timer.start(&mut hr_control.control); + out1.enable(); + + capture.enable_interrupt(true, &mut hr_control); + capture.add_event(&eev_input6); + + defmt::info!("Setup DMA"); + let channels = dp.DMA1.split(&rcc); + let config = DmaConfig::default() + .transfer_complete_interrupt(false) + .circular_buffer(true) + .memory_increment(true); + + let first_buffer = cortex_m::singleton!(: [u32; 16] = [0; 16]).unwrap(); + let mut transfer = channels.ch1.into_circ_peripheral_to_memory_transfer( + capture.enable_dma(dma_channel), + &mut first_buffer[..], + config, + ); + + transfer.start(|_| ()); + + let mut old_duty = 0; + loop { + for duty in (u32::from(period) / 10)..(9 * u32::from(period) / 10) { + let mut data = [0; 2]; + transfer.read_exact(&mut data); + let [t1, t2] = data.map(|x| capture::dma_value_to_signed(x, period)); + cr1.set_duty(duty as u16); + defmt::info!("Capture: t1: {}, t2: {}, duty: {}, ", t1, t2, old_duty); + old_duty = duty; + } + } +} diff --git a/examples/stm32g4/capture.rs b/examples/stm32g4/capture.rs new file mode 100644 index 0000000..6efe8e9 --- /dev/null +++ b/examples/stm32g4/capture.rs @@ -0,0 +1,116 @@ +#![no_std] +#![no_main] + +/// Example showcasing the use of the HRTIM peripheral's capture function to detect phase shift between a digital event and the output of HRTIM_TIMA +use cortex_m_rt::entry; +use panic_probe as _; +use stm32_hrtim::{ + capture::HrCapture, + compare_register::HrCompareRegister, + control::HrControltExt, + external_event::{self, ToExternalEventSource}, + output::HrOutput, + timer::{HrSlaveTimerCpt, HrTimer}, + HrParts, HrPwmAdvExt, Pscl128, +}; +use stm32g4xx_hal::{ + gpio::GpioExt, + pwr::PwrExt, + rcc::{self, RccExt}, + stm32::Peripherals, +}; + +#[entry] +fn main() -> ! { + defmt::info!("start"); + + let dp = Peripherals::take().unwrap(); + + // Set system frequency to 16MHz * 15/1/2 = 120MHz + // This would lead to HrTim running at 120MHz * 32 = 3.84... + defmt::info!("rcc"); + let pwr = dp.PWR.constrain().freeze(); + let mut rcc = dp.RCC.freeze( + rcc::Config::pll().pll_cfg(rcc::PllConfig { + mux: rcc::PllSrc::HSI, + n: rcc::PllNMul::MUL_15, + m: rcc::PllMDiv::DIV_1, + r: Some(rcc::PllRDiv::DIV_2), + + ..Default::default() + }), + pwr, + ); + + defmt::info!("Setup Gpio"); + let gpioa = dp.GPIOA.split(&mut rcc); + let gpiob = dp.GPIOB.split(&mut rcc); + + // PA8 (D7 on Nucleo G474RE) + let pin_a = gpioa.pa8; + + // PB5 (D4 on Nucleo G474RE) + let input = gpiob.pb5.into_pull_down_input(); + + // ...with a prescaler of 128 this gives us a HrTimer with a tick rate of 30MHz + // With max the max period set, this would be 30MHz/2^16 ~= 458Hz... + let prescaler = Pscl128; + + // . . + // . 50% . + // ------ ------ + //out1 | | | | + // | | | | + // -------- ---------- -------- + let period = 0xFFFF; + let (mut hr_control, _flt_inputs, eev_inputs) = + dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + + let eev_input6 = eev_inputs + .eev_input6 + .bind(input) + .edge_or_polarity(external_event::EdgeOrPolarity::Edge( + external_event::Edge::Falling, + )) + .finalize(&mut hr_control); + + let mut hr_control = hr_control.constrain(); + let HrParts { + mut timer, + mut cr1, + mut out, + .. + } = dp + .HRTIM_TIMA + .pwm_advanced(pin_a, &mut rcc) + .prescaler(prescaler) + .period(period) + .finalize(&mut hr_control); + + out.enable_rst_event(&cr1); // Set low on compare match with cr1 + out.enable_set_event(&timer); // Set high at new period + + cr1.set_duty(period / 2); + timer.start(&mut hr_control.control); + out.enable(); + + let capture = timer.capture_ch1(); + capture.enable_interrupt(true, &mut hr_control); + capture.add_event(&eev_input6); + + let mut old_duty = 0; + loop { + for duty in (u32::from(period) / 10)..(9 * u32::from(period) / 10) { + if let Some(value) = capture.get_signed(period) { + defmt::info!( + "Capture: {:?}, duty: {}, diff: {}", + value, + old_duty, + value - old_duty as i32 + ); + cr1.set_duty(duty as u16); + old_duty = duty; + } + } + } +} diff --git a/examples/stm32g4/eev-comp.rs b/examples/stm32g4/eev-comp.rs new file mode 100644 index 0000000..7d3544a --- /dev/null +++ b/examples/stm32g4/eev-comp.rs @@ -0,0 +1,137 @@ +#![no_std] +#![no_main] + +/// Example showcasing the use of the HRTIM peripheral together with a comparator to implement a cycle by cycle current limit. +/// Once the comparator input exceeds the reference set by the DAC, the output is set low thus limiting the pulse width and in turn the current. +use cortex_m_rt::entry; +use panic_probe as _; +use stm32_hrtim::{ + compare_register::HrCompareRegister, + control::HrControltExt, + external_event::{self, ToExternalEventSource}, + output::HrOutput, + timer::HrTimer, + timer_eev_cfg::{EevCfg, EevCfgs}, + HrParts, HrPwmAdvExt, Pscl4, +}; +use stm32g4xx_hal::{ + comparator::{self, ComparatorExt, ComparatorSplit}, + dac::{self, DacExt, DacOut}, + delay::SYSTDelayExt, + gpio::{GpioExt, SignalEdge}, + pwm, + pwr::PwrExt, + rcc::{self, RccExt}, + stm32::{CorePeripherals, Peripherals}, +}; + +#[entry] +fn main() -> ! { + let dp = Peripherals::take().expect("cannot take peripherals"); + let cp = CorePeripherals::take().expect("cannot take core"); + // Set system frequency to 16MHz * 75/4/2 = 150MHz + // This would lead to HrTim running at 150MHz * 32 = 4.8GHz... + let pwr = dp.PWR.constrain().freeze(); + + let mut rcc = dp.RCC.freeze( + rcc::Config::pll().pll_cfg(rcc::PllConfig { + mux: rcc::PllSrc::HSI, + n: rcc::PllNMul::MUL_75, + m: rcc::PllMDiv::DIV_4, + r: Some(rcc::PllRDiv::DIV_2), + ..Default::default() + }), + pwr, + ); + + let exti = dp.EXTI; + + let mut delay = cp.SYST.delay(&rcc.clocks); + + let gpioa = dp.GPIOA.split(&mut rcc); + + let input = gpioa.pa1.into_analog(); + let pin_a = gpioa.pa8; + + let dac1ch1 = dp.DAC1.constrain(dac::Dac1IntSig1, &mut rcc); + let mut dac = dac1ch1.calibrate_buffer(&mut delay).enable(); + + // Use dac to define the fault threshold + // 2^12 / 2 = 2^11 for about half of VCC + let limit = 1 << 11; + dac.set_value(limit); + + let (comp1, ..) = dp.COMP.split(&mut rcc); + + let comp1 = comp1.comparator( + &input, + &dac, + comparator::Config::default().hysteresis(comparator::Hysteresis::None), + //.output_inverted(), + &rcc.clocks, + ); + comp1.listen(SignalEdge::Rising, &exti); + let comp1 = comp1.enable().lock(); + + let (mut hr_control, _flt_inputs, eev_inputs) = + dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + + let eev_input4 = eev_inputs + .eev_input4 + .bind(&comp1) + .edge_or_polarity(external_event::EdgeOrPolarity::Polarity( + pwm::Polarity::ActiveHigh, + )) + .finalize(&mut hr_control); + + let mut hr_control = hr_control.constrain(); + + // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 1.2GHz + // With max the max period set, this would be 1.2GHz/2^16 ~= 18kHz... + let prescaler = Pscl4; + + // . . * . + // . 33% . * . . . + // .-----. .--* . .-----. .----- + //out1 | | | | . | | | + // | | | * . | | | + // ------ ----------- ------------------------------ ----------- + // . . * . . . + // . . * . . . + // . . *-------------* . . + //eev . . | .| . . + // . . | .| . . + // ------------------------- .-------------------------------------- + // . . * . . . + // . . * . . . + let HrParts { + mut timer, + mut cr1, + mut out, + .. + } = dp + .HRTIM_TIMA + .pwm_advanced(pin_a, &mut rcc) + .prescaler(prescaler) + .eev_cfg(EevCfgs::default().eev4(EevCfg::default())) + .period(0xFFFF) + .finalize(&mut hr_control); + + out.enable_rst_event(&cr1); // Set low on compare match with cr1 + out.enable_rst_event(&eev_input4); + out.enable_set_event(&timer); // Set high at new period + cr1.set_duty(timer.get_period() / 3); + + out.enable(); + timer.start(&mut hr_control.control); + + defmt::info!("Started"); + + loop { + defmt::info!( + "Comp: {}, pending: {}", + comp1.output(), + comp1.is_pending(&exti) + ); + } +} diff --git a/examples/stm32g4/eev.rs b/examples/stm32g4/eev.rs new file mode 100644 index 0000000..8911daf --- /dev/null +++ b/examples/stm32g4/eev.rs @@ -0,0 +1,105 @@ +#![no_std] +#![no_main] + +/// Example showcasing the use of the HRTIM peripheral together with a digital input to implement a cycle by cycle current limit. +/// Once the digital input goes high, the output is set low thus limiting the pulse width and in turn the current. +use cortex_m_rt::entry; +use panic_probe as _; +use stm32_hrtim::{ + compare_register::HrCompareRegister, + control::HrControltExt, + external_event::{self, ToExternalEventSource}, + output::HrOutput, + timer::HrTimer, + timer_eev_cfg::EevCfgs, + HrParts, HrPwmAdvExt, Pscl4, +}; +use stm32g4xx_hal::{ + gpio::GpioExt, + pwm, + pwr::PwrExt, + rcc::{self, RccExt}, + stm32::Peripherals, +}; + +#[entry] +fn main() -> ! { + let dp = Peripherals::take().expect("cannot take peripherals"); + // Set system frequency to 16MHz * 75/4/2 = 150MHz + // This would lead to HrTim running at 150MHz * 32 = 4.8GHz... + let pwr = dp.PWR.constrain().freeze(); + + let mut rcc = dp.RCC.freeze( + rcc::Config::pll().pll_cfg(rcc::PllConfig { + mux: rcc::PllSrc::HSI, + n: rcc::PllNMul::MUL_75, + m: rcc::PllMDiv::DIV_4, + r: Some(rcc::PllRDiv::DIV_2), + ..Default::default() + }), + pwr, + ); + + let gpioa = dp.GPIOA.split(&mut rcc); + let gpiob = dp.GPIOB.split(&mut rcc); + + let (mut hr_control, _flt_inputs, eev_inputs) = + dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + + let eev_input3 = eev_inputs + .eev_input3 + .bind(gpiob.pb7.into_pull_down_input()) + .edge_or_polarity(external_event::EdgeOrPolarity::Polarity( + pwm::Polarity::ActiveHigh, + )) + .finalize(&mut hr_control); + + let mut hr_control = hr_control.constrain(); + + // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 1.2GHz + // With max the max period set, this would be 1.2GHz/2^16 ~= 18kHz... + let prescaler = Pscl4; + + let pin_a = gpioa.pa8; + + // . . * . + // . 33% . * . . . + // .-----. .--* .-----. .-----. .----- + //out1 | | | | | | | | | + // | | | * | | | | | + // ------ ----------- -------------- ----------- ----------- + // . . * . . . + // . . * . . . + // . . *--------* . . . + //eev . . | | . . . + // . . | | . . . + // ------------------------- ------------------------------------------ + // . . * . . . + // . . * . . . + let HrParts { + mut timer, + mut cr1, + mut out, + .. + } = dp + .HRTIM_TIMA + .pwm_advanced(pin_a, &mut rcc) + .prescaler(prescaler) + .eev_cfg(EevCfgs::default()) + .period(0xFFFF) + .finalize(&mut hr_control); + + out.enable_rst_event(&cr1); // Set low on compare match with cr1 + out.enable_rst_event(&eev_input3); + out.enable_set_event(&timer); // Set high at new period + cr1.set_duty(timer.get_period() / 3); + + out.enable(); + timer.start(&mut hr_control.control); + + defmt::info!("Started"); + + loop { + cortex_m::asm::nop() + } +} diff --git a/examples/stm32g4/flt-comp.rs b/examples/stm32g4/flt-comp.rs new file mode 100644 index 0000000..587620c --- /dev/null +++ b/examples/stm32g4/flt-comp.rs @@ -0,0 +1,152 @@ +#![no_std] +#![no_main] + +/// Example showcasing the use of the HRTIM peripheral together with a comparator to implement a current fault. +/// Once the comparator input exceeds the reference set by the DAC, the output is forced low and put into a fault state. +use cortex_m_rt::entry; +use panic_probe as _; +use stm32_hrtim::{ + compare_register::HrCompareRegister, + control::HrControltExt, + fault::{FaultAction, FaultMonitor}, + output::HrOutput, + timer::HrTimer, + HrParts, HrPwmAdvExt, Pscl4, +}; +use stm32g4xx_hal::{ + self as hal, + adc::AdcClaim, + comparator::{self, ComparatorExt, ComparatorSplit}, + dac::{Dac3IntSig1, DacExt, DacOut}, + delay::SYSTDelayExt, + gpio::GpioExt, + pwr::PwrExt, + rcc::{self, RccExt}, + stm32::{CorePeripherals, Peripherals}, +}; + +#[entry] +fn main() -> ! { + let dp = Peripherals::take().expect("cannot take peripherals"); + let cp = CorePeripherals::take().expect("cannot take core"); + // Set system frequency to 16MHz * 15/1/2 = 120MHz + // This would lead to HrTim running at 120MHz * 32 = 3.84GHz... + let pwr = dp.PWR.constrain().freeze(); + let mut rcc = dp.RCC.freeze( + rcc::Config::pll().pll_cfg(rcc::PllConfig { + mux: rcc::PllSrc::HSI, + n: rcc::PllNMul::MUL_15, + m: rcc::PllMDiv::DIV_1, + r: Some(rcc::PllRDiv::DIV_2), + ..Default::default() + }), + pwr, + ); + + let mut delay = cp.SYST.delay(&rcc.clocks); + + let mut adc1 = dp.ADC1.claim_and_configure( + hal::adc::ClockSource::SystemClock, + &rcc, + hal::adc::config::AdcConfig::default() + .clock_mode(hal::adc::config::ClockMode::Synchronous_Div_4), + &mut delay, + false, + ); + + let gpioa = dp.GPIOA.split(&mut rcc); + let gpioc = dp.GPIOC.split(&mut rcc); + + let dac3ch1 = dp.DAC3.constrain(Dac3IntSig1, &mut rcc); + let mut dac = dac3ch1.enable(); + + // Use dac to define the fault threshold + // 2^12 / 2 = 2^11 for about half of VCC + let fault_limit = 60; + dac.set_value(fault_limit); + + let (_comp1, _comp2, comp3, ..) = dp.COMP.split(&mut rcc); + + let pc1 = gpioc.pc1.into_analog(); + let comp3 = comp3 + .comparator( + &pc1, + &dac, + comparator::Config::default() + .hysteresis(comparator::Hysteresis::None) + .output_inverted(), + &rcc.clocks, + ) + .enable(); + + let (hr_control, flt_inputs, _) = dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + let mut hr_control = hr_control.constrain(); + + let fault_source5 = flt_inputs + .fault_input5 + .bind_comp(&comp3) + .polarity(hal::pwm::Polarity::ActiveHigh) + .finalize(&mut hr_control); + + // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 1.2GHz + // With max the max period set, this would be 1.2GHz/2^16 ~= 18kHz... + let prescaler = Pscl4; + + let pin_a = gpioa.pa8; + + // . . . * + // . 33% . . * . . + // .-----. .-----. .--. . . + //out1 | | | | | | . . + // | | | | | | . . + // ------ ----------- ----------- ----------------------------------- + // . . . * . . + // . . . * . . + // . . . *-------- . . + //fault . . . | | . . + // . . . | | . . + // ----------------------------------------- -------------------------- + // . . . * . . + // . . . * . . + let HrParts { + mut timer, + mut cr1, + out: mut out1, + .. + } = dp + .HRTIM_TIMA + .pwm_advanced(pin_a, &mut rcc) + .prescaler(prescaler) + .period(0xFFFF) + .with_fault_source(fault_source5) // Set fault source + .fault_action1(FaultAction::ForceInactive) + .fault_action2(FaultAction::ForceInactive) + .finalize(&mut hr_control); + + out1.enable_rst_event(&cr1); // Set low on compare match with cr1 + out1.enable_set_event(&timer); // Set high at new period + cr1.set_duty(timer.get_period() / 3); + //unsafe {((HRTIM_COMMON::ptr() as *mut u8).offset(0x14) as *mut u32).write_volatile(1); } + out1.enable(); + timer.start(&mut hr_control.control); + + defmt::info!("Started"); + + loop { + for _ in 0..5 { + //delay.delay(500_u32.millis()); + defmt::info!( + "State: {:?}, comp: {}, is_fault_active: {}, pc1: {}", + out1.get_state(), + comp3.output(), + hr_control.fault_5.is_fault_active(), + adc1.convert(&pc1, hal::adc::config::SampleTime::Cycles_92_5) + ); + } + if hr_control.fault_5.is_fault_active() { + hr_control.fault_5.clear_fault(); // Clear fault every 5s + out1.enable(); + defmt::info!("failt cleared, and output reenabled"); + } + } +} diff --git a/examples/stm32g4/flt.rs b/examples/stm32g4/flt.rs new file mode 100644 index 0000000..53d966e --- /dev/null +++ b/examples/stm32g4/flt.rs @@ -0,0 +1,120 @@ +#![no_std] +#![no_main] + +/// Example showcasing the use of the HRTIM peripheral together with a comparator to implement a current fault. +/// Once the digital input goes high, the output is forced low and put into a fault state. +use cortex_m_rt::entry; +use panic_probe as _; +use stm32_hrtim::{ + compare_register::HrCompareRegister, + control::HrControltExt, + fault::{FaultAction, FaultMonitor}, + output::HrOutput, + timer::HrTimer, + HrParts, HrPwmAdvExt, Pscl4, +}; +use stm32g4xx_hal::{ + self as hal, + delay::{DelayExt, SYSTDelayExt}, + gpio::GpioExt, + pwr::PwrExt, + rcc::{self, RccExt}, + stm32::{CorePeripherals, Peripherals}, + time::ExtU32, +}; + +#[entry] +fn main() -> ! { + let dp = Peripherals::take().expect("cannot take peripherals"); + let cp = CorePeripherals::take().expect("cannot take core"); + // Set system frequency to 16MHz * 75/4/2 = 150MHz + // This would lead to HrTim running at 150MHz * 32 = 4.8GHz... + let pwr = dp.PWR.constrain().freeze(); + let mut rcc = dp.RCC.freeze( + rcc::Config::pll().pll_cfg(rcc::PllConfig { + mux: rcc::PllSrc::HSI, + n: rcc::PllNMul::MUL_75, + m: rcc::PllMDiv::DIV_4, + r: Some(rcc::PllRDiv::DIV_2), + ..Default::default() + }), + pwr, + ); + + let mut delay = cp.SYST.delay(&rcc.clocks); + + let gpioa = dp.GPIOA.split(&mut rcc); + let gpiob = dp.GPIOB.split(&mut rcc); + let (hr_control, flt_inputs, _) = dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + let mut hr_control = hr_control.constrain(); + + let fault_source3 = flt_inputs + .fault_input3 + .bind_pin(gpiob.pb10.into_pull_down_input()) + .polarity(hal::pwm::Polarity::ActiveHigh) + .finalize(&mut hr_control); + + // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 1.2GHz + // With max the max period set, this would be 1.2GHz/2^16 ~= 18kHz... + let prescaler = Pscl4; + + let pin_a = gpioa.pa8; + + // . . . * + // . 33% . . * . . + // .-----. .-----. .--. . . + //out1 | | | | | | . . + // | | | | | | . . + // ------ ----------- ----------- ----------------------------------- + // . . . * . . + // . . . * . . + // . . . *-------- . . + //fault . . . | | . . + // . . . | | . . + // ----------------------------------------- -------------------------- + // . . . * . . + // . . . * . . + let HrParts { + mut timer, + mut cr1, + mut out, + .. + } = dp + .HRTIM_TIMA + .pwm_advanced(pin_a, &mut rcc) + .prescaler(prescaler) + .period(0xFFFF) + //.with_fault_source(fault_source1) + //.with_fault_source(fault_source2) + .with_fault_source(fault_source3) // Set fault source + //.with_fault_source(fault_source4) + //.with_fault_source(fault_source5) + //.with_fault_source(fault_source6) + .fault_action1(FaultAction::ForceInactive) + .fault_action2(FaultAction::ForceInactive) + // alternated every period with one being + // inactive and the other getting to output its wave form + // as normal + .finalize(&mut hr_control); + + out.enable_rst_event(&cr1); // Set low on compare match with cr1 + out.enable_set_event(&timer); // Set high at new period + cr1.set_duty(timer.get_period() / 3); + //unsafe {((HRTIM_COMMON::ptr() as *mut u8).offset(0x14) as *mut u32).write_volatile(1); } + out.enable(); + timer.start(&mut hr_control.control); + + defmt::info!("Started"); + + loop { + for _ in 0..5 { + delay.delay(500_u32.millis()); + defmt::info!("State: {:?}", out.get_state()); + } + if hr_control.fault_3.is_fault_active() { + hr_control.fault_3.clear_fault(); // Clear fault every 5s + out.enable(); + defmt::info!("failt cleared, and output reenabled"); + } + } +} diff --git a/examples/stm32g4/hrtim.rs b/examples/stm32g4/hrtim.rs new file mode 100644 index 0000000..f2c3891 --- /dev/null +++ b/examples/stm32g4/hrtim.rs @@ -0,0 +1,101 @@ +#![no_std] +#![no_main] + +use cortex_m_rt::entry; +use panic_probe as _; +use stm32_hrtim::{ + compare_register::HrCompareRegister, control::HrControltExt, output::HrOutput, timer::HrTimer, + HrParts, HrPwmAdvExt, Pscl4, +}; +use stm32g4xx_hal::{ + delay::{DelayExt, SYSTDelayExt}, + gpio::GpioExt, + pwr::PwrExt, + rcc::{self, RccExt}, + stm32::{CorePeripherals, Peripherals}, + time::ExtU32, +}; + +#[entry] +fn main() -> ! { + defmt::info!("Initializing..."); + + let dp = Peripherals::take().expect("cannot take peripherals"); + let cp = CorePeripherals::take().expect("cannot take core"); + // Set system frequency to 16MHz * 15/1/2 = 120MHz + // This would lead to HrTim running at 120MHz * 32 = 3.84... + let pwr = dp.PWR.constrain().freeze(); + let mut rcc = dp.RCC.freeze( + rcc::Config::pll().pll_cfg(rcc::PllConfig { + mux: rcc::PllSrc::HSI, + n: rcc::PllNMul::MUL_15, + m: rcc::PllMDiv::DIV_1, + r: Some(rcc::PllRDiv::DIV_2), + + ..Default::default() + }), + pwr, + ); + + let mut delay = cp.SYST.delay(&rcc.clocks); + + // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 960MHz + // With max the max period set, this would be 960MHz/2^16 ~= 15kHz... + let prescaler = Pscl4; + + let gpioa = dp.GPIOA.split(&mut rcc); + let pin_a = gpioa.pa8; + let pin_b = gpioa.pa9; + + // . . . . + // . 30% . . . + // ---- . .---- . + //out1 | | . | | . + // | | . | | . + // -------- ---------------------------- -------------------- + // . .---- . .---- + //out2 . | | . | | + // . | | . | | + // ------------------------ ---------------------------- ---- + // . . . . + // . . . . + let (hr_control, ..) = dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + let mut hr_control = hr_control.constrain(); + + let HrParts { + mut timer, + mut cr1, + out: (mut out1, mut out2), + .. + } = dp + .HRTIM_TIMA + .pwm_advanced((pin_a, pin_b), &mut rcc) + .prescaler(prescaler) + .period(0xFFFF) + .push_pull_mode(true) // Set push pull mode, out1 and out2 are + // alternated every period with one being + // inactive and the other getting to output its wave form + // as normal + .finalize(&mut hr_control); + + out1.enable_rst_event(&cr1); // Set low on compare match with cr1 + out2.enable_rst_event(&cr1); + + out1.enable_set_event(&timer); // Set high at new period + out2.enable_set_event(&timer); + + out1.enable(); + out2.enable(); + + loop { + // Step frequency from 18kHz to about 180kHz(half of that when only looking at one pin) + for i in 1..10 { + let new_period = u16::MAX / i; + + cr1.set_duty(new_period / 3); + timer.set_period(new_period); + + delay.delay(500_u32.millis()); + } + } +} diff --git a/examples/stm32g4/master.rs b/examples/stm32g4/master.rs new file mode 100644 index 0000000..1028cde --- /dev/null +++ b/examples/stm32g4/master.rs @@ -0,0 +1,130 @@ +#![no_std] +#![no_main] + +use cortex_m_rt::entry; +use panic_probe as _; +use stm32_hrtim::{ + compare_register::HrCompareRegister, + control::HrControltExt, + output::HrOutput, + timer::{HrSlaveTimer, HrTimer}, + HrParts, HrPwmAdvExt, HrTimerMode, MasterPreloadSource, PreloadSource, Pscl4, +}; +use stm32g4xx_hal::{ + delay::{DelayExt, SYSTDelayExt}, + gpio::GpioExt, + pwr::PwrExt, + rcc::{self, RccExt}, + stm32::{CorePeripherals, Peripherals}, + time::ExtU32, +}; + +#[entry] +fn main() -> ! { + let dp = Peripherals::take().expect("cannot take peripherals"); + let cp = CorePeripherals::take().expect("cannot take core"); + // Set system frequency to 16MHz * 15/1/2 = 120MHz + // This would lead to HrTim running at 120MHz * 32 = 3.84... + let pwr = dp.PWR.constrain().freeze(); + let mut rcc = dp.RCC.freeze( + rcc::Config::pll().pll_cfg(rcc::PllConfig { + mux: rcc::PllSrc::HSI, + n: rcc::PllNMul::MUL_15, + m: rcc::PllMDiv::DIV_1, + r: Some(rcc::PllRDiv::DIV_2), + + ..Default::default() + }), + pwr, + ); + + let mut delay = cp.SYST.delay(&rcc.clocks); + + // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 960MHz + // With max the max period set, this would be 960MHz/2^16 ~= 15kHz... + let prescaler = Pscl4; + + let gpioa = dp.GPIOA.split(&mut rcc); + let pin_a = gpioa.pa8; + let pin_b = gpioa.pa9; + + // . . . . + // . 30% . . . + // ---- . .---- . + //out1 | | . | | . + // | | . | | . + // -------- ---------------------------- -------------------- + // . .---- . .---- + //out2 . | | . | | + // . | | . | | + // ------------------------ ---------------------------- ---- + // . . . . + // . . . . + let (hr_control, ..) = dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + let mut hr_control = hr_control.constrain(); + + let HrParts { + mut timer, + mut cr1, + out: (mut out1, mut out2), + .. + } = dp + .HRTIM_TIMA + .pwm_advanced((pin_a, pin_b), &mut rcc) + .prescaler(prescaler) + .push_pull_mode(true) // Set push pull mode, out1 and out2 are + // alternated every period with one being + // inactive and the other getting to output its wave form + // as normal + .preload(PreloadSource::OnMasterTimerUpdate) + .timer_mode(HrTimerMode::SingleShotRetriggerable) + .finalize(&mut hr_control); + + let HrParts { + timer: mut mtimer, + cr1: mut mcr1, + .. + } = dp + .HRTIM_MASTER + .pwm_advanced((), &mut rcc) + .prescaler(prescaler) + .preload(MasterPreloadSource::OnMasterRepetitionUpdate) + .period(0xFFFF) + .finalize(&mut hr_control); + + // Run in sync with master timer + timer.enable_reset_event(&mtimer); + + out1.enable_rst_event(&mcr1); // Set low on compare match with cr1 + out2.enable_rst_event(&mcr1); + + out1.enable_set_event(&mtimer); // Set high at new period + out2.enable_set_event(&mtimer); + + out1.enable(); + out2.enable(); + + defmt::info!("Running"); + + loop { + // Step frequency from 18kHz to about 180kHz(half of that when only looking at one pin) + for i in 1..10 { + let new_period = u16::MAX / i; + + mcr1.set_duty(new_period / 3); + cr1.set_duty(new_period / 3 - 1000); + mtimer.set_period(new_period); + timer.set_period(new_period - 1000); + + defmt::info!( + "period: {}, duty: {}, get_duty: {}, get_period: {}", + new_period, + new_period / 3, + mcr1.get_duty(), + mtimer.get_period() + ); + + delay.delay(500_u32.millis()); + } + } +} From 3411886789adf65cb0cc4926fd26453ff19b9700 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 4 Dec 2024 23:15:28 +0100 Subject: [PATCH 13/25] Fix some warnings --- src/capture.rs | 4 ++-- src/control.rs | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/capture.rs b/src/capture.rs index 96bef80..7936295 100644 --- a/src/capture.rs +++ b/src/capture.rs @@ -86,7 +86,7 @@ pub trait HrCapture { /// /// where captures during down counting count as negative (before the upcount) /// - /// ```txt + /// ```text /// Counter /// ---------------------------------- <--- period /// \ ^ / @@ -117,7 +117,7 @@ pub trait HrCapture { /// /// where captures during down counting count as negative (before the upcount) /// - /// ``` + /// ```text /// Counter /// ---------------------------------- <--- period /// \ ^ / diff --git a/src/control.rs b/src/control.rs index 03bfc33..f5915a0 100644 --- a/src/control.rs +++ b/src/control.rs @@ -19,18 +19,19 @@ impl HrControltExt for HRTIM_COMMON { let common = unsafe { &*HRTIM_COMMON::ptr() }; let rcc_ptr = { - #[cfg(feature = "stm32g4")] unsafe { + #[cfg(feature = "stm32g4")] + unsafe { &*stm32::RCC::ptr() } - #[cfg(feature = "stm32f3")] { + #[cfg(feature = "stm32f3")] + { &mut rcc.apb2 } }; ::enable(rcc_ptr); ::reset(rcc_ptr); - // Start calibration procedure common From a8dd2e25a0b8637a7dac9013a4e49869181ef062 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 4 Dec 2024 23:24:39 +0100 Subject: [PATCH 14/25] Fix adc-trigger example --- examples/stm32g4/adc-trigger.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/stm32g4/adc-trigger.rs b/examples/stm32g4/adc-trigger.rs index 9d511b1..9ec143f 100644 --- a/examples/stm32g4/adc-trigger.rs +++ b/examples/stm32g4/adc-trigger.rs @@ -106,11 +106,10 @@ fn main() -> ! { .ADC1 .claim(ClockSource::SystemClock, &rcc, &mut delay, true); - // TODO: Add the three lines below once the hal has been updated or this example will not work - //adc.set_external_trigger(( - // adc::config::TriggerMode::RisingEdge, - // &hr_control.adc_trigger1, - //)); + adc.set_external_trigger(( + adc::config::TriggerMode::RisingEdge, + (&hr_control.adc_trigger1).into(), + )); adc.enable_temperature(&dp.ADC12_COMMON); adc.set_continuous(adc::config::Continuous::Discontinuous); adc.reset_sequence(); From b0dd45f204e508c80aabd96d6115c48460810e01 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Fri, 6 Dec 2024 14:26:45 +0100 Subject: [PATCH 15/25] Update for h7 (broken) --- Cargo.toml | 5 ++++- src/control.rs | 36 ++++++++++++++++++++++++++++++------ src/external_event.rs | 4 ++++ src/lib.rs | 7 ++++--- src/stm32h7.rs | 9 +++++++++ 5 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 src/stm32h7.rs diff --git a/Cargo.toml b/Cargo.toml index 405b137..c2eb3a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,10 @@ stm32f3 = { git = "https://github.com/stm32-rs/stm32-rs-nightlies", optional = t #stm32f3xx-hal = { version = "0.10.0", optional = true } stm32f3xx-hal = { git = "https://github.com/usbalbin/stm32f3xx-hal", branch = "update_for_new_pac", optional = true } -stm32h7xx-hal = { version = "0.16.0", optional = true } +#stm32h7xx-hal = { version = "0.16.0", optional = true } +stm32h7xx-hal = { git = "https://github.com/usbalbin/stm32h7xx-hal", branch = "update_for_new_pac", optional = true } +#stm32h7xx-hal = { path = "../stm32h7xx-hal", optional = true } + #stm32g4xx-hal = { version = "0.0.1", optional = true } stm32g4xx-hal = { git = "https://github.com/stm32-rs/stm32g4xx-hal", branch = "staged-pac", optional = true } #stm32g4xx-hal = { path = "../stm32g4xx-hal", optional = true } diff --git a/src/control.rs b/src/control.rs index f5915a0..4be8c52 100644 --- a/src/control.rs +++ b/src/control.rs @@ -5,20 +5,29 @@ use crate::fault::{ }; use crate::{hal, stm32}; -use hal::rcc::{Enable, Rcc, Reset}; + +#[cfg(feature = "stm32h7")] +use hal::rcc::{rec::Hrtim as Rcc, ResetEnable as Reset, ResetEnable as Enable}; + +#[cfg(not(feature = "stm32h7"))] +use hal::rcc::{Enable, Reset}; + +#[cfg(not(feature = "stm32h7"))] +type Rcc = &mut hal::rcc::Rcc; + use stm32::HRTIM_COMMON; use super::{external_event::EevInputs, fault::FaultInputs}; pub trait HrControltExt { - fn hr_control(self, _rcc: &mut Rcc) -> HrTimOngoingCalibration; + fn hr_control(self, _rcc: Rcc) -> HrTimOngoingCalibration; } impl HrControltExt for HRTIM_COMMON { - fn hr_control(self, #[allow(unused_variables)] rcc: &mut Rcc) -> HrTimOngoingCalibration { + fn hr_control(self, #[allow(unused_variables)] rcc: Rcc) -> HrTimOngoingCalibration { let common = unsafe { &*HRTIM_COMMON::ptr() }; - let rcc_ptr = { + let rcc = { #[cfg(feature = "stm32g4")] unsafe { &*stm32::RCC::ptr() @@ -28,10 +37,20 @@ impl HrControltExt for HRTIM_COMMON { { &mut rcc.apb2 } + + #[cfg(feature = "stm32h7")] + { + rcc + } }; - ::enable(rcc_ptr); - ::reset(rcc_ptr); + #[cfg(not(feature = "stm32h7"))] + ::enable(rcc); + #[cfg(not(feature = "stm32h7"))] + ::reset(rcc); + + #[cfg(feature = "stm32h7")] + rcc.enable().reset(); // Start calibration procedure common @@ -136,6 +155,11 @@ impl HrTimOngoingCalibration { common .fltinr2() .write(|w| w.fltsd().bits(flt_divider as u8)); + + #[cfg(feature = "stm32h7")] + let please_dont_forget_to_remove_this_once_pac_is_fixed = (); + + #[cfg(not(feature = "stm32h7"))] common.eecr3().write(|w| w.eevsd().bits(eev_divider as u8)); #[cfg(feature = "stm32g4")] diff --git a/src/external_event.rs b/src/external_event.rs index ceea360..4ac46d9 100644 --- a/src/external_event.rs +++ b/src/external_event.rs @@ -328,8 +328,12 @@ macro_rules! impl_eev6_10_to_es { let common = unsafe { &*HRTIM_COMMON::ptr() }; + #[cfg(feature = "stm32h7")] + let please_dont_forget_to_remove_this_once_pac_is_fixed = (); + // SAFETY: Thanks to, `HrTimCalibrated`, we know we have exclusive access to the register, // we also know no timers are started. + #[cfg(not(feature = "stm32h7"))] unsafe { common.eecr2().modify(|_r, w| { w.$eeXsrc() diff --git a/src/lib.rs b/src/lib.rs index 8f66a9a..3da8a35 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,7 +17,8 @@ pub mod timer_eev_cfg; mod mcu; #[cfg(feature = "stm32h7")] -pub use stm32h7xx_hal as hal; +#[path = "stm32h7.rs"] +mod mcu; #[cfg(feature = "stm32g4")] #[path = "stm32g4.rs"] @@ -604,7 +605,7 @@ macro_rules! hrtim_hal { ) } - #[cfg(feature = "stm32g4")] { + #[cfg(not(feature = "stm32f3"))] { hrtim_finalize_body!(self, PreloadSource, $TIMX, [$($out)*],) } } @@ -764,7 +765,7 @@ where ) } - #[cfg(feature = "stm32g4")] + #[cfg(not(feature = "stm32f3"))] { hrtim_finalize_body!(self, MasterPreloadSource, HRTIM_MASTER, [],) } diff --git a/src/stm32h7.rs b/src/stm32h7.rs new file mode 100644 index 0000000..f74baba --- /dev/null +++ b/src/stm32h7.rs @@ -0,0 +1,9 @@ +pub use hal::stm32; +pub use stm32h7xx_hal as hal; + +pub type GpioInputMode = hal::gpio::Input; + +pub use hal::pwm::Alignment; + +#[cfg(feature = "stm32h7")] +pub use hal::pwm::Polarity; From 1eb2b31ebec07b8e26ab7c7bce672399d6efedf7 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Thu, 12 Dec 2024 21:18:12 +0100 Subject: [PATCH 16/25] Add non working examples --- examples/stm32f3/hrtim.rs | 91 +++++++++++++++++++++++++++++++++ examples/stm32h7/hrtim.rs | 103 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 examples/stm32f3/hrtim.rs create mode 100644 examples/stm32h7/hrtim.rs diff --git a/examples/stm32f3/hrtim.rs b/examples/stm32f3/hrtim.rs new file mode 100644 index 0000000..cec37dc --- /dev/null +++ b/examples/stm32f3/hrtim.rs @@ -0,0 +1,91 @@ +#![no_std] +#![no_main] + +use cortex_m_rt::entry; +use panic_probe as _; +use stm32_hrtim::{ + compare_register::HrCompareRegister, control::HrControltExt, output::HrOutput, timer::HrTimer, + HrParts, HrPwmAdvExt, Pscl4, +}; +use stm32g4xx_hal::{ + delay::{DelayExt, SYSTDelayExt}, + gpio::GpioExt, + pwr::PwrExt, + rcc::{self, RccExt}, + stm32::{CorePeripherals, Peripherals}, + time::ExtU32, +}; + +#[entry] +fn main() -> ! { + defmt::info!("Initializing..."); + + let dp = Peripherals::take().expect("cannot take peripherals"); + let cp = CorePeripherals::take().expect("cannot take core"); + // Set system frequency to 16MHz * 15/1/2 = 120MHz + // This would lead to HrTim running at 120MHz * 32 = 3.84... + let pwr = dp.PWR.constrain().freeze(); + let mut rcc = Input to hrtim needs to be 128MHz when using HSI, 128-144 with HSE + + let mut delay = cp.SYST.delay(&rcc.clocks); + + // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 960MHz + // With max the max period set, this would be 960MHz/2^16 ~= 15kHz... + let prescaler = Pscl4; + + let gpioa = dp.GPIOA.split(&mut rcc); + let pin_a = gpioa.pa8; + let pin_b = gpioa.pa9; + + // . . . . + // . 30% . . . + // ---- . .---- . + //out1 | | . | | . + // | | . | | . + // -------- ---------------------------- -------------------- + // . .---- . .---- + //out2 . | | . | | + // . | | . | | + // ------------------------ ---------------------------- ---- + // . . . . + // . . . . + let (hr_control, ..) = dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + let mut hr_control = hr_control.constrain(); + + let HrParts { + mut timer, + mut cr1, + out: (mut out1, mut out2), + .. + } = dp + .HRTIM_TIMA + .pwm_advanced((pin_a, pin_b), &mut rcc) + .prescaler(prescaler) + .period(0xFFFF) + .push_pull_mode(true) // Set push pull mode, out1 and out2 are + // alternated every period with one being + // inactive and the other getting to output its wave form + // as normal + .finalize(&mut hr_control); + + out1.enable_rst_event(&cr1); // Set low on compare match with cr1 + out2.enable_rst_event(&cr1); + + out1.enable_set_event(&timer); // Set high at new period + out2.enable_set_event(&timer); + + out1.enable(); + out2.enable(); + + loop { + // Step frequency from 18kHz to about 180kHz(half of that when only looking at one pin) + for i in 1..10 { + let new_period = u16::MAX / i; + + cr1.set_duty(new_period / 3); + timer.set_period(new_period); + + delay.delay(500_u32.millis()); + } + } +} diff --git a/examples/stm32h7/hrtim.rs b/examples/stm32h7/hrtim.rs new file mode 100644 index 0000000..2acebdc --- /dev/null +++ b/examples/stm32h7/hrtim.rs @@ -0,0 +1,103 @@ +#![no_std] +#![no_main] + +use cortex_m_rt::entry; +use panic_probe as _; +use stm32_hrtim::{ + compare_register::HrCompareRegister, control::HrControltExt, output::HrOutput, timer::HrTimer, + HrParts, HrPwmAdvExt, Pscl4, +}; +use stm32h7xx_hal::{ + delay::DelayExt, + gpio::GpioExt, + pwr::PwrExt, + rcc::{self, RccExt}, + stm32::{CorePeripherals, Peripherals}, +}; + +use fugit::{ExtU32, RateExtU32 as _}; + +#[entry] +fn main() -> ! { + defmt::info!("Initializing..."); + + let dp = Peripherals::take().expect("cannot take peripherals"); + let cp = CorePeripherals::take().expect("cannot take core"); + + // Constrain and Freeze power + let pwr = dp.PWR.constrain(); + let pwrcfg = pwr.freeze(); + + // Constrain and Freeze clock + let rcc = dp.RCC.constrain(); + let ccdr = rcc.sys_ck(320.MHz()).freeze(pwrcfg, &dp.SYSCFG); + + // Acquire the GPIO peripherals. This also enables the clock for + // the GPIOs in the RCC register. + let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA); + + // Get the delay provider. + let mut delay = cp.SYST.delay(ccdr.clocks); + + // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 960MHz + // With max the max period set, this would be 960MHz/2^16 ~= 15kHz... + let prescaler = Pscl4; + + let pin_a = gpioa.pa8; + let pin_b = gpioa.pa9; + + // . . . . + // . 30% . . . + // ---- . .---- . + //out1 | | . | | . + // | | . | | . + // -------- ---------------------------- -------------------- + // . .---- . .---- + //out2 . | | . | | + // . | | . | | + // ------------------------ ---------------------------- ---- + // . . . . + // . . . . + let (hr_control, ..) = dp + .HRTIM_COMMON + .hr_control(ccdr.peripheral.HRTIM) + .wait_for_calibration(); + let mut hr_control = hr_control.constrain(); + + let HrParts { + mut timer, + mut cr1, + out: (mut out1, mut out2), + .. + } = dp + .HRTIM_TIMA + .pwm_advanced((pin_a, pin_b), &mut rcc) + .prescaler(prescaler) + .period(0xFFFF) + .push_pull_mode(true) // Set push pull mode, out1 and out2 are + // alternated every period with one being + // inactive and the other getting to output its wave form + // as normal + .finalize(&mut hr_control); + + out1.enable_rst_event(&cr1); // Set low on compare match with cr1 + out2.enable_rst_event(&cr1); + + out1.enable_set_event(&timer); // Set high at new period + out2.enable_set_event(&timer); + + out1.enable(); + out2.enable(); + + loop { + // Step frequency from 18kHz to about 180kHz(half of that when only looking at one pin) + for i in 1..10 { + let new_period = u16::MAX / i; + + cr1.set_duty(new_period / 3); + timer.set_period(new_period); + + delay.delay(500_u32.millis()); + } + } +} From a5a28b71e537a2750b5d7fff812cdb20f0381b84 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Thu, 12 Dec 2024 21:18:45 +0100 Subject: [PATCH 17/25] Some fixes for H7 --- src/control.rs | 4 ---- src/lib.rs | 20 +++++++++++++++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/control.rs b/src/control.rs index 4be8c52..ab57af4 100644 --- a/src/control.rs +++ b/src/control.rs @@ -156,10 +156,6 @@ impl HrTimOngoingCalibration { .fltinr2() .write(|w| w.fltsd().bits(flt_divider as u8)); - #[cfg(feature = "stm32h7")] - let please_dont_forget_to_remove_this_once_pac_is_fixed = (); - - #[cfg(not(feature = "stm32h7"))] common.eecr3().write(|w| w.eevsd().bits(eev_divider as u8)); #[cfg(feature = "stm32g4")] diff --git a/src/lib.rs b/src/lib.rs index 3da8a35..02b26e9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -178,7 +178,7 @@ pub trait HrPwmAdvExt: Sized { self, _pins: PINS, rcc: &mut Rcc, - ) -> HrPwmBuilder + ) -> HrPwmBuilder where PINS: ToHrOut; } @@ -551,7 +551,7 @@ macro_rules! hrtim_hal { self, pins: PINS, _rcc: &mut Rcc, - ) -> HrPwmBuilder + ) -> HrPwmBuilder where PINS: ToHrOut<$TIMX>, { @@ -705,7 +705,7 @@ impl HrPwmAdvExt for HRTIM_MASTER { self, pins: PINS, _rcc: &mut Rcc, - ) -> HrPwmBuilder + ) -> HrPwmBuilder where PINS: ToHrOut, { @@ -815,6 +815,13 @@ macro_rules! impl_pscl { )+}; } +#[cfg(any(feature = "stm32f3", feature = "stm32g4"))] +pub type PsclDefault = Pscl128; + +#[cfg(feature = "stm32h7")] +pub type PsclDefault = Pscl4; + +#[cfg(any(feature = "stm32f3", feature = "stm32g4"))] impl_pscl! { Pscl1 => 0b000, 1, 0x0060, 0xFFDF Pscl2 => 0b001, 2, 0x0030, 0xFFEF @@ -826,6 +833,13 @@ impl_pscl! { Pscl128 => 0b111, 128, 0x0003, 0xFFFD } +#[cfg(feature = "stm32h7")] +impl_pscl! { + Pscl1 => 0b101, 1, 0x0003, 0xFFFD + Pscl2 => 0b110, 2, 0x0003, 0xFFFD + Pscl4 => 0b111, 4, 0x0003, 0xFFFD +} + /* /// HrTim timer struct TimerHrTim(PhantomData); From 5234ff2599d5a5e93e5755c25ee9858a05002bb0 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Thu, 12 Dec 2024 22:27:10 +0100 Subject: [PATCH 18/25] G4 and H7 examples are compiling --- Cargo.toml | 23 +++++++++++++--- examples/stm32g4/adc-trigger.rs | 2 +- examples/stm32g4/capture-dma.rs | 2 +- examples/stm32g4/capture.rs | 2 +- examples/stm32g4/eev-comp.rs | 2 +- examples/stm32g4/eev.rs | 2 +- examples/stm32g4/flt-comp.rs | 2 +- examples/stm32g4/flt.rs | 2 +- examples/stm32g4/hrtim.rs | 2 +- examples/stm32g4/master.rs | 4 +-- examples/stm32h7/hrtim.rs | 15 ++++++----- src/compare_register.rs | 48 +++++++++++++++++++++++++++++++-- src/control.rs | 18 ++++++++----- src/external_event.rs | 6 ----- src/lib.rs | 4 --- src/output.rs | 30 ++++++++++++++++++--- src/stm32h7.rs | 1 + 17 files changed, 124 insertions(+), 41 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c2eb3a9..256b5f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] stm32f3 = { git = "https://github.com/stm32-rs/stm32-rs-nightlies", optional = true } -#stm32h7 = { git = "", optional = true } +stm32h7 = { git = "https://github.com/stm32-rs/stm32-rs-nightlies", fatures = ["critical-section"], optional = true } #stm32g4 = { git = "", optional = true } #stm32f3xx-hal = { version = "0.10.0", optional = true } @@ -35,7 +35,7 @@ hrtim_v1_1 = [] hrtim_v2 = [] stm32f3 = ["stm32f3/stm32f3x4"] -stm32h7 = [] +stm32h7 = ["dep:stm32h7"] stm32g4 = [] stm32f334x4 = ["stm32f3", "stm32f3xx-hal/stm32f334x4", "hrtim_v1"] @@ -55,6 +55,16 @@ stm32g474 = ["stm32g4", "stm32g4xx-hal/stm32g474", "hrtim_v2"] stm32g484 = ["stm32g4", "stm32g4xx-hal/stm32g484", "hrtim_v2"] defmt = ["dep:defmt", "fugit/defmt"] +# F3 + +[[example]] +name = "stm32f3" +required-features = ["stm32f3"] +path = "examples/stm32f3/hrtim.rs" + + +# G4 + [[example]] name = "stm32g4-adc-trigger" required-features = ["stm32g4"] @@ -98,4 +108,11 @@ path = "examples/stm32g4/hrtim.rs" [[example]] name = "stm32g4-master" required-features = ["stm32g4"] -path = "examples/stm32g4/master.rs" \ No newline at end of file +path = "examples/stm32g4/master.rs" + +# H7 + +[[example]] +name = "stm32h7" +required-features = ["stm32h7"] +path = "examples/stm32h7/hrtim.rs" \ No newline at end of file diff --git a/examples/stm32g4/adc-trigger.rs b/examples/stm32g4/adc-trigger.rs index 9ec143f..3150ec6 100644 --- a/examples/stm32g4/adc-trigger.rs +++ b/examples/stm32g4/adc-trigger.rs @@ -83,7 +83,7 @@ fn main() -> ! { .. } = dp .HRTIM_TIMA - .pwm_advanced((pin_a, pin_b), &mut rcc) + .pwm_advanced((pin_a, pin_b)) .prescaler(prescaler) .period(period) .finalize(&mut hr_control); diff --git a/examples/stm32g4/capture-dma.rs b/examples/stm32g4/capture-dma.rs index d8486ae..9ea1341 100644 --- a/examples/stm32g4/capture-dma.rs +++ b/examples/stm32g4/capture-dma.rs @@ -87,7 +87,7 @@ fn main() -> ! { .. } = dp .HRTIM_TIMA - .pwm_advanced(pin_a, &mut rcc) + .pwm_advanced(pin_a) .prescaler(prescaler) .period(period) .finalize(&mut hr_control); diff --git a/examples/stm32g4/capture.rs b/examples/stm32g4/capture.rs index 6efe8e9..522aaa2 100644 --- a/examples/stm32g4/capture.rs +++ b/examples/stm32g4/capture.rs @@ -82,7 +82,7 @@ fn main() -> ! { .. } = dp .HRTIM_TIMA - .pwm_advanced(pin_a, &mut rcc) + .pwm_advanced(pin_a) .prescaler(prescaler) .period(period) .finalize(&mut hr_control); diff --git a/examples/stm32g4/eev-comp.rs b/examples/stm32g4/eev-comp.rs index 7d3544a..a0804ee 100644 --- a/examples/stm32g4/eev-comp.rs +++ b/examples/stm32g4/eev-comp.rs @@ -111,7 +111,7 @@ fn main() -> ! { .. } = dp .HRTIM_TIMA - .pwm_advanced(pin_a, &mut rcc) + .pwm_advanced(pin_a) .prescaler(prescaler) .eev_cfg(EevCfgs::default().eev4(EevCfg::default())) .period(0xFFFF) diff --git a/examples/stm32g4/eev.rs b/examples/stm32g4/eev.rs index 8911daf..aa245ba 100644 --- a/examples/stm32g4/eev.rs +++ b/examples/stm32g4/eev.rs @@ -83,7 +83,7 @@ fn main() -> ! { .. } = dp .HRTIM_TIMA - .pwm_advanced(pin_a, &mut rcc) + .pwm_advanced(pin_a) .prescaler(prescaler) .eev_cfg(EevCfgs::default()) .period(0xFFFF) diff --git a/examples/stm32g4/flt-comp.rs b/examples/stm32g4/flt-comp.rs index 587620c..6116088 100644 --- a/examples/stm32g4/flt-comp.rs +++ b/examples/stm32g4/flt-comp.rs @@ -115,7 +115,7 @@ fn main() -> ! { .. } = dp .HRTIM_TIMA - .pwm_advanced(pin_a, &mut rcc) + .pwm_advanced(pin_a) .prescaler(prescaler) .period(0xFFFF) .with_fault_source(fault_source5) // Set fault source diff --git a/examples/stm32g4/flt.rs b/examples/stm32g4/flt.rs index 53d966e..c3f7fb1 100644 --- a/examples/stm32g4/flt.rs +++ b/examples/stm32g4/flt.rs @@ -81,7 +81,7 @@ fn main() -> ! { .. } = dp .HRTIM_TIMA - .pwm_advanced(pin_a, &mut rcc) + .pwm_advanced(pin_a) .prescaler(prescaler) .period(0xFFFF) //.with_fault_source(fault_source1) diff --git a/examples/stm32g4/hrtim.rs b/examples/stm32g4/hrtim.rs index f2c3891..e44e93b 100644 --- a/examples/stm32g4/hrtim.rs +++ b/examples/stm32g4/hrtim.rs @@ -69,7 +69,7 @@ fn main() -> ! { .. } = dp .HRTIM_TIMA - .pwm_advanced((pin_a, pin_b), &mut rcc) + .pwm_advanced((pin_a, pin_b)) .prescaler(prescaler) .period(0xFFFF) .push_pull_mode(true) // Set push pull mode, out1 and out2 are diff --git a/examples/stm32g4/master.rs b/examples/stm32g4/master.rs index 1028cde..ea2ed3c 100644 --- a/examples/stm32g4/master.rs +++ b/examples/stm32g4/master.rs @@ -70,7 +70,7 @@ fn main() -> ! { .. } = dp .HRTIM_TIMA - .pwm_advanced((pin_a, pin_b), &mut rcc) + .pwm_advanced((pin_a, pin_b)) .prescaler(prescaler) .push_pull_mode(true) // Set push pull mode, out1 and out2 are // alternated every period with one being @@ -86,7 +86,7 @@ fn main() -> ! { .. } = dp .HRTIM_MASTER - .pwm_advanced((), &mut rcc) + .pwm_advanced(()) .prescaler(prescaler) .preload(MasterPreloadSource::OnMasterRepetitionUpdate) .period(0xFFFF) diff --git a/examples/stm32h7/hrtim.rs b/examples/stm32h7/hrtim.rs index 2acebdc..08b401c 100644 --- a/examples/stm32h7/hrtim.rs +++ b/examples/stm32h7/hrtim.rs @@ -8,14 +8,15 @@ use stm32_hrtim::{ HrParts, HrPwmAdvExt, Pscl4, }; use stm32h7xx_hal::{ + prelude::_embedded_hal_blocking_delay_DelayMs, delay::DelayExt, gpio::GpioExt, pwr::PwrExt, - rcc::{self, RccExt}, + rcc::RccExt, stm32::{CorePeripherals, Peripherals}, }; -use fugit::{ExtU32, RateExtU32 as _}; +use fugit::RateExtU32 as _; #[entry] fn main() -> ! { @@ -34,7 +35,7 @@ fn main() -> ! { // Acquire the GPIO peripherals. This also enables the clock for // the GPIOs in the RCC register. - let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA); + let gpioc = dp.GPIOC.split(ccdr.peripheral.GPIOC); // Get the delay provider. let mut delay = cp.SYST.delay(ccdr.clocks); @@ -43,8 +44,8 @@ fn main() -> ! { // With max the max period set, this would be 960MHz/2^16 ~= 15kHz... let prescaler = Pscl4; - let pin_a = gpioa.pa8; - let pin_b = gpioa.pa9; + let pin_a = gpioc.pc6.into_input(); + let pin_b = gpioc.pc7.into_input(); // . . . . // . 30% . . . @@ -71,7 +72,7 @@ fn main() -> ! { .. } = dp .HRTIM_TIMA - .pwm_advanced((pin_a, pin_b), &mut rcc) + .pwm_advanced((pin_a, pin_b)) .prescaler(prescaler) .period(0xFFFF) .push_pull_mode(true) // Set push pull mode, out1 and out2 are @@ -97,7 +98,7 @@ fn main() -> ! { cr1.set_duty(new_period / 3); timer.set_period(new_period); - delay.delay(500_u32.millis()); + delay.delay_ms(500_u16); } } } diff --git a/src/compare_register.rs b/src/compare_register.rs index 1afa31f..c49f8a0 100644 --- a/src/compare_register.rs +++ b/src/compare_register.rs @@ -23,7 +23,6 @@ use super::adc_trigger::Adc579Trigger as Adc579; #[cfg(feature = "stm32g4")] use super::adc_trigger::Adc6810Trigger as Adc6810; -#[cfg(feature = "stm32g4")] macro_rules! hrtim_cr_helper { (HRTIM_MASTER: $cr_type:ident: $cmpXYr:ident, @@ -76,7 +75,6 @@ macro_rules! hrtim_cr_helper { }; } -#[cfg(feature = "stm32g4")] macro_rules! hrtim_cr { ($($TIMX:ident: [ [$(($cr1_trigger:ident: $cr1_trigger_bits:expr)),*], [$(($cr1_event_dst:ident, $cr1_tim_event_index:expr)),*], @@ -144,6 +142,52 @@ hrtim_cr! { ] } +// TODO: Populate more things +#[cfg(any(feature = "stm32f3", feature = "stm32h7"))] +hrtim_cr! { + HRTIM_MASTER: [ + [], [], + [], [], + [], [], + [], [] + ], + + HRTIM_TIMA: [ + [], [], + [], [], + [], [], + [], [] + ], + + HRTIM_TIMB: [ + [], [], + [], [], + [], [], + [], [] + ], + + HRTIM_TIMC: [ + [], [], + [], [], + [], [], + [], [] + ], + + HRTIM_TIMD: [ + [], [], + [], [], + [], [], + [], [] + ], + + HRTIM_TIME: [ + [], [], + [], [], + [], [], + [], [] + ] +} + macro_rules! hrtim_master_cr { ($($cr_type:ident: $cr_index:expr),*) => {$( /// Compare match event for neighbor timer diff --git a/src/control.rs b/src/control.rs index ab57af4..aacf292 100644 --- a/src/control.rs +++ b/src/control.rs @@ -7,24 +7,30 @@ use crate::fault::{ use crate::{hal, stm32}; #[cfg(feature = "stm32h7")] -use hal::rcc::{rec::Hrtim as Rcc, ResetEnable as Reset, ResetEnable as Enable}; +use hal::rcc::ResetEnable as _; #[cfg(not(feature = "stm32h7"))] use hal::rcc::{Enable, Reset}; -#[cfg(not(feature = "stm32h7"))] -type Rcc = &mut hal::rcc::Rcc; - use stm32::HRTIM_COMMON; use super::{external_event::EevInputs, fault::FaultInputs}; pub trait HrControltExt { - fn hr_control(self, _rcc: Rcc) -> HrTimOngoingCalibration; + #[cfg(feature = "stm32h7")] + fn hr_control(self, _rcc: hal::rcc::rec::Hrtim) -> HrTimOngoingCalibration; + + #[cfg(not(feature = "stm32h7"))] + fn hr_control(self, _rcc: &mut hal::rcc::Rcc) -> HrTimOngoingCalibration; } impl HrControltExt for HRTIM_COMMON { - fn hr_control(self, #[allow(unused_variables)] rcc: Rcc) -> HrTimOngoingCalibration { + fn hr_control(self, + #[cfg(feature = "stm32h7")] rcc: hal::rcc::rec::Hrtim, + + #[allow(unused_variables)] + #[cfg(not(feature = "stm32h7"))] rcc: &mut hal::rcc::Rcc, + ) -> HrTimOngoingCalibration { let common = unsafe { &*HRTIM_COMMON::ptr() }; let rcc = { diff --git a/src/external_event.rs b/src/external_event.rs index 4ac46d9..f344010 100644 --- a/src/external_event.rs +++ b/src/external_event.rs @@ -328,12 +328,6 @@ macro_rules! impl_eev6_10_to_es { let common = unsafe { &*HRTIM_COMMON::ptr() }; - #[cfg(feature = "stm32h7")] - let please_dont_forget_to_remove_this_once_pac_is_fixed = (); - - // SAFETY: Thanks to, `HrTimCalibrated`, we know we have exclusive access to the register, - // we also know no timers are started. - #[cfg(not(feature = "stm32h7"))] unsafe { common.eecr2().modify(|_r, w| { w.$eeXsrc() diff --git a/src/lib.rs b/src/lib.rs index 02b26e9..e371a42 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,6 @@ use self::deadtime::DeadtimeConfig; use self::output::ToHrOut; use self::timer_eev_cfg::EevCfgs; use fugit::HertzU32 as Hertz; -use hal::rcc::Rcc; /// Internal enum that keeps track of the count settings before PWM is finalized enum CountSettings { @@ -177,7 +176,6 @@ pub trait HrPwmAdvExt: Sized { fn pwm_advanced( self, _pins: PINS, - rcc: &mut Rcc, ) -> HrPwmBuilder where PINS: ToHrOut; @@ -550,7 +548,6 @@ macro_rules! hrtim_hal { fn pwm_advanced( self, pins: PINS, - _rcc: &mut Rcc, ) -> HrPwmBuilder where PINS: ToHrOut<$TIMX>, @@ -704,7 +701,6 @@ impl HrPwmAdvExt for HRTIM_MASTER { fn pwm_advanced( self, pins: PINS, - _rcc: &mut Rcc, ) -> HrPwmBuilder where PINS: ToHrOut, diff --git a/src/output.rs b/src/output.rs index 2b06f7f..05af02a 100644 --- a/src/output.rs +++ b/src/output.rs @@ -8,10 +8,23 @@ use crate::{ use core::marker::PhantomData; use super::event::EventSource; + use hal::gpio::{ gpioa::{PA10, PA11, PA8, PA9}, + gpioc::PC8, +}; + +#[cfg(any(feature = "stm32f3", feature = "stm32g4"))] +use hal::gpio::{ gpiob::{PB12, PB13, PB14, PB15}, - gpioc::{PC8, PC9}, + gpioc::PC9, +}; + +#[cfg(feature = "stm32h7")] +use hal::gpio::{ + gpioa::PA12, + gpioc::{PC6, PC7}, + gpiog::{PG6, PG7}, }; #[cfg(feature = "stm32g4")] @@ -195,7 +208,7 @@ where } } -#[cfg(feature = "stm32g4")] +#[cfg(any(feature = "stm32g4", feature = "stm32h7"))] impl ToHrOut for (PA, PB) where PA: ToHrOut, @@ -240,13 +253,14 @@ macro_rules! pins_helper { let _: $CHY> = self.into_af_push_pull(moder, otyper, afr); - #[cfg(feature = "stm32g4")] + #[cfg(any(feature = "stm32g4", feature = "stm32h7"))] let _: $CHY> = self.into_alternate(); } } }; } +// $GpioX is only used for f3x4 macro_rules! pins { ($($TIMX:ty: CH1: $CH1:ident<$CH1_AF:literal>, CH2: $CH2:ident<$CH2_AF:literal>, $GpioX:ident)+) => {$( pins_helper!($TIMX, HrOut1, $CH1<$CH1_AF>, $GpioX); @@ -268,6 +282,16 @@ pins! { HRTIM_TIMF: CH1: PC6<13>, CH2: PC7<13>, Gpioc } +// TODO: H7 does not start in input mode, it starts in Analog +#[cfg(feature = "stm32h7")] // RM0433 +pins! { + HRTIM_TIMA: CH1: PC6<1>, CH2: PC7<1>, Gpioc + HRTIM_TIMB: CH1: PC8<1>, CH2: PA8<2>, GpioC // This type is not used for in this config so it's ok + HRTIM_TIMC: CH1: PA9<2>, CH2: PA10<2>, GpioA + HRTIM_TIMD: CH1: PA11<2>, CH2: PA12<2>, GpioA + HRTIM_TIME: CH1: PG6<2>, CH2: PG7<2>, GpioG +} + impl sealed::Sealed for () {} impl ToHrOut for () { type Out = (); diff --git a/src/stm32h7.rs b/src/stm32h7.rs index f74baba..fd8c117 100644 --- a/src/stm32h7.rs +++ b/src/stm32h7.rs @@ -1,6 +1,7 @@ pub use hal::stm32; pub use stm32h7xx_hal as hal; +// TODO: H7 does not start in input mode, it starts in Analog pub type GpioInputMode = hal::gpio::Input; pub use hal::pwm::Alignment; From ffd77b58103428cc9cd7cc48c6f625b80f511a43 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Fri, 13 Dec 2024 23:54:22 +0100 Subject: [PATCH 19/25] Examples for all devices compiles --- examples/stm32f3/hrtim.rs | 50 ++++++++++++++++++++++++++------------- src/control.rs | 27 ++++++++++++++------- 2 files changed, 53 insertions(+), 24 deletions(-) diff --git a/examples/stm32f3/hrtim.rs b/examples/stm32f3/hrtim.rs index cec37dc..9de491a 100644 --- a/examples/stm32f3/hrtim.rs +++ b/examples/stm32f3/hrtim.rs @@ -7,13 +7,13 @@ use stm32_hrtim::{ compare_register::HrCompareRegister, control::HrControltExt, output::HrOutput, timer::HrTimer, HrParts, HrPwmAdvExt, Pscl4, }; -use stm32g4xx_hal::{ - delay::{DelayExt, SYSTDelayExt}, +use stm32f3xx_hal::{ + delay::Delay, + flash::FlashExt as _, gpio::GpioExt, - pwr::PwrExt, - rcc::{self, RccExt}, - stm32::{CorePeripherals, Peripherals}, - time::ExtU32, + pac::{CorePeripherals, Peripherals}, + prelude::{_embedded_hal_blocking_delay_DelayMs, _stm32f3xx_hal_time_rate_Extensions}, + rcc::RccExt, }; #[entry] @@ -22,18 +22,28 @@ fn main() -> ! { let dp = Peripherals::take().expect("cannot take peripherals"); let cp = CorePeripherals::take().expect("cannot take core"); - // Set system frequency to 16MHz * 15/1/2 = 120MHz - // This would lead to HrTim running at 120MHz * 32 = 3.84... - let pwr = dp.PWR.constrain().freeze(); - let mut rcc = Input to hrtim needs to be 128MHz when using HSI, 128-144 with HSE - let mut delay = cp.SYST.delay(&rcc.clocks); + let mut flash = dp.FLASH.constrain(); + let mut rcc = dp.RCC.constrain(); + let mut gpioa = dp.GPIOA.split(&mut rcc.ahb); + + //let mut rcc = Input to hrtim needs to be 128MHz when using HSI, 128-144 with HSE + + // Set system frequency to 64MHz using PLL, PLLCLKx2 will thus be 128MHz which + // feeds into the HRTIM. This and the HRTIM's DLL would lead to an effective + // HRTIM frequency of 128MHz * 32 = 4.096GHz... + let clocks = rcc + .cfgr + .sysclk(64_u32.MHz()) + .use_pll() + .freeze(&mut flash.acr); + + let mut delay = Delay::new(cp.SYST, clocks); // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 960MHz // With max the max period set, this would be 960MHz/2^16 ~= 15kHz... let prescaler = Pscl4; - let gpioa = dp.GPIOA.split(&mut rcc); let pin_a = gpioa.pa8; let pin_b = gpioa.pa9; @@ -49,7 +59,10 @@ fn main() -> ! { // ------------------------ ---------------------------- ---- // . . . . // . . . . - let (hr_control, ..) = dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + let (hr_control, ..) = dp + .HRTIM_COMMON + .hr_control(&clocks, &mut rcc.apb2) + .wait_for_calibration(); let mut hr_control = hr_control.constrain(); let HrParts { @@ -59,14 +72,19 @@ fn main() -> ! { .. } = dp .HRTIM_TIMA - .pwm_advanced((pin_a, pin_b), &mut rcc) + .pwm_advanced((pin_a, pin_b)) .prescaler(prescaler) .period(0xFFFF) .push_pull_mode(true) // Set push pull mode, out1 and out2 are // alternated every period with one being // inactive and the other getting to output its wave form // as normal - .finalize(&mut hr_control); + .finalize( + &mut hr_control, + &mut gpioa.moder, + &mut gpioa.otyper, + &mut gpioa.afrh, + ); out1.enable_rst_event(&cr1); // Set low on compare match with cr1 out2.enable_rst_event(&cr1); @@ -85,7 +103,7 @@ fn main() -> ! { cr1.set_duty(new_period / 3); timer.set_period(new_period); - delay.delay(500_u32.millis()); + delay.delay_ms(500_u16); } } } diff --git a/src/control.rs b/src/control.rs index aacf292..228d28b 100644 --- a/src/control.rs +++ b/src/control.rs @@ -17,19 +17,30 @@ use stm32::HRTIM_COMMON; use super::{external_event::EevInputs, fault::FaultInputs}; pub trait HrControltExt { - #[cfg(feature = "stm32h7")] - fn hr_control(self, _rcc: hal::rcc::rec::Hrtim) -> HrTimOngoingCalibration; + fn hr_control( + self, + #[cfg(feature = "stm32f3")] _clocks: &hal::rcc::Clocks, + #[cfg(feature = "stm32f3")] apb2: &mut hal::rcc::APB2, - #[cfg(not(feature = "stm32h7"))] - fn hr_control(self, _rcc: &mut hal::rcc::Rcc) -> HrTimOngoingCalibration; + #[allow(unused_variables)] + #[cfg(feature = "stm32g4")] + rcc: &mut hal::rcc::Rcc, + + #[cfg(feature = "stm32h7")] rcc: hal::rcc::rec::Hrtim, + ) -> HrTimOngoingCalibration; } impl HrControltExt for HRTIM_COMMON { - fn hr_control(self, - #[cfg(feature = "stm32h7")] rcc: hal::rcc::rec::Hrtim, + fn hr_control( + self, + #[cfg(feature = "stm32f3")] _clocks: &hal::rcc::Clocks, + #[cfg(feature = "stm32f3")] apb2: &mut hal::rcc::APB2, #[allow(unused_variables)] - #[cfg(not(feature = "stm32h7"))] rcc: &mut hal::rcc::Rcc, + #[cfg(feature = "stm32g4")] + rcc: &mut hal::rcc::Rcc, + + #[cfg(feature = "stm32h7")] rcc: hal::rcc::rec::Hrtim, ) -> HrTimOngoingCalibration { let common = unsafe { &*HRTIM_COMMON::ptr() }; @@ -41,7 +52,7 @@ impl HrControltExt for HRTIM_COMMON { #[cfg(feature = "stm32f3")] { - &mut rcc.apb2 + apb2 } #[cfg(feature = "stm32h7")] From 5ed0deb1290d5f9315ea44b108c1f0705fed77bf Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sat, 14 Dec 2024 00:01:12 +0100 Subject: [PATCH 20/25] Enable H7 in CI --- .github/workflows/ci.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 57a8de9..2e87e9d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,14 +19,14 @@ jobs: - stm32f334x6 - stm32f334x8 - #- stm32h742 - #- stm32h743 - ##- stm32h745 - ##- stm32h747 - #- stm32h750 - #- stm32h753 - ##- stm32h755 - ##- stm32h757 + - stm32h742 + - stm32h743 + #- stm32h745 + - stm32h747cm7 + - stm32h750 + - stm32h753 + #- stm32h755 + #- stm32h757 - stm32g474 - stm32g484 From 3b8bbb6d23268965795bba87ddcba83ebcd7ec64 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sat, 14 Dec 2024 01:08:47 +0100 Subject: [PATCH 21/25] Update examples with calculations of frequencies --- examples/stm32f3/hrtim.rs | 10 ++++------ examples/stm32g4/hrtim.rs | 6 +++--- examples/stm32h7/hrtim.rs | 23 +++++++++++++++-------- src/control.rs | 7 +++++++ 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/examples/stm32f3/hrtim.rs b/examples/stm32f3/hrtim.rs index 9de491a..61d52cb 100644 --- a/examples/stm32f3/hrtim.rs +++ b/examples/stm32f3/hrtim.rs @@ -27,8 +27,6 @@ fn main() -> ! { let mut rcc = dp.RCC.constrain(); let mut gpioa = dp.GPIOA.split(&mut rcc.ahb); - //let mut rcc = Input to hrtim needs to be 128MHz when using HSI, 128-144 with HSE - // Set system frequency to 64MHz using PLL, PLLCLKx2 will thus be 128MHz which // feeds into the HRTIM. This and the HRTIM's DLL would lead to an effective // HRTIM frequency of 128MHz * 32 = 4.096GHz... @@ -40,8 +38,8 @@ fn main() -> ! { let mut delay = Delay::new(cp.SYST, clocks); - // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 960MHz - // With max the max period set, this would be 960MHz/2^16 ~= 15kHz... + // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 1024MHz + // With max the max period set, this would be 1024MHz/2^16 ~= 15.6kHz... let prescaler = Pscl4; let pin_a = gpioa.pa8; @@ -96,8 +94,8 @@ fn main() -> ! { out2.enable(); loop { - // Step frequency from 18kHz to about 180kHz(half of that when only looking at one pin) - for i in 1..10 { + // Step frequency from 15.6kHz to about 156kHz(half of that when only looking at one pin) + for i in 1..=10 { let new_period = u16::MAX / i; cr1.set_duty(new_period / 3); diff --git a/examples/stm32g4/hrtim.rs b/examples/stm32g4/hrtim.rs index e44e93b..df1081c 100644 --- a/examples/stm32g4/hrtim.rs +++ b/examples/stm32g4/hrtim.rs @@ -40,7 +40,7 @@ fn main() -> ! { let mut delay = cp.SYST.delay(&rcc.clocks); // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 960MHz - // With max the max period set, this would be 960MHz/2^16 ~= 15kHz... + // With max the max period set, this would be 960MHz/2^16 ~= 14.6kHz... let prescaler = Pscl4; let gpioa = dp.GPIOA.split(&mut rcc); @@ -88,8 +88,8 @@ fn main() -> ! { out2.enable(); loop { - // Step frequency from 18kHz to about 180kHz(half of that when only looking at one pin) - for i in 1..10 { + // Step frequency from 14.6kHz to about 146kHz(half of that when only looking at one pin) + for i in 1..=10 { let new_period = u16::MAX / i; cr1.set_duty(new_period / 3); diff --git a/examples/stm32h7/hrtim.rs b/examples/stm32h7/hrtim.rs index 08b401c..130c6fb 100644 --- a/examples/stm32h7/hrtim.rs +++ b/examples/stm32h7/hrtim.rs @@ -5,12 +5,12 @@ use cortex_m_rt::entry; use panic_probe as _; use stm32_hrtim::{ compare_register::HrCompareRegister, control::HrControltExt, output::HrOutput, timer::HrTimer, - HrParts, HrPwmAdvExt, Pscl4, + HrParts, HrPwmAdvExt, Pscl1, }; use stm32h7xx_hal::{ - prelude::_embedded_hal_blocking_delay_DelayMs, delay::DelayExt, gpio::GpioExt, + prelude::_embedded_hal_blocking_delay_DelayMs, pwr::PwrExt, rcc::RccExt, stm32::{CorePeripherals, Peripherals}, @@ -31,7 +31,14 @@ fn main() -> ! { // Constrain and Freeze clock let rcc = dp.RCC.constrain(); - let ccdr = rcc.sys_ck(320.MHz()).freeze(pwrcfg, &dp.SYSCFG); + + // With a sys_ck of 240MHz and d1cpre of 1 if the HRTIM will be fed by 240MHz/1 = 240MHz + // since HRTIMSEL is set to take the HRTIM's clock directly from the core clock. The + // stm32h7 devices' HRTIM does not have a DLL, also leading to an effective HRTIM + // frequency of 240MHz... + let ccdr = rcc + .sys_ck(240.MHz()) + .freeze(pwrcfg, &dp.SYSCFG); // Acquire the GPIO peripherals. This also enables the clock for // the GPIOs in the RCC register. @@ -40,9 +47,9 @@ fn main() -> ! { // Get the delay provider. let mut delay = cp.SYST.delay(ccdr.clocks); - // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 960MHz - // With max the max period set, this would be 960MHz/2^16 ~= 15kHz... - let prescaler = Pscl4; + // ...with a prescaler of 1 this gives us a HrTimer with a tick rate of 240MHz + // With max the max period set, this would be 240MHz/2^16 ~= 3.7kHz... + let prescaler = Pscl1; let pin_a = gpioc.pc6.into_input(); let pin_b = gpioc.pc7.into_input(); @@ -61,7 +68,7 @@ fn main() -> ! { // . . . . let (hr_control, ..) = dp .HRTIM_COMMON - .hr_control(ccdr.peripheral.HRTIM) + .hr_control(&ccdr.clocks, ccdr.peripheral.HRTIM) .wait_for_calibration(); let mut hr_control = hr_control.constrain(); @@ -91,7 +98,7 @@ fn main() -> ! { out2.enable(); loop { - // Step frequency from 18kHz to about 180kHz(half of that when only looking at one pin) + // Step frequency from 3.7kHz to about 36.6kHz(half of that when only looking at one pin) for i in 1..10 { let new_period = u16::MAX / i; diff --git a/src/control.rs b/src/control.rs index 228d28b..edff930 100644 --- a/src/control.rs +++ b/src/control.rs @@ -26,6 +26,7 @@ pub trait HrControltExt { #[cfg(feature = "stm32g4")] rcc: &mut hal::rcc::Rcc, + #[cfg(feature = "stm32h7")] _clocks: &hal::rcc::CoreClocks, #[cfg(feature = "stm32h7")] rcc: hal::rcc::rec::Hrtim, ) -> HrTimOngoingCalibration; } @@ -40,6 +41,7 @@ impl HrControltExt for HRTIM_COMMON { #[cfg(feature = "stm32g4")] rcc: &mut hal::rcc::Rcc, + #[cfg(feature = "stm32h7")] _clocks: &hal::rcc::CoreClocks, #[cfg(feature = "stm32h7")] rcc: hal::rcc::rec::Hrtim, ) -> HrTimOngoingCalibration { let common = unsafe { &*HRTIM_COMMON::ptr() }; @@ -57,6 +59,11 @@ impl HrControltExt for HRTIM_COMMON { #[cfg(feature = "stm32h7")] { + { + let rcc = unsafe { &*hal::stm32::RCC::ptr() }; + // Same clock source as CPU + rcc.cfgr().modify(|_, w| w.hrtimsel().c_ck()); + } rcc } }; From 7bc500ee4f833810c1a2a17643506e1d505b13e0 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sat, 14 Dec 2024 01:19:27 +0100 Subject: [PATCH 22/25] More cleanup of G4 and H7 examples --- examples/stm32g4/flt-comp.rs | 11 ++++++----- examples/stm32g4/flt.rs | 12 ++---------- examples/stm32g4/master.rs | 4 ++-- examples/stm32h7/hrtim.rs | 4 +--- 4 files changed, 11 insertions(+), 20 deletions(-) diff --git a/examples/stm32g4/flt-comp.rs b/examples/stm32g4/flt-comp.rs index 6116088..4baa222 100644 --- a/examples/stm32g4/flt-comp.rs +++ b/examples/stm32g4/flt-comp.rs @@ -4,6 +4,7 @@ /// Example showcasing the use of the HRTIM peripheral together with a comparator to implement a current fault. /// Once the comparator input exceeds the reference set by the DAC, the output is forced low and put into a fault state. use cortex_m_rt::entry; +use fugit::ExtU32 as _; use panic_probe as _; use stm32_hrtim::{ compare_register::HrCompareRegister, @@ -18,7 +19,7 @@ use stm32g4xx_hal::{ adc::AdcClaim, comparator::{self, ComparatorExt, ComparatorSplit}, dac::{Dac3IntSig1, DacExt, DacOut}, - delay::SYSTDelayExt, + delay::{DelayExt as _, SYSTDelayExt}, gpio::GpioExt, pwr::PwrExt, rcc::{self, RccExt}, @@ -88,8 +89,8 @@ fn main() -> ! { .polarity(hal::pwm::Polarity::ActiveHigh) .finalize(&mut hr_control); - // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 1.2GHz - // With max the max period set, this would be 1.2GHz/2^16 ~= 18kHz... + // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 960MHz + // With max the max period set, this would be 960MHz/2^16 ~= 15kHz... let prescaler = Pscl4; let pin_a = gpioa.pa8; @@ -126,7 +127,7 @@ fn main() -> ! { out1.enable_rst_event(&cr1); // Set low on compare match with cr1 out1.enable_set_event(&timer); // Set high at new period cr1.set_duty(timer.get_period() / 3); - //unsafe {((HRTIM_COMMON::ptr() as *mut u8).offset(0x14) as *mut u32).write_volatile(1); } + out1.enable(); timer.start(&mut hr_control.control); @@ -134,7 +135,7 @@ fn main() -> ! { loop { for _ in 0..5 { - //delay.delay(500_u32.millis()); + delay.delay(500_u32.millis()); defmt::info!( "State: {:?}, comp: {}, is_fault_active: {}, pc1: {}", out1.get_state(), diff --git a/examples/stm32g4/flt.rs b/examples/stm32g4/flt.rs index c3f7fb1..991cdb4 100644 --- a/examples/stm32g4/flt.rs +++ b/examples/stm32g4/flt.rs @@ -84,23 +84,15 @@ fn main() -> ! { .pwm_advanced(pin_a) .prescaler(prescaler) .period(0xFFFF) - //.with_fault_source(fault_source1) - //.with_fault_source(fault_source2) - .with_fault_source(fault_source3) // Set fault source - //.with_fault_source(fault_source4) - //.with_fault_source(fault_source5) - //.with_fault_source(fault_source6) + .with_fault_source(fault_source3) .fault_action1(FaultAction::ForceInactive) .fault_action2(FaultAction::ForceInactive) - // alternated every period with one being - // inactive and the other getting to output its wave form - // as normal .finalize(&mut hr_control); out.enable_rst_event(&cr1); // Set low on compare match with cr1 out.enable_set_event(&timer); // Set high at new period cr1.set_duty(timer.get_period() / 3); - //unsafe {((HRTIM_COMMON::ptr() as *mut u8).offset(0x14) as *mut u32).write_volatile(1); } + out.enable(); timer.start(&mut hr_control.control); diff --git a/examples/stm32g4/master.rs b/examples/stm32g4/master.rs index ea2ed3c..2edef09 100644 --- a/examples/stm32g4/master.rs +++ b/examples/stm32g4/master.rs @@ -107,8 +107,8 @@ fn main() -> ! { defmt::info!("Running"); loop { - // Step frequency from 18kHz to about 180kHz(half of that when only looking at one pin) - for i in 1..10 { + // Step frequency from 15kHz to about 146kHz(half of that when only looking at one pin) + for i in 1..=10 { let new_period = u16::MAX / i; mcr1.set_duty(new_period / 3); diff --git a/examples/stm32h7/hrtim.rs b/examples/stm32h7/hrtim.rs index 130c6fb..f117e91 100644 --- a/examples/stm32h7/hrtim.rs +++ b/examples/stm32h7/hrtim.rs @@ -36,9 +36,7 @@ fn main() -> ! { // since HRTIMSEL is set to take the HRTIM's clock directly from the core clock. The // stm32h7 devices' HRTIM does not have a DLL, also leading to an effective HRTIM // frequency of 240MHz... - let ccdr = rcc - .sys_ck(240.MHz()) - .freeze(pwrcfg, &dp.SYSCFG); + let ccdr = rcc.sys_ck(240.MHz()).freeze(pwrcfg, &dp.SYSCFG); // Acquire the GPIO peripherals. This also enables the clock for // the GPIOs in the RCC register. From f99da02dc671c93f9eadc43a1a359817ee2264b7 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sat, 14 Dec 2024 01:22:14 +0100 Subject: [PATCH 23/25] Rename device feature --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 256b5f7..00e433c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,7 @@ stm32f334x8 = ["stm32f3", "stm32f3xx-hal/stm32f334x8", "hrtim_v1"] stm32h742 = ["stm32h7", "stm32h7xx-hal/stm32h742", "hrtim_v1_1"] stm32h743 = ["stm32h7", "stm32h7xx-hal/stm32h743", "hrtim_v1_1"] #stm32h745 = ["stm32h7", "stm32h7xx-hal/stm32h745", "hrtim_v1_1"] -#stm32h747 = ["stm32h7", "stm32h7xx-hal/stm32h747", "hrtim_v1_1"] +stm32h747cm7 = ["stm32h7", "stm32h7xx-hal/stm32h747cm7", "hrtim_v1_1"] stm32h750 = ["stm32h7", "stm32h7xx-hal/stm32h750", "hrtim_v1_1"] stm32h753 = ["stm32h7", "stm32h7xx-hal/stm32h753", "hrtim_v1_1"] #stm32h755 = ["stm32h7", "stm32h7xx-hal/stm32h755", "hrtim_v1_1"] From d103db2356dbe5bc67a23f2feebc84f6bb0fcd60 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sun, 15 Dec 2024 21:16:43 +0100 Subject: [PATCH 24/25] H7 does not have DLL --- src/control.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/control.rs b/src/control.rs index edff930..d5cc594 100644 --- a/src/control.rs +++ b/src/control.rs @@ -77,6 +77,7 @@ impl HrControltExt for HRTIM_COMMON { rcc.enable().reset(); // Start calibration procedure + #[cfg(not(feature = "stm32h7"))] common .dllcr() .write(|w| w.cal().set_bit().calen().clear_bit()); @@ -173,6 +174,7 @@ impl HrTimOngoingCalibration { // Enable periodic calibration // with f_hrtim at 170MHz, these settings leads to // a period of about 6.2ms + #[cfg(not(feature = "stm32h7"))] common .dllcr() .modify(|_r, w| w.calrte().bits(0b00).cal().set_bit().calen().clear_bit()); @@ -215,9 +217,12 @@ impl HrTimOngoingCalibration { } pub fn wait_for_calibration(self) -> (HrTimCalibrated, FaultInputs, EevInputs) { - let common = unsafe { &*HRTIM_COMMON::ptr() }; - while common.isr().read().dllrdy().bit_is_clear() { - // Wait until ready + #[cfg(not(feature = "stm32h7"))] + { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + while common.isr().read().dllrdy().bit_is_clear() { + // Wait until ready + } } // Calibration is now done, it is safe to continue From c0aa71ddd727ac74ad660bf0ace21e02d92a65cc Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Thu, 1 May 2025 11:47:46 +0200 Subject: [PATCH 25/25] Dont depend on hal (#6) * Dont depend on hal * Remove connect pins * Move out device specific things to hals * update pac * Update CI * fixes * Fix errors for f334 and h7 * Update examples * clippy --- .github/workflows/ci.yml | 4 +- Cargo.toml | 66 ++++------- examples/stm32f3/hrtim.rs | 107 ----------------- examples/stm32g4/adc-trigger.rs | 5 +- examples/stm32g4/capture-dma.rs | 2 +- examples/stm32g4/capture.rs | 2 +- examples/stm32g4/eev-comp.rs | 7 +- examples/stm32g4/eev.rs | 7 +- examples/stm32g4/flt-comp.rs | 25 +--- examples/stm32g4/flt.rs | 9 +- examples/stm32g4/hrtim.rs | 11 +- examples/stm32g4/master.rs | 8 +- examples/stm32h7/hrtim.rs | 109 ------------------ src/adc_trigger.rs | 78 +++++++++++-- src/capture.rs | 26 +---- src/compare_register.rs | 15 +-- src/control.rs | 196 +++++--------------------------- src/external_event.rs | 66 +---------- src/fault.rs | 89 +++++---------- src/lib.rs | 172 +++++++++++++--------------- src/output.rs | 176 ++-------------------------- src/stm32f3.rs | 17 --- src/stm32g4.rs | 20 ---- src/stm32h7.rs | 10 -- src/timer.rs | 15 +-- 25 files changed, 282 insertions(+), 960 deletions(-) delete mode 100644 examples/stm32f3/hrtim.rs delete mode 100644 examples/stm32h7/hrtim.rs delete mode 100644 src/stm32f3.rs delete mode 100644 src/stm32g4.rs delete mode 100644 src/stm32h7.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2e87e9d..aa0f3d8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,9 +15,7 @@ jobs: rust: - stable device: - - stm32f334x4 - - stm32f334x6 - - stm32f334x8 + - stm32f334 - stm32h742 - stm32h743 diff --git a/Cargo.toml b/Cargo.toml index 00e433c..35454e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,21 +3,17 @@ name = "stm32-hrtim" version = "0.1.0" edition = "2021" -[dependencies] +[patch.crates-io] +stm32-hrtim = { path = "." } + +[patch."https://github.com/usbalbin/stm32-hrtim"] +stm32-hrtim = { path = "." } +[dependencies] stm32f3 = { git = "https://github.com/stm32-rs/stm32-rs-nightlies", optional = true } -stm32h7 = { git = "https://github.com/stm32-rs/stm32-rs-nightlies", fatures = ["critical-section"], optional = true } -#stm32g4 = { git = "", optional = true } - -#stm32f3xx-hal = { version = "0.10.0", optional = true } -stm32f3xx-hal = { git = "https://github.com/usbalbin/stm32f3xx-hal", branch = "update_for_new_pac", optional = true } -#stm32h7xx-hal = { version = "0.16.0", optional = true } -stm32h7xx-hal = { git = "https://github.com/usbalbin/stm32h7xx-hal", branch = "update_for_new_pac", optional = true } -#stm32h7xx-hal = { path = "../stm32h7xx-hal", optional = true } - -#stm32g4xx-hal = { version = "0.0.1", optional = true } -stm32g4xx-hal = { git = "https://github.com/stm32-rs/stm32g4xx-hal", branch = "staged-pac", optional = true } -#stm32g4xx-hal = { path = "../stm32g4xx-hal", optional = true } +stm32h7 = { git = "https://github.com/stm32-rs/stm32-rs-nightlies", features = ["critical-section"], optional = true } +stm32g4 = { version = "0.22.0", package = "stm32g4-staging", optional = true } + defmt = { version = "0.3.10", optional = true } fugit = "0.3.7" @@ -26,6 +22,7 @@ cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } defmt-rtt = "0.4.0" cortex-m-rt = "0.7.2" panic-probe = { version = "0.3.0", features = ["print-defmt"] } +stm32g4xx-hal = { git = "https://github.com/usbalbin/stm32g4xx-hal", branch = "hrtim", features = ["defmt", "hrtim"] } [features] default = [] @@ -38,30 +35,20 @@ stm32f3 = ["stm32f3/stm32f3x4"] stm32h7 = ["dep:stm32h7"] stm32g4 = [] -stm32f334x4 = ["stm32f3", "stm32f3xx-hal/stm32f334x4", "hrtim_v1"] -stm32f334x6 = ["stm32f3", "stm32f3xx-hal/stm32f334x6", "hrtim_v1"] -stm32f334x8 = ["stm32f3", "stm32f3xx-hal/stm32f334x8", "hrtim_v1"] - -stm32h742 = ["stm32h7", "stm32h7xx-hal/stm32h742", "hrtim_v1_1"] -stm32h743 = ["stm32h7", "stm32h7xx-hal/stm32h743", "hrtim_v1_1"] -#stm32h745 = ["stm32h7", "stm32h7xx-hal/stm32h745", "hrtim_v1_1"] -stm32h747cm7 = ["stm32h7", "stm32h7xx-hal/stm32h747cm7", "hrtim_v1_1"] -stm32h750 = ["stm32h7", "stm32h7xx-hal/stm32h750", "hrtim_v1_1"] -stm32h753 = ["stm32h7", "stm32h7xx-hal/stm32h753", "hrtim_v1_1"] -#stm32h755 = ["stm32h7", "stm32h7xx-hal/stm32h755", "hrtim_v1_1"] -#stm32h757 = ["stm32h7", "stm32h7xx-hal/stm32h757", "hrtim_v1_1"] - -stm32g474 = ["stm32g4", "stm32g4xx-hal/stm32g474", "hrtim_v2"] -stm32g484 = ["stm32g4", "stm32g4xx-hal/stm32g484", "hrtim_v2"] -defmt = ["dep:defmt", "fugit/defmt"] +stm32f334 = ["stm32f3/stm32f3x4", "hrtim_v1"] -# F3 - -[[example]] -name = "stm32f3" -required-features = ["stm32f3"] -path = "examples/stm32f3/hrtim.rs" +stm32h742 = ["stm32h7/stm32h742", "hrtim_v1_1"] +stm32h743 = ["stm32h7/stm32h743", "hrtim_v1_1"] +#stm32h745 = ["stm32h7/stm32h745", "hrtim_v1_1"] +stm32h747cm7 = ["stm32h7/stm32h747cm7", "hrtim_v1_1"] +stm32h750 = ["stm32h7/stm32h750", "hrtim_v1_1"] +stm32h753 = ["stm32h7/stm32h753", "hrtim_v1_1"] +#stm32h755 = ["stm32h7/stm32h755", "hrtim_v1_1"] +#stm32h757 = ["stm32h7/stm32h757", "hrtim_v1_1"] +stm32g474 = ["stm32g4/stm32g474", "stm32g4xx-hal/stm32g474", "hrtim_v2"] +stm32g484 = ["stm32g4/stm32g484", "stm32g4xx-hal/stm32g484", "hrtim_v2"] +defmt = ["dep:defmt", "fugit/defmt"] # G4 @@ -108,11 +95,4 @@ path = "examples/stm32g4/hrtim.rs" [[example]] name = "stm32g4-master" required-features = ["stm32g4"] -path = "examples/stm32g4/master.rs" - -# H7 - -[[example]] -name = "stm32h7" -required-features = ["stm32h7"] -path = "examples/stm32h7/hrtim.rs" \ No newline at end of file +path = "examples/stm32g4/master.rs" \ No newline at end of file diff --git a/examples/stm32f3/hrtim.rs b/examples/stm32f3/hrtim.rs deleted file mode 100644 index 61d52cb..0000000 --- a/examples/stm32f3/hrtim.rs +++ /dev/null @@ -1,107 +0,0 @@ -#![no_std] -#![no_main] - -use cortex_m_rt::entry; -use panic_probe as _; -use stm32_hrtim::{ - compare_register::HrCompareRegister, control::HrControltExt, output::HrOutput, timer::HrTimer, - HrParts, HrPwmAdvExt, Pscl4, -}; -use stm32f3xx_hal::{ - delay::Delay, - flash::FlashExt as _, - gpio::GpioExt, - pac::{CorePeripherals, Peripherals}, - prelude::{_embedded_hal_blocking_delay_DelayMs, _stm32f3xx_hal_time_rate_Extensions}, - rcc::RccExt, -}; - -#[entry] -fn main() -> ! { - defmt::info!("Initializing..."); - - let dp = Peripherals::take().expect("cannot take peripherals"); - let cp = CorePeripherals::take().expect("cannot take core"); - - let mut flash = dp.FLASH.constrain(); - let mut rcc = dp.RCC.constrain(); - let mut gpioa = dp.GPIOA.split(&mut rcc.ahb); - - // Set system frequency to 64MHz using PLL, PLLCLKx2 will thus be 128MHz which - // feeds into the HRTIM. This and the HRTIM's DLL would lead to an effective - // HRTIM frequency of 128MHz * 32 = 4.096GHz... - let clocks = rcc - .cfgr - .sysclk(64_u32.MHz()) - .use_pll() - .freeze(&mut flash.acr); - - let mut delay = Delay::new(cp.SYST, clocks); - - // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 1024MHz - // With max the max period set, this would be 1024MHz/2^16 ~= 15.6kHz... - let prescaler = Pscl4; - - let pin_a = gpioa.pa8; - let pin_b = gpioa.pa9; - - // . . . . - // . 30% . . . - // ---- . .---- . - //out1 | | . | | . - // | | . | | . - // -------- ---------------------------- -------------------- - // . .---- . .---- - //out2 . | | . | | - // . | | . | | - // ------------------------ ---------------------------- ---- - // . . . . - // . . . . - let (hr_control, ..) = dp - .HRTIM_COMMON - .hr_control(&clocks, &mut rcc.apb2) - .wait_for_calibration(); - let mut hr_control = hr_control.constrain(); - - let HrParts { - mut timer, - mut cr1, - out: (mut out1, mut out2), - .. - } = dp - .HRTIM_TIMA - .pwm_advanced((pin_a, pin_b)) - .prescaler(prescaler) - .period(0xFFFF) - .push_pull_mode(true) // Set push pull mode, out1 and out2 are - // alternated every period with one being - // inactive and the other getting to output its wave form - // as normal - .finalize( - &mut hr_control, - &mut gpioa.moder, - &mut gpioa.otyper, - &mut gpioa.afrh, - ); - - out1.enable_rst_event(&cr1); // Set low on compare match with cr1 - out2.enable_rst_event(&cr1); - - out1.enable_set_event(&timer); // Set high at new period - out2.enable_set_event(&timer); - - out1.enable(); - out2.enable(); - - loop { - // Step frequency from 15.6kHz to about 156kHz(half of that when only looking at one pin) - for i in 1..=10 { - let new_period = u16::MAX / i; - - cr1.set_duty(new_period / 3); - timer.set_period(new_period); - - delay.delay_ms(500_u16); - } - } -} diff --git a/examples/stm32g4/adc-trigger.rs b/examples/stm32g4/adc-trigger.rs index 3150ec6..05505c7 100644 --- a/examples/stm32g4/adc-trigger.rs +++ b/examples/stm32g4/adc-trigger.rs @@ -5,14 +5,15 @@ use cortex_m_rt::entry; use panic_probe as _; use stm32_hrtim::{ - compare_register::HrCompareRegister, control::HrControltExt, output::HrOutput, timer::HrTimer, - HrParts, HrPwmAdvExt, Pscl4, + compare_register::HrCompareRegister, output::HrOutput, timer::HrTimer, HrParts, HrPwmAdvExt, + Pscl4, }; use stm32g4xx_hal::{ adc::{self, AdcClaim, ClockSource, Temperature, Vref}, delay::SYSTDelayExt, dma::{self, channel::DMAExt, config::DmaConfig, TransferExt}, gpio::GpioExt, + hrtim::{HrControltExt, HrPwmBuilderExt}, pwr::PwrExt, rcc::{self, RccExt}, stm32::{CorePeripherals, Peripherals}, diff --git a/examples/stm32g4/capture-dma.rs b/examples/stm32g4/capture-dma.rs index 9ea1341..bd55126 100644 --- a/examples/stm32g4/capture-dma.rs +++ b/examples/stm32g4/capture-dma.rs @@ -7,7 +7,6 @@ use panic_probe as _; use stm32_hrtim::{ capture, compare_register::HrCompareRegister, - control::HrControltExt, external_event::{self, ToExternalEventSource}, output::HrOutput, timer::{HrSlaveTimerCpt, HrTimer, TimerSplitCapture}, @@ -16,6 +15,7 @@ use stm32_hrtim::{ use stm32g4xx_hal::{ dma::{channel::DMAExt, config::DmaConfig, TransferExt}, gpio::GpioExt, + hrtim::{external_event::EevInputExt, HrControltExt, HrPwmBuilderExt}, pwr::PwrExt, rcc::{self, RccExt}, stm32::Peripherals, diff --git a/examples/stm32g4/capture.rs b/examples/stm32g4/capture.rs index 522aaa2..85c1b26 100644 --- a/examples/stm32g4/capture.rs +++ b/examples/stm32g4/capture.rs @@ -7,7 +7,6 @@ use panic_probe as _; use stm32_hrtim::{ capture::HrCapture, compare_register::HrCompareRegister, - control::HrControltExt, external_event::{self, ToExternalEventSource}, output::HrOutput, timer::{HrSlaveTimerCpt, HrTimer}, @@ -15,6 +14,7 @@ use stm32_hrtim::{ }; use stm32g4xx_hal::{ gpio::GpioExt, + hrtim::{external_event::EevInputExt, HrControltExt, HrPwmBuilderExt}, pwr::PwrExt, rcc::{self, RccExt}, stm32::Peripherals, diff --git a/examples/stm32g4/eev-comp.rs b/examples/stm32g4/eev-comp.rs index a0804ee..ab196f9 100644 --- a/examples/stm32g4/eev-comp.rs +++ b/examples/stm32g4/eev-comp.rs @@ -7,19 +7,18 @@ use cortex_m_rt::entry; use panic_probe as _; use stm32_hrtim::{ compare_register::HrCompareRegister, - control::HrControltExt, external_event::{self, ToExternalEventSource}, output::HrOutput, timer::HrTimer, timer_eev_cfg::{EevCfg, EevCfgs}, - HrParts, HrPwmAdvExt, Pscl4, + HrParts, HrPwmAdvExt, Polarity, Pscl4, }; use stm32g4xx_hal::{ comparator::{self, ComparatorExt, ComparatorSplit}, dac::{self, DacExt, DacOut}, delay::SYSTDelayExt, gpio::{GpioExt, SignalEdge}, - pwm, + hrtim::{external_event::EevInputExt, HrControltExt, HrPwmBuilderExt}, pwr::PwrExt, rcc::{self, RccExt}, stm32::{CorePeripherals, Peripherals}, @@ -80,7 +79,7 @@ fn main() -> ! { .eev_input4 .bind(&comp1) .edge_or_polarity(external_event::EdgeOrPolarity::Polarity( - pwm::Polarity::ActiveHigh, + Polarity::ActiveHigh, )) .finalize(&mut hr_control); diff --git a/examples/stm32g4/eev.rs b/examples/stm32g4/eev.rs index aa245ba..0cf45e0 100644 --- a/examples/stm32g4/eev.rs +++ b/examples/stm32g4/eev.rs @@ -7,16 +7,15 @@ use cortex_m_rt::entry; use panic_probe as _; use stm32_hrtim::{ compare_register::HrCompareRegister, - control::HrControltExt, external_event::{self, ToExternalEventSource}, output::HrOutput, timer::HrTimer, timer_eev_cfg::EevCfgs, - HrParts, HrPwmAdvExt, Pscl4, + HrParts, HrPwmAdvExt, Polarity, Pscl4, }; use stm32g4xx_hal::{ gpio::GpioExt, - pwm, + hrtim::{external_event::EevInputExt, HrControltExt, HrPwmBuilderExt}, pwr::PwrExt, rcc::{self, RccExt}, stm32::Peripherals, @@ -50,7 +49,7 @@ fn main() -> ! { .eev_input3 .bind(gpiob.pb7.into_pull_down_input()) .edge_or_polarity(external_event::EdgeOrPolarity::Polarity( - pwm::Polarity::ActiveHigh, + Polarity::ActiveHigh, )) .finalize(&mut hr_control); diff --git a/examples/stm32g4/flt-comp.rs b/examples/stm32g4/flt-comp.rs index 4baa222..b0287b5 100644 --- a/examples/stm32g4/flt-comp.rs +++ b/examples/stm32g4/flt-comp.rs @@ -7,23 +7,10 @@ use cortex_m_rt::entry; use fugit::ExtU32 as _; use panic_probe as _; use stm32_hrtim::{ - compare_register::HrCompareRegister, - control::HrControltExt, - fault::{FaultAction, FaultMonitor}, - output::HrOutput, - timer::HrTimer, - HrParts, HrPwmAdvExt, Pscl4, + compare_register::HrCompareRegister, fault::{FaultAction, FaultMonitor}, output::HrOutput, timer::HrTimer, HrParts, HrPwmAdvExt, Polarity, Pscl4 }; use stm32g4xx_hal::{ - self as hal, - adc::AdcClaim, - comparator::{self, ComparatorExt, ComparatorSplit}, - dac::{Dac3IntSig1, DacExt, DacOut}, - delay::{DelayExt as _, SYSTDelayExt}, - gpio::GpioExt, - pwr::PwrExt, - rcc::{self, RccExt}, - stm32::{CorePeripherals, Peripherals}, + self as hal, adc::AdcClaim, comparator::{self, ComparatorExt, ComparatorSplit}, dac::{Dac3IntSig1, DacExt, DacOut}, delay::{DelayExt as _, SYSTDelayExt}, gpio::GpioExt, hrtim::{fault::FaultInput, HrControltExt, HrPwmBuilderExt}, pwr::PwrExt, rcc::{self, RccExt}, stm32::{CorePeripherals, Peripherals} }; #[entry] @@ -85,8 +72,8 @@ fn main() -> ! { let fault_source5 = flt_inputs .fault_input5 - .bind_comp(&comp3) - .polarity(hal::pwm::Polarity::ActiveHigh) + .bind(comp3) + .polarity(Polarity::ActiveHigh) .finalize(&mut hr_control); // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 960MHz @@ -137,9 +124,9 @@ fn main() -> ! { for _ in 0..5 { delay.delay(500_u32.millis()); defmt::info!( - "State: {:?}, comp: {}, is_fault_active: {}, pc1: {}", + "State: {:?}, comp: {}, is_fault_active: _, pc1: {}", out1.get_state(), - comp3.output(), + //comp3.output(), // TODO hr_control.fault_5.is_fault_active(), adc1.convert(&pc1, hal::adc::config::SampleTime::Cycles_92_5) ); diff --git a/examples/stm32g4/flt.rs b/examples/stm32g4/flt.rs index 991cdb4..3deff42 100644 --- a/examples/stm32g4/flt.rs +++ b/examples/stm32g4/flt.rs @@ -7,16 +7,15 @@ use cortex_m_rt::entry; use panic_probe as _; use stm32_hrtim::{ compare_register::HrCompareRegister, - control::HrControltExt, fault::{FaultAction, FaultMonitor}, output::HrOutput, timer::HrTimer, - HrParts, HrPwmAdvExt, Pscl4, + HrParts, HrPwmAdvExt, Polarity, Pscl4, }; use stm32g4xx_hal::{ - self as hal, delay::{DelayExt, SYSTDelayExt}, gpio::GpioExt, + hrtim::{fault::FaultInput, HrControltExt, HrPwmBuilderExt}, pwr::PwrExt, rcc::{self, RccExt}, stm32::{CorePeripherals, Peripherals}, @@ -50,8 +49,8 @@ fn main() -> ! { let fault_source3 = flt_inputs .fault_input3 - .bind_pin(gpiob.pb10.into_pull_down_input()) - .polarity(hal::pwm::Polarity::ActiveHigh) + .bind(gpiob.pb10.into_pull_down_input().into_alternate()) + .polarity(Polarity::ActiveHigh) .finalize(&mut hr_control); // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 1.2GHz diff --git a/examples/stm32g4/hrtim.rs b/examples/stm32g4/hrtim.rs index df1081c..8187ef3 100644 --- a/examples/stm32g4/hrtim.rs +++ b/examples/stm32g4/hrtim.rs @@ -4,16 +4,11 @@ use cortex_m_rt::entry; use panic_probe as _; use stm32_hrtim::{ - compare_register::HrCompareRegister, control::HrControltExt, output::HrOutput, timer::HrTimer, - HrParts, HrPwmAdvExt, Pscl4, + compare_register::HrCompareRegister, output::HrOutput, timer::HrTimer, HrParts, HrPwmAdvExt, + Pscl4, }; use stm32g4xx_hal::{ - delay::{DelayExt, SYSTDelayExt}, - gpio::GpioExt, - pwr::PwrExt, - rcc::{self, RccExt}, - stm32::{CorePeripherals, Peripherals}, - time::ExtU32, + delay::{DelayExt, SYSTDelayExt}, gpio::GpioExt, hrtim::{HrControltExt, HrPwmBuilderExt}, pwr::PwrExt, rcc::{self, RccExt}, stm32::{CorePeripherals, Peripherals}, time::ExtU32 }; #[entry] diff --git a/examples/stm32g4/master.rs b/examples/stm32g4/master.rs index 2edef09..8166507 100644 --- a/examples/stm32g4/master.rs +++ b/examples/stm32g4/master.rs @@ -5,18 +5,12 @@ use cortex_m_rt::entry; use panic_probe as _; use stm32_hrtim::{ compare_register::HrCompareRegister, - control::HrControltExt, output::HrOutput, timer::{HrSlaveTimer, HrTimer}, HrParts, HrPwmAdvExt, HrTimerMode, MasterPreloadSource, PreloadSource, Pscl4, }; use stm32g4xx_hal::{ - delay::{DelayExt, SYSTDelayExt}, - gpio::GpioExt, - pwr::PwrExt, - rcc::{self, RccExt}, - stm32::{CorePeripherals, Peripherals}, - time::ExtU32, + delay::{DelayExt, SYSTDelayExt}, gpio::GpioExt, hrtim::{HrControltExt, HrPwmBuilderExt}, pwr::PwrExt, rcc::{self, RccExt}, stm32::{CorePeripherals, Peripherals}, time::ExtU32 }; #[entry] diff --git a/examples/stm32h7/hrtim.rs b/examples/stm32h7/hrtim.rs deleted file mode 100644 index f117e91..0000000 --- a/examples/stm32h7/hrtim.rs +++ /dev/null @@ -1,109 +0,0 @@ -#![no_std] -#![no_main] - -use cortex_m_rt::entry; -use panic_probe as _; -use stm32_hrtim::{ - compare_register::HrCompareRegister, control::HrControltExt, output::HrOutput, timer::HrTimer, - HrParts, HrPwmAdvExt, Pscl1, -}; -use stm32h7xx_hal::{ - delay::DelayExt, - gpio::GpioExt, - prelude::_embedded_hal_blocking_delay_DelayMs, - pwr::PwrExt, - rcc::RccExt, - stm32::{CorePeripherals, Peripherals}, -}; - -use fugit::RateExtU32 as _; - -#[entry] -fn main() -> ! { - defmt::info!("Initializing..."); - - let dp = Peripherals::take().expect("cannot take peripherals"); - let cp = CorePeripherals::take().expect("cannot take core"); - - // Constrain and Freeze power - let pwr = dp.PWR.constrain(); - let pwrcfg = pwr.freeze(); - - // Constrain and Freeze clock - let rcc = dp.RCC.constrain(); - - // With a sys_ck of 240MHz and d1cpre of 1 if the HRTIM will be fed by 240MHz/1 = 240MHz - // since HRTIMSEL is set to take the HRTIM's clock directly from the core clock. The - // stm32h7 devices' HRTIM does not have a DLL, also leading to an effective HRTIM - // frequency of 240MHz... - let ccdr = rcc.sys_ck(240.MHz()).freeze(pwrcfg, &dp.SYSCFG); - - // Acquire the GPIO peripherals. This also enables the clock for - // the GPIOs in the RCC register. - let gpioc = dp.GPIOC.split(ccdr.peripheral.GPIOC); - - // Get the delay provider. - let mut delay = cp.SYST.delay(ccdr.clocks); - - // ...with a prescaler of 1 this gives us a HrTimer with a tick rate of 240MHz - // With max the max period set, this would be 240MHz/2^16 ~= 3.7kHz... - let prescaler = Pscl1; - - let pin_a = gpioc.pc6.into_input(); - let pin_b = gpioc.pc7.into_input(); - - // . . . . - // . 30% . . . - // ---- . .---- . - //out1 | | . | | . - // | | . | | . - // -------- ---------------------------- -------------------- - // . .---- . .---- - //out2 . | | . | | - // . | | . | | - // ------------------------ ---------------------------- ---- - // . . . . - // . . . . - let (hr_control, ..) = dp - .HRTIM_COMMON - .hr_control(&ccdr.clocks, ccdr.peripheral.HRTIM) - .wait_for_calibration(); - let mut hr_control = hr_control.constrain(); - - let HrParts { - mut timer, - mut cr1, - out: (mut out1, mut out2), - .. - } = dp - .HRTIM_TIMA - .pwm_advanced((pin_a, pin_b)) - .prescaler(prescaler) - .period(0xFFFF) - .push_pull_mode(true) // Set push pull mode, out1 and out2 are - // alternated every period with one being - // inactive and the other getting to output its wave form - // as normal - .finalize(&mut hr_control); - - out1.enable_rst_event(&cr1); // Set low on compare match with cr1 - out2.enable_rst_event(&cr1); - - out1.enable_set_event(&timer); // Set high at new period - out2.enable_set_event(&timer); - - out1.enable(); - out2.enable(); - - loop { - // Step frequency from 3.7kHz to about 36.6kHz(half of that when only looking at one pin) - for i in 1..10 { - let new_period = u16::MAX / i; - - cr1.set_duty(new_period / 3); - timer.set_period(new_period); - - delay.delay_ms(500_u16); - } - } -} diff --git a/src/adc_trigger.rs b/src/adc_trigger.rs index 133a42b..410e14e 100644 --- a/src/adc_trigger.rs +++ b/src/adc_trigger.rs @@ -1,27 +1,81 @@ +#[cfg(feature = "hrtim_v2")] +use crate::pac; use core::marker::PhantomData; -#[cfg(feature = "stm32g4")] -pub trait Adc13Trigger { +/// Handle to timers reset/roll-over event +pub struct TimerReset(pub(crate) PhantomData); + +/// Handle to timers period event +pub struct TimerPeriod(pub(crate) PhantomData); + +#[cfg(feature = "hrtim_v2")] +macro_rules! impl_adc1234_trigger { + ($($t:ident: [$trait_:ident, $adcXr:ident]),*) => {$( + #[non_exhaustive] + pub struct $t; + + impl $t { + pub fn enable_source(&mut self, _trigger: &T) { + let common = unsafe { &*pac::HRTIM_COMMON::ptr() }; + unsafe { + common.$adcXr().modify(|r, w| w.bits(r.bits() | T::BITS)); + } + } + } + )*} +} + +#[cfg(feature = "hrtim_v2")] +macro_rules! impl_adc5678910_trigger { + ($($t:ident: [$trait_:ident, $adcXtrg:ident]),*) => {$( + #[non_exhaustive] + pub struct $t; + + impl $t { + pub fn enable_source(&mut self, _trigger: &T) { + let common = unsafe { &*pac::HRTIM_COMMON::ptr() }; + common + .adcer() + .modify(|_r, w| unsafe { w.$adcXtrg().bits(T::BITS as u8) }); + } + } + )*} +} + +#[cfg(feature = "hrtim_v2")] +pub trait AdcTrigger13 { const BITS: u32; } -#[cfg(feature = "stm32g4")] -pub trait Adc24Trigger { +#[cfg(feature = "hrtim_v2")] +pub trait AdcTrigger24 { const BITS: u32; } -#[cfg(feature = "stm32g4")] -pub trait Adc579Trigger { +#[cfg(feature = "hrtim_v2")] +pub trait AdcTrigger579 { const BITS: u32; } -#[cfg(feature = "stm32g4")] -pub trait Adc6810Trigger { +#[cfg(feature = "hrtim_v2")] +pub trait AdcTrigger6810 { const BITS: u32; } -/// Handle to timers reset/roll-over event -pub struct TimerReset(pub(crate) PhantomData); +#[cfg(feature = "hrtim_v2")] +impl_adc1234_trigger! { + AdcTrigger1: [AdcTrigger13, adc1r], + AdcTrigger2: [AdcTrigger24, adc2r], + AdcTrigger3: [AdcTrigger13, adc3r], + AdcTrigger4: [AdcTrigger24, adc4r] +} -/// Handle to timers period event -pub struct TimerPeriod(pub(crate) PhantomData); +#[cfg(feature = "hrtim_v2")] +impl_adc5678910_trigger! { + AdcTrigger5: [AdcTrigger579, adc5trg], + AdcTrigger6: [AdcTrigger6810, adc6trg], + AdcTrigger7: [AdcTrigger579, adc7trg], + AdcTrigger8: [AdcTrigger6810, adc8trg], + AdcTrigger9: [AdcTrigger579, adc9trg], + AdcTrigger10: [AdcTrigger6810, adc10trg] +} diff --git a/src/capture.rs b/src/capture.rs index 7936295..1e8e469 100644 --- a/src/capture.rs +++ b/src/capture.rs @@ -1,16 +1,9 @@ -use crate::stm32; - use super::timer; -#[cfg(feature = "stm32g4")] -use crate::hal::dma::PeripheralToMemory; -#[cfg(feature = "stm32g4")] -use crate::mcu::DmaMuxResources; - -use core::marker::PhantomData; #[cfg(feature = "hrtim_v2")] -use stm32::HRTIM_TIMF; -use stm32::{HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME}; +use crate::pac::HRTIM_TIMF; +use crate::pac::{HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME}; +use core::marker::PhantomData; pub struct Ch1; pub struct Ch2; @@ -258,19 +251,6 @@ macro_rules! impl_capture { tim.isr().read().$cptX().bit() } } - - #[cfg(feature = "stm32g4")] - unsafe impl crate::hal::dma::traits::TargetAddress for HrCapt<$TIMX, PSCL, $CH, Dma> { - #[inline(always)] - fn address(&self) -> u32 { - let tim = unsafe { &*$TIMX::ptr() }; - &tim.$cptXr() as *const _ as u32 - } - - type MemSize = u32; - - const REQUEST_LINE: Option = Some(DmaMuxResources::$TIMX as u8); - } }; } diff --git a/src/compare_register.rs b/src/compare_register.rs index c49f8a0..da938e1 100644 --- a/src/compare_register.rs +++ b/src/compare_register.rs @@ -1,8 +1,8 @@ use core::marker::PhantomData; #[cfg(feature = "hrtim_v2")] -use crate::stm32::HRTIM_TIMF; -use crate::stm32::{HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME}; +use crate::pac::HRTIM_TIMF; +use crate::pac::{HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME}; pub trait HrCompareRegister { fn get_duty(&self) -> u16; @@ -15,13 +15,10 @@ pub struct HrCr3(PhantomData<(TIM, PSCL)>); pub struct HrCr4(PhantomData<(TIM, PSCL)>); #[cfg(feature = "stm32g4")] -use super::adc_trigger::Adc13Trigger as Adc13; -#[cfg(feature = "stm32g4")] -use super::adc_trigger::Adc24Trigger as Adc24; -#[cfg(feature = "stm32g4")] -use super::adc_trigger::Adc579Trigger as Adc579; -#[cfg(feature = "stm32g4")] -use super::adc_trigger::Adc6810Trigger as Adc6810; +use super::adc_trigger::{ + AdcTrigger13 as Adc13, AdcTrigger24 as Adc24, AdcTrigger579 as Adc579, + AdcTrigger6810 as Adc6810, +}; macro_rules! hrtim_cr_helper { (HRTIM_MASTER: $cr_type:ident: diff --git a/src/control.rs b/src/control.rs index d5cc594..d33011a 100644 --- a/src/control.rs +++ b/src/control.rs @@ -1,81 +1,26 @@ #[cfg(feature = "hrtim_v2")] +use crate::adc_trigger; +#[cfg(feature = "hrtim_v2")] use crate::fault::FltMonitor6; use crate::fault::{ FltMonitor1, FltMonitor2, FltMonitor3, FltMonitor4, FltMonitor5, FltMonitorSys, }; -use crate::{hal, stm32}; - -#[cfg(feature = "stm32h7")] -use hal::rcc::ResetEnable as _; - -#[cfg(not(feature = "stm32h7"))] -use hal::rcc::{Enable, Reset}; - -use stm32::HRTIM_COMMON; +use crate::pac::HRTIM_COMMON; use super::{external_event::EevInputs, fault::FaultInputs}; -pub trait HrControltExt { - fn hr_control( - self, - #[cfg(feature = "stm32f3")] _clocks: &hal::rcc::Clocks, - #[cfg(feature = "stm32f3")] apb2: &mut hal::rcc::APB2, - - #[allow(unused_variables)] - #[cfg(feature = "stm32g4")] - rcc: &mut hal::rcc::Rcc, - - #[cfg(feature = "stm32h7")] _clocks: &hal::rcc::CoreClocks, - #[cfg(feature = "stm32h7")] rcc: hal::rcc::rec::Hrtim, - ) -> HrTimOngoingCalibration; -} - -impl HrControltExt for HRTIM_COMMON { - fn hr_control( - self, - #[cfg(feature = "stm32f3")] _clocks: &hal::rcc::Clocks, - #[cfg(feature = "stm32f3")] apb2: &mut hal::rcc::APB2, - +impl HrTimOngoingCalibration { + /// Look in the hal for an corresponding extension trait for `HRTIM_COMMON`. + /// + /// ..unless you are the one implementing the hal + /// + /// # Safety + /// The user is expected to have setup and enabled rcc clock to the peripheral + pub unsafe fn hr_control() -> HrTimOngoingCalibration { #[allow(unused_variables)] - #[cfg(feature = "stm32g4")] - rcc: &mut hal::rcc::Rcc, - - #[cfg(feature = "stm32h7")] _clocks: &hal::rcc::CoreClocks, - #[cfg(feature = "stm32h7")] rcc: hal::rcc::rec::Hrtim, - ) -> HrTimOngoingCalibration { let common = unsafe { &*HRTIM_COMMON::ptr() }; - let rcc = { - #[cfg(feature = "stm32g4")] - unsafe { - &*stm32::RCC::ptr() - } - - #[cfg(feature = "stm32f3")] - { - apb2 - } - - #[cfg(feature = "stm32h7")] - { - { - let rcc = unsafe { &*hal::stm32::RCC::ptr() }; - // Same clock source as CPU - rcc.cfgr().modify(|_, w| w.hrtimsel().c_ck()); - } - rcc - } - }; - - #[cfg(not(feature = "stm32h7"))] - ::enable(rcc); - #[cfg(not(feature = "stm32h7"))] - ::reset(rcc); - - #[cfg(feature = "stm32h7")] - rcc.enable().reset(); - // Start calibration procedure #[cfg(not(feature = "stm32h7"))] common @@ -288,25 +233,25 @@ impl HrTimCalibrated { fault_6: FltMonitor6, #[cfg(feature = "stm32g4")] - adc_trigger1: Adc1Trigger, + adc_trigger1: adc_trigger::AdcTrigger1, #[cfg(feature = "stm32g4")] - adc_trigger2: Adc2Trigger, + adc_trigger2: adc_trigger::AdcTrigger2, #[cfg(feature = "stm32g4")] - adc_trigger3: Adc3Trigger, + adc_trigger3: adc_trigger::AdcTrigger3, #[cfg(feature = "stm32g4")] - adc_trigger4: Adc4Trigger, + adc_trigger4: adc_trigger::AdcTrigger4, #[cfg(feature = "stm32g4")] - adc_trigger5: Adc5Trigger, + adc_trigger5: adc_trigger::AdcTrigger5, #[cfg(feature = "stm32g4")] - adc_trigger6: Adc6Trigger, + adc_trigger6: adc_trigger::AdcTrigger6, #[cfg(feature = "stm32g4")] - adc_trigger7: Adc7Trigger, + adc_trigger7: adc_trigger::AdcTrigger7, #[cfg(feature = "stm32g4")] - adc_trigger8: Adc8Trigger, + adc_trigger8: adc_trigger::AdcTrigger8, #[cfg(feature = "stm32g4")] - adc_trigger9: Adc9Trigger, + adc_trigger9: adc_trigger::AdcTrigger9, #[cfg(feature = "stm32g4")] - adc_trigger10: Adc10Trigger, + adc_trigger10: adc_trigger::AdcTrigger10, } } } @@ -338,107 +283,28 @@ pub struct HrPwmControl { pub fault_6: FltMonitor6, #[cfg(feature = "stm32g4")] - pub adc_trigger1: Adc1Trigger, + pub adc_trigger1: adc_trigger::AdcTrigger1, #[cfg(feature = "stm32g4")] - pub adc_trigger2: Adc2Trigger, + pub adc_trigger2: adc_trigger::AdcTrigger2, #[cfg(feature = "stm32g4")] - pub adc_trigger3: Adc3Trigger, + pub adc_trigger3: adc_trigger::AdcTrigger3, #[cfg(feature = "stm32g4")] - pub adc_trigger4: Adc4Trigger, + pub adc_trigger4: adc_trigger::AdcTrigger4, #[cfg(feature = "stm32g4")] - pub adc_trigger5: Adc5Trigger, + pub adc_trigger5: adc_trigger::AdcTrigger5, #[cfg(feature = "stm32g4")] - pub adc_trigger6: Adc6Trigger, + pub adc_trigger6: adc_trigger::AdcTrigger6, #[cfg(feature = "stm32g4")] - pub adc_trigger7: Adc7Trigger, + pub adc_trigger7: adc_trigger::AdcTrigger7, #[cfg(feature = "stm32g4")] - pub adc_trigger8: Adc8Trigger, + pub adc_trigger8: adc_trigger::AdcTrigger8, #[cfg(feature = "stm32g4")] - pub adc_trigger9: Adc9Trigger, + pub adc_trigger9: adc_trigger::AdcTrigger9, #[cfg(feature = "stm32g4")] - pub adc_trigger10: Adc10Trigger, + pub adc_trigger10: adc_trigger::AdcTrigger10, } -#[cfg(feature = "stm32g4")] -macro_rules! impl_adc1234_trigger { - ($($t:ident: [$trait_:ident, $adcXr:ident, $variant345:ident $(, $variant12:ident)*]),*) => {$( - #[non_exhaustive] - pub struct $t; - - impl $t { - pub fn enable_source(&mut self, _trigger: &T) { - let common = unsafe { &*HRTIM_COMMON::ptr() }; - unsafe { - common.$adcXr().modify(|r, w| w.bits(r.bits() | T::BITS)); - } - } - } - - $(impl From<&$t> for hal::adc::config::ExternalTrigger12 { - fn from(_val: &$t) -> Self { - hal::adc::config::ExternalTrigger12::$variant12 - } - })* - - impl From<&$t> for hal::adc::config::ExternalTrigger345 { - fn from(_val: &$t) -> Self { - hal::adc::config::ExternalTrigger345::$variant345 - } - } - )*} -} - -#[cfg(feature = "stm32g4")] -macro_rules! impl_adc5678910_trigger { - ($($t:ident: [$trait_:ident, $adcXtrg:ident, $variant345:ident, $variant12:ident]),*) => {$( - #[non_exhaustive] - pub struct $t; - - impl $t { - pub fn enable_source(&mut self, _trigger: &T) { - let common = unsafe { &*HRTIM_COMMON::ptr() }; - common - .adcer() - .modify(|_r, w| unsafe { w.$adcXtrg().bits(T::BITS as u8) }); - } - } - - impl From<&$t> for hal::adc::config::ExternalTrigger12 { - fn from(_val: &$t) -> Self { - hal::adc::config::ExternalTrigger12::$variant12 - } - } - - impl From<&$t> for hal::adc::config::ExternalTrigger345 { - fn from(_val: &$t) -> Self { - hal::adc::config::ExternalTrigger345::$variant345 - } - } - - )*} -} -#[cfg(feature = "stm32g4")] -impl_adc1234_trigger! {// reg adc345, adc12 - Adc1Trigger: [Adc13Trigger, adc1r, Hrtim_adc_trg_1, Hrtim_adc_trg_1], - Adc2Trigger: [Adc24Trigger, adc2r, Hrtim_adc_trg_2], - Adc3Trigger: [Adc13Trigger, adc3r, Hrtim_adc_trg_3, Hrtim_adc_trg_3], - Adc4Trigger: [Adc24Trigger, adc4r, Hrtim_adc_trg_4] -} - -#[cfg(feature = "stm32g4")] -impl_adc5678910_trigger! { - Adc5Trigger: [Adc579Trigger, adc5trg, Hrtim_adc_trg_5, Hrtim_adc_trg_5], - Adc6Trigger: [Adc6810Trigger, adc6trg, Hrtim_adc_trg_6, Hrtim_adc_trg_6], - Adc7Trigger: [Adc579Trigger, adc7trg, Hrtim_adc_trg_7, Hrtim_adc_trg_7], - Adc8Trigger: [Adc6810Trigger, adc8trg, Hrtim_adc_trg_8, Hrtim_adc_trg_8], - Adc9Trigger: [Adc579Trigger, adc9trg, Hrtim_adc_trg_9, Hrtim_adc_trg_9], - Adc10Trigger: [Adc6810Trigger, adc10trg, Hrtim_adc_trg_10, Hrtim_adc_trg_10] -} - -#[cfg(feature = "stm32g4")] -use super::adc_trigger::{Adc13Trigger, Adc24Trigger, Adc579Trigger, Adc6810Trigger}; - #[cfg(feature = "stm32g4")] pub enum AdcTriggerPostscaler { None = 0, diff --git a/src/external_event.rs b/src/external_event.rs index f344010..da63f52 100644 --- a/src/external_event.rs +++ b/src/external_event.rs @@ -1,15 +1,5 @@ -use crate::stm32; - -#[cfg(feature = "stm32g4")] -use crate::hal::comparator::{COMP1, COMP2, COMP3, COMP4, COMP5, COMP6, COMP7}; -#[cfg(feature = "stm32g4")] -use crate::hal::gpio::gpiob::{PB3, PB4, PB5, PB6, PB7, PB8, PB9}; -#[cfg(feature = "stm32g4")] -use crate::hal::gpio::gpioc::{PC11, PC12, PC5, PC6}; -#[cfg(feature = "stm32g4")] -use crate::hal::gpio::{self, AF13, AF3}; +use crate::pac::HRTIM_COMMON; use crate::Polarity; -use stm32::HRTIM_COMMON; use super::control::HrTimCalibrated; @@ -58,55 +48,6 @@ pub unsafe trait EevSrcBits: Sized { fn cfg(self) {} } -#[cfg(feature = "stm32g4")] -macro_rules! impl_eev_input { - ($($N:literal: COMP=[$compX:ident $(, ($compY:ident, $compY_src_bits:literal))*], PINS=[$(($pin:ident, $af:ident)),*])*) => {$( - $(unsafe impl EevSrcBits<$N> for $pin>{ - const SRC_BITS: u8 = 0b00; - fn cfg(self) { - self.into_alternate::<$af>(); - } - })* - - unsafe impl EevSrcBits<$N> for &crate::hal::comparator::Comparator<$compX, ED> - where ED: crate::hal::comparator::EnabledState - { - const SRC_BITS: u8 = 0b01; - } - - $( - unsafe impl EevSrcBits<$N> for &crate::hal::comparator::Comparator<$compY, ED> - where ED: crate::hal::comparator::EnabledState - { - const SRC_BITS: u8 = $compY_src_bits; - } - )* - - impl EevInput<$N> { - pub fn bind(self, src: SRC) -> SourceBuilder<$N, IS_FAST> - where SRC: EevSrcBits<$N> - { - src.cfg(); - unsafe { SourceBuilder::new(SRC::SRC_BITS) } - } - } - )*}; -} - -#[cfg(feature = "stm32g4")] -impl_eev_input! { - 1: COMP = [COMP2], PINS = [(PC12, AF3)] - 2: COMP = [COMP4], PINS = [(PC11, AF3)] - 3: COMP = [COMP6], PINS = [(PB7, AF13)] - 4: COMP = [COMP1, (COMP5, 0b10)], PINS = [(PB6, AF13)] - 5: COMP = [COMP3, (COMP7, 0b10)], PINS = [(PB9, AF13)] - 6: COMP = [COMP2, (COMP1, 0b10)], PINS = [(PB5, AF13)] - 7: COMP = [COMP4], PINS = [(PB4, AF13)] - 8: COMP = [COMP6, (COMP3, 0b10)], PINS = [(PB8, AF13)] - 9: COMP = [COMP5, (COMP4, 0b11)], PINS = [(PB3, AF13)] - 10: COMP = [COMP7], PINS = [(PC5, AF13), (PC6, AF3)] -} - #[derive()] pub enum EdgeOrPolarity { Edge(Edge), @@ -197,7 +138,10 @@ pub struct SourceBuilder { #[cfg(feature = "stm32g4")] impl SourceBuilder { - unsafe fn new(src_bits: u8) -> Self { + /// # Safety + /// Caller needs to ensure that src_bits is a valid bit pattern + /// for eeXsrc bits in eecr1/2 registers for the intended input + pub unsafe fn new(src_bits: u8) -> Self { Self { src_bits, edge_or_polarity_bits: 0, // Level sensitive diff --git a/src/fault.rs b/src/fault.rs index 6cd2cef..32abc24 100644 --- a/src/fault.rs +++ b/src/fault.rs @@ -1,18 +1,6 @@ -#[cfg(feature = "stm32g4")] +#[cfg(feature = "hrtim_v2")] use crate::control::HrPwmControl; -use crate::stm32; - -#[cfg(feature = "stm32g4")] -use crate::hal::comparator::{COMP1, COMP2, COMP3, COMP4, COMP5, COMP6}; -#[cfg(feature = "stm32g4")] -use crate::hal::gpio::{ - self, - gpioa::{PA12, PA15}, - gpiob::{PB0, PB10, PB11}, - gpioc::{PC10, PC7}, - AF13, AF3, -}; -use stm32::HRTIM_COMMON; +use crate::pac::HRTIM_COMMON; use super::control::HrPwmCtrl; @@ -64,7 +52,10 @@ pub struct SourceBuilder { #[cfg(feature = "stm32g4")] impl SourceBuilder { - unsafe fn new(input: I, src_bits: u8) -> Self { + /// # Safety + /// Caller needs to ensure that src_bits is a valid bit pattern + /// for fltXsrc bits in fltinr1/2 registers for the intended input + pub unsafe fn new(input: I, src_bits: u8) -> Self { SourceBuilder { _input: input, src_bits, @@ -74,15 +65,13 @@ impl SourceBuilder { } } -#[cfg(feature = "stm32g4")] +#[cfg(feature = "hrtim_v2")] macro_rules! impl_faults { ($( $input:ident => $source:ident: - PINS=[($pin:ident, $af:ident) $(,($pin_b:ident, $af_b:ident))*], - COMP=$compX:ident, $enable_bits:literal, + $enable_bits:literal, $fltinrZ:ident, $fltWsrc_0:ident, $fltWsrc_1:ident, $fltWp:ident, $fltWf:ident, $fltWe:ident, $fltWlck:ident, )+) => {$( - // This should NOT be Copy/Clone #[non_exhaustive] pub struct $input; @@ -91,30 +80,6 @@ macro_rules! impl_faults { #[derive(Copy, Clone)] pub struct $source; - impl $input { - pub fn bind_pin(self, pin: $pin>) -> SourceBuilder<$input> { - pin.into_alternate::<$af>(); - unsafe { SourceBuilder::new(self, 0b00) } - } - - $( - // TODO: Is there a nicer way to do this? - pub fn bind_pin_b(self, pin: $pin_b>) -> SourceBuilder<$input> { - pin.into_alternate::<$af_b>(); - unsafe { SourceBuilder::new(self, 0b00) } - } - )* - - #[cfg(feature = "stm32g4")] - pub fn bind_comp(self, _comp: &crate::hal::comparator::Comparator<$compX, crate::hal::comparator::Enabled>) -> SourceBuilder<$input> { - unsafe { SourceBuilder::new(self, 0b01) } - } - - /*pub fn bind_external(?) { - SourceBuilder::new(self, 0b10); - }*/ - } - impl SourceBuilder<$input> { pub fn finalize(self, _control: &mut HrPwmControl) -> $source { let SourceBuilder{ _input, src_bits, is_active_high, filter_bits } = self; @@ -158,45 +123,45 @@ macro_rules! impl_faults { )+} } -#[cfg(feature = "stm32g4")] +#[cfg(feature = "hrtim_v2")] impl_faults!( - FaultInput1 => FaultSource1: PINS=[(PA12, AF13)], COMP=COMP2, 0b000001, fltinr1, flt1src, flt1src_1, flt1p, flt1f, flt1e, flt1lck, - FaultInput2 => FaultSource2: PINS=[(PA15, AF13)], COMP=COMP4, 0b000010, fltinr1, flt2src, flt2src_1, flt2p, flt2f, flt2e, flt2lck, - FaultInput3 => FaultSource3: PINS=[(PB10, AF13)], COMP=COMP6, 0b000100, fltinr1, flt3src, flt3src_1, flt3p, flt3f, flt3e, flt3lck, - FaultInput4 => FaultSource4: PINS=[(PB11, AF13)], COMP=COMP1, 0b001000, fltinr1, flt4src, flt4src_1, flt4p, flt4f, flt4e, flt4lck, - FaultInput5 => FaultSource5: PINS=[(PB0, AF13), (PC7, AF3)], COMP=COMP3, 0b010000, fltinr2, flt5src, flt5src_1, flt5p, flt5f, flt5e, flt5lck, - FaultInput6 => FaultSource6: PINS=[(PC10, AF13)], COMP=COMP5, 0b100000, fltinr2, flt6src, flt6src_1, flt6p, flt6f, flt6e, flt6lck, + FaultInput1 => FaultSource1: 0b000001, fltinr1, flt1src, flt1src_1, flt1p, flt1f, flt1e, flt1lck, + FaultInput2 => FaultSource2: 0b000010, fltinr1, flt2src, flt2src_1, flt2p, flt2f, flt2e, flt2lck, + FaultInput3 => FaultSource3: 0b000100, fltinr1, flt3src, flt3src_1, flt3p, flt3f, flt3e, flt3lck, + FaultInput4 => FaultSource4: 0b001000, fltinr1, flt4src, flt4src_1, flt4p, flt4f, flt4e, flt4lck, + FaultInput5 => FaultSource5: 0b010000, fltinr2, flt5src, flt5src_1, flt5p, flt5f, flt5e, flt5lck, + FaultInput6 => FaultSource6: 0b100000, fltinr2, flt6src, flt6src_1, flt6p, flt6f, flt6e, flt6lck, ); pub struct FaultInputs { - #[cfg(feature = "stm32g4")] + #[cfg(feature = "hrtim_v2")] pub fault_input1: FaultInput1, - #[cfg(feature = "stm32g4")] + #[cfg(feature = "hrtim_v2")] pub fault_input2: FaultInput2, - #[cfg(feature = "stm32g4")] + #[cfg(feature = "hrtim_v2")] pub fault_input3: FaultInput3, - #[cfg(feature = "stm32g4")] + #[cfg(feature = "hrtim_v2")] pub fault_input4: FaultInput4, - #[cfg(feature = "stm32g4")] + #[cfg(feature = "hrtim_v2")] pub fault_input5: FaultInput5, - #[cfg(feature = "stm32g4")] + #[cfg(feature = "hrtim_v2")] pub fault_input6: FaultInput6, } impl FaultInputs { pub(crate) unsafe fn new() -> Self { FaultInputs { - #[cfg(feature = "stm32g4")] + #[cfg(feature = "hrtim_v2")] fault_input1: FaultInput1, - #[cfg(feature = "stm32g4")] + #[cfg(feature = "hrtim_v2")] fault_input2: FaultInput2, - #[cfg(feature = "stm32g4")] + #[cfg(feature = "hrtim_v2")] fault_input3: FaultInput3, - #[cfg(feature = "stm32g4")] + #[cfg(feature = "hrtim_v2")] fault_input4: FaultInput4, - #[cfg(feature = "stm32g4")] + #[cfg(feature = "hrtim_v2")] fault_input5: FaultInput5, - #[cfg(feature = "stm32g4")] + #[cfg(feature = "hrtim_v2")] fault_input6: FaultInput6, } } diff --git a/src/lib.rs b/src/lib.rs index e371a42..31d92ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,35 @@ #![no_std] +#[cfg(not(any( + feature = "stm32f334", + feature = "stm32h742", + feature = "stm32h743", + //feature = "stm32h745", + feature = "stm32h747cm7", + feature = "stm32h750", + feature = "stm32h753", + //feature = "stm32h755", + //feature = "stm32h757", + feature = "stm32g474", + feature = "stm32g484", +)))] +compile_error!( + "This crate requires one of the following features enabled: + stm32f334 + + stm32h742 + stm32h743 + #stm32h745 + stm32h747cm7 + stm32h750 + stm32h753 + #stm32h755 + #stm32h757 + + stm32g474 + stm32g484" +); + pub mod adc_trigger; pub mod capture; pub mod compare_register; @@ -12,31 +42,48 @@ pub mod output; pub mod timer; pub mod timer_eev_cfg; -#[cfg(feature = "stm32f3")] -#[path = "stm32f3.rs"] -mod mcu; +#[cfg(feature = "stm32f334")] +pub use stm32f3::stm32f3x4 as pac; -#[cfg(feature = "stm32h7")] -#[path = "stm32h7.rs"] -mod mcu; +#[cfg(feature = "stm32h742")] +pub use stm32h7::stm32h742 as pac; + +#[cfg(feature = "stm32h743")] +pub use stm32h7::stm32h743 as pac; + +//#[cfg(feature = "stm32h745")] +//pub use stm32h7::stm32h745 as pac; + +#[cfg(feature = "stm32h747cm7")] +pub use stm32h7::stm32h747cm7 as pac; + +#[cfg(feature = "stm32h750")] +pub use stm32h7::stm32h750 as pac; + +#[cfg(feature = "stm32h753")] +pub use stm32h7::stm32h753 as pac; + +//#[cfg(feature = "stm32h755")] +//pub use stm32h7::stm32h755 as pac; + +//#[cfg(feature = "stm32h757")] +//pub use stm32h7::stm32h757 as pac; -#[cfg(feature = "stm32g4")] -#[path = "stm32g4.rs"] -mod mcu; +#[cfg(feature = "stm32g474")] +pub use stm32g4::stm32g474 as pac; -pub use mcu::{hal, stm32, Polarity}; +#[cfg(feature = "stm32g484")] +pub use stm32g4::stm32g484 as pac; use core::marker::PhantomData; use core::mem::MaybeUninit; use crate::compare_register::{HrCr1, HrCr2, HrCr3, HrCr4}; use crate::fault::{FaultAction, FaultSource}; -#[cfg(feature = "hrtim_v2")] -use crate::stm32::HRTIM_TIMF; -use crate::stm32::{ - HRTIM_COMMON, HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, -}; use crate::timer::HrTim; +#[cfg(feature = "hrtim_v2")] +use pac::HRTIM_TIMF; +use pac::{HRTIM_COMMON, HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME}; use capture::{HrCaptCh1, HrCaptCh2}; @@ -45,11 +92,10 @@ use self::control::HrPwmControl; use self::deadtime::DeadtimeConfig; use self::output::ToHrOut; use self::timer_eev_cfg::EevCfgs; -use fugit::HertzU32 as Hertz; /// Internal enum that keeps track of the count settings before PWM is finalized enum CountSettings { - Frequency(Hertz), + //Frequency(Hertz), Period(u16), } @@ -117,17 +163,6 @@ pub enum HrCountingDirection { UpDown, } -// Needed to calculate frequency -impl From for crate::mcu::Alignment { - fn from(val: HrCountingDirection) -> Self { - match val { - HrCountingDirection::Up => crate::mcu::Alignment::Left, - #[cfg(feature = "hrtim_v2")] - HrCountingDirection::UpDown => crate::mcu::Alignment::Center, - } - } -} - #[derive(Copy, Clone, PartialEq, Debug)] pub enum InterleavedMode { Disabled, @@ -181,11 +216,17 @@ pub trait HrPwmAdvExt: Sized { PINS: ToHrOut; } +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Polarity { + ActiveHigh, + ActiveLow, +} + /// HrPwmBuilder is used to configure advanced HrTim PWM features pub struct HrPwmBuilder { _tim: PhantomData, _prescaler: PhantomData, - pins: PINS, + pub pins: PINS, timer_mode: HrTimerMode, counting_direction: HrCountingDirection, //base_freq: HertzU64, @@ -233,13 +274,10 @@ pub enum MasterPreloadSource { } macro_rules! hrtim_finalize_body { - ($this:expr, $PreloadSource:ident, $TIMX:ident, [$($out:ident)*], $($moder:ident, $otyper:ident, $afr:ident)*) => {{ + ($this:expr, $PreloadSource:ident, $TIMX:ident, [$($out:ident)*]) => {{ let tim = unsafe { &*$TIMX::ptr() }; let (period, prescaler_bits) = match $this.count { CountSettings::Period(period) => (period as u32, PSCL::BITS as u16), - CountSettings::Frequency(_freq) => { - todo!()//>::calculate_frequency($this.base_freq, freq, $this.counting_direction.into()) - }, }; let (half, _intlvd) = match $this.interleaved_mode { @@ -389,13 +427,6 @@ macro_rules! hrtim_finalize_body { // Start timer //let master = unsafe { &*HRTIM_MASTER::ptr() }; //master.mcr.modify(|_r, w| { w.$tXcen().set_bit() }); - - // Connect pins and let HRTIM take over control over them - $this.pins.connect_to_hrtim($($moder, $otyper, $afr)*); - - unsafe { - MaybeUninit::uninit().assume_init() - } }}; (PreloadSource, $this:expr, $tim:expr) => {{ @@ -437,14 +468,6 @@ macro_rules! hrtim_finalize_body { macro_rules! hrtim_common_methods { ($TIMX:ident, $PS:ident) => { - /// 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. - pub fn frequency>(mut self, freq: T) -> Self { - self.count = CountSettings::Frequency(freq.into()); - - self - } - /// Set the prescaler; PWM count runs at base_frequency/(prescaler+1) pub fn prescaler

(self, _prescaler: P) -> HrPwmBuilder<$TIMX, P, $PS, PINS> where @@ -473,7 +496,6 @@ macro_rules! hrtim_common_methods { } = self; let period = match count { - CountSettings::Frequency(_) => u16::MAX, CountSettings::Period(period) => period, }; @@ -587,24 +609,12 @@ macro_rules! hrtim_hal { PSCL: HrtimPrescaler, PINS: ToHrOut<$TIMX>, { - pub fn finalize(self, _control: &mut HrPwmControl, - #[cfg(feature = "stm32f3")] - moder: &mut ::MODER, - #[cfg(feature = "stm32f3")] - otyper: &mut ::OTYPER, - #[cfg(feature = "stm32f3")] - afr: &mut PINS::Afr - ) -> HrParts<$TIMX, PSCL, PINS::Out> { - #[cfg(feature = "stm32f3")] { - hrtim_finalize_body!( - self, PreloadSource, - $TIMX, [$($out)*], moder, otyper, afr - ) - } - - #[cfg(not(feature = "stm32f3"))] { - hrtim_finalize_body!(self, PreloadSource, $TIMX, [$($out)*],) - } + // For HAL writers: + // Make sure to connect gpios after calling this function and then it should be safe to + // conjure an instance of HrParts<$TIMX, PSCL, PINS::Out> + pub fn _init(self, _control: &mut HrPwmControl) -> PINS { + hrtim_finalize_body!(self, PreloadSource, $TIMX, [$($out)*]); + self.pins } hrtim_common_methods!($TIMX, PreloadSource); @@ -739,32 +749,10 @@ where PSCL: HrtimPrescaler, PINS: ToHrOut, { - pub fn finalize( - self, - _control: &mut HrPwmControl, - #[cfg(feature = "stm32f3")] - moder: &mut ::MODER, - #[cfg(feature = "stm32f3")] - otyper: &mut ::OTYPER, - #[cfg(feature = "stm32f3")] afr: &mut PINS::Afr, - ) -> HrParts { - #[cfg(feature = "stm32f3")] - { - hrtim_finalize_body!( - self, - MasterPreloadSource, - HRTIM_MASTER, - [], - moder, - otyper, - afr - ) - } + pub fn finalize(self, _control: &mut HrPwmControl) -> HrParts { + hrtim_finalize_body!(self, MasterPreloadSource, HRTIM_MASTER, []); - #[cfg(not(feature = "stm32f3"))] - { - hrtim_finalize_body!(self, MasterPreloadSource, HRTIM_MASTER, [],) - } + unsafe { MaybeUninit::uninit().assume_init() } } hrtim_common_methods!(HRTIM_MASTER, MasterPreloadSource); diff --git a/src/output.rs b/src/output.rs index 05af02a..f6f999e 100644 --- a/src/output.rs +++ b/src/output.rs @@ -1,39 +1,10 @@ #[cfg(feature = "hrtim_v2")] -use crate::stm32::HRTIM_TIMF; -use crate::{ - hal, - mcu::GpioInputMode, - stm32::{HRTIM_COMMON, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME}, -}; +use crate::pac::HRTIM_TIMF; +use crate::pac::{HRTIM_COMMON, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME}; use core::marker::PhantomData; use super::event::EventSource; -use hal::gpio::{ - gpioa::{PA10, PA11, PA8, PA9}, - gpioc::PC8, -}; - -#[cfg(any(feature = "stm32f3", feature = "stm32g4"))] -use hal::gpio::{ - gpiob::{PB12, PB13, PB14, PB15}, - gpioc::PC9, -}; - -#[cfg(feature = "stm32h7")] -use hal::gpio::{ - gpioa::PA12, - gpioc::{PC6, PC7}, - gpiog::{PG6, PG7}, -}; - -#[cfg(feature = "stm32g4")] -use hal::gpio::gpioc::{PC6, PC7}; - -mod sealed { - pub trait Sealed {} -} - macro_rules! hrtim_out { ($($TIMX:ident: $out_type:ident: $tXYoen:ident, $tXYodis:ident, $tXYods:ident, $setXYr:ident, $rstXYr:ident,)+) => {$( impl HrOutput<$TIMX, PSCL> for $out_type<$TIMX, PSCL> { @@ -159,156 +130,27 @@ impl State { } } -pub trait ToHrOut: sealed::Sealed { +/// # Safety +/// Caller needs to ensure that this is only implemented +/// for types that represent pin that can act as an output +/// for the specified timer `TIM` +pub unsafe trait ToHrOut { type Out; - - #[cfg(feature = "stm32f3")] - type GpioX: hal::gpio::marker::GpioStatic; - #[cfg(feature = "stm32f3")] - type Afr; - - fn connect_to_hrtim( - self, - #[cfg(feature = "stm32f3")] - moder: &mut ::MODER, - #[cfg(feature = "stm32f3")] - otyper: &mut ::OTYPER, - #[cfg(feature = "stm32f3")] afr: &mut Self::Afr, - ); } -impl sealed::Sealed for (PA, PB) +unsafe impl ToHrOut for (PA, PB) where PA: ToHrOut, PB: ToHrOut, -{ -} - -#[cfg(feature = "stm32f3")] -impl ToHrOut for (PA, PB) -where - PA: ToHrOut, - PB: ToHrOut, { type Out = (PA::Out, PB::Out); - type GpioX = PA::GpioX; - type Afr = PA::Afr; - - fn connect_to_hrtim( - self, - - moder: &mut ::MODER, - - otyper: &mut ::OTYPER, - - afr: &mut Self::Afr, - ) { - self.0.connect_to_hrtim(moder, otyper, afr); - self.1.connect_to_hrtim(moder, otyper, afr); - } -} - -#[cfg(any(feature = "stm32g4", feature = "stm32h7"))] -impl ToHrOut for (PA, PB) -where - PA: ToHrOut, - PB: ToHrOut, -{ - type Out = (PA::Out, PB::Out); - - fn connect_to_hrtim(self) { - self.0.connect_to_hrtim(); - self.1.connect_to_hrtim(); - } } pub struct HrOut1(PhantomData<(TIM, PSCL)>); pub struct HrOut2(PhantomData<(TIM, PSCL)>); -macro_rules! pins_helper { - ($TIMX:ty, $HrOutY:ident, $CHY:ident<$CHY_AF:literal>, $GpioX:ident) => { - impl sealed::Sealed<$TIMX> for $CHY {} - - impl ToHrOut<$TIMX> for $CHY { - type Out = $HrOutY<$TIMX, PSCL>; - - #[cfg(feature = "stm32f3")] - type GpioX = hal::gpio::$GpioX; - #[cfg(feature = "stm32f3")] - type Afr = >::AFR; - - // Pin> - fn connect_to_hrtim( - self, - #[cfg(feature = "stm32f3")] - moder: &mut ::MODER, - #[cfg(feature = "stm32f3")] - otyper: &mut ::OTYPER, - #[cfg(feature = "stm32f3")] afr: &mut Self::Afr, - ) { - #[allow(non_snake_case, unused_variables)] - let $GpioX = (); - - #[cfg(feature = "stm32f3")] - let _: $CHY> = - self.into_af_push_pull(moder, otyper, afr); - - #[cfg(any(feature = "stm32g4", feature = "stm32h7"))] - let _: $CHY> = self.into_alternate(); - } - } - }; -} - -// $GpioX is only used for f3x4 -macro_rules! pins { - ($($TIMX:ty: CH1: $CH1:ident<$CH1_AF:literal>, CH2: $CH2:ident<$CH2_AF:literal>, $GpioX:ident)+) => {$( - pins_helper!($TIMX, HrOut1, $CH1<$CH1_AF>, $GpioX); - pins_helper!($TIMX, HrOut2, $CH2<$CH2_AF>, $GpioX); - )+}; -} - -#[cfg(any(feature = "stm32g4", feature = "stm32f3"))] -pins! { - HRTIM_TIMA: CH1: PA8<13>, CH2: PA9<13>, Gpioa - HRTIM_TIMB: CH1: PA10<13>, CH2: PA11<13>, Gpioa - HRTIM_TIMC: CH1: PB12<13>, CH2: PB13<13>, Gpiob - HRTIM_TIMD: CH1: PB14<13>, CH2: PB15<13>, Gpiob - HRTIM_TIME: CH1: PC8<3>, CH2: PC9<3>, Gpioc -} - -#[cfg(feature = "stm32g4")] -pins! { - HRTIM_TIMF: CH1: PC6<13>, CH2: PC7<13>, Gpioc -} - -// TODO: H7 does not start in input mode, it starts in Analog -#[cfg(feature = "stm32h7")] // RM0433 -pins! { - HRTIM_TIMA: CH1: PC6<1>, CH2: PC7<1>, Gpioc - HRTIM_TIMB: CH1: PC8<1>, CH2: PA8<2>, GpioC // This type is not used for in this config so it's ok - HRTIM_TIMC: CH1: PA9<2>, CH2: PA10<2>, GpioA - HRTIM_TIMD: CH1: PA11<2>, CH2: PA12<2>, GpioA - HRTIM_TIME: CH1: PG6<2>, CH2: PG7<2>, GpioG -} - -impl sealed::Sealed for () {} -impl ToHrOut for () { +unsafe impl ToHrOut for () { type Out = (); - #[cfg(feature = "stm32f3")] - type GpioX = hal::gpio::Gpioa; - #[cfg(feature = "stm32f3")] - type Afr = (); - - fn connect_to_hrtim( - self, - #[cfg(feature = "stm32f3")] - _moder: &mut ::MODER, - #[cfg(feature = "stm32f3")] - _otyper: &mut ::OTYPER, - #[cfg(feature = "stm32f3")] _afr: &mut Self::Afr, - ) { - } } pub struct CH1(PhantomData); diff --git a/src/stm32f3.rs b/src/stm32f3.rs deleted file mode 100644 index 1ca5c39..0000000 --- a/src/stm32f3.rs +++ /dev/null @@ -1,17 +0,0 @@ -pub use stm32f3xx_hal as hal; -//pub use hal::pac as stm32; -pub use stm32f3::stm32f3x4 as stm32; - -#[allow(non_camel_case_types, dead_code)] -pub enum DmaMuxResources {} - -pub type GpioInputMode = hal::gpio::Input; - -pub enum Alignment { - Left, -} -#[cfg(feature = "stm32f3")] -pub enum Polarity { - ActiveHigh, - ActiveLow, -} diff --git a/src/stm32g4.rs b/src/stm32g4.rs deleted file mode 100644 index a42b791..0000000 --- a/src/stm32g4.rs +++ /dev/null @@ -1,20 +0,0 @@ -pub use hal::stm32; -pub use stm32g4xx_hal as hal; - -#[allow(non_camel_case_types, dead_code)] -pub enum DmaMuxResources { - HRTIM_MASTER = 95, - HRTIM_TIMA = 96, - HRTIM_TIMB = 97, - HRTIM_TIMC = 98, - HRTIM_TIMD = 99, - HRTIM_TIME = 100, - HRTIM_TIMF = 101, -} - -pub type GpioInputMode = hal::gpio::Input; - -pub use hal::pwm::Alignment; - -#[cfg(feature = "stm32g4")] -pub use hal::pwm::Polarity; diff --git a/src/stm32h7.rs b/src/stm32h7.rs deleted file mode 100644 index fd8c117..0000000 --- a/src/stm32h7.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub use hal::stm32; -pub use stm32h7xx_hal as hal; - -// TODO: H7 does not start in input mode, it starts in Analog -pub type GpioInputMode = hal::gpio::Input; - -pub use hal::pwm::Alignment; - -#[cfg(feature = "stm32h7")] -pub use hal::pwm::Polarity; diff --git a/src/timer.rs b/src/timer.rs index d03ed0d..182b97c 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,6 +1,6 @@ #[cfg(feature = "hrtim_v2")] -use crate::stm32::HRTIM_TIMF; -use crate::stm32::{HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME}; +use crate::pac::HRTIM_TIMF; +use crate::pac::{HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME}; use core::marker::PhantomData; use super::{ @@ -315,13 +315,10 @@ macro_rules! hrtim_timer_adc_trigger { } #[cfg(feature = "stm32g4")] -use super::adc_trigger::Adc13Trigger as Adc13; -#[cfg(feature = "stm32g4")] -use super::adc_trigger::Adc24Trigger as Adc24; -#[cfg(feature = "stm32g4")] -use super::adc_trigger::Adc579Trigger as Adc579; -#[cfg(feature = "stm32g4")] -use super::adc_trigger::Adc6810Trigger as Adc6810; +use super::adc_trigger::{ + AdcTrigger13 as Adc13, AdcTrigger24 as Adc24, AdcTrigger579 as Adc579, + AdcTrigger6810 as Adc6810, +}; hrtim_timer! { HRTIM_MASTER: mcen, mudis,,