stm32: rename timer channel trait; replace impls via macro with impls generic over timer channels

This commit is contained in:
melvdl 2025-06-27 01:08:28 +02:00
parent cbd24bf2ee
commit 6f88c2c73c
8 changed files with 248 additions and 281 deletions

View File

@ -6,11 +6,11 @@ use stm32_metapac::timer::vals::Ckd;
use super::low_level::{CountingMode, OutputPolarity, Timer};
use super::simple_pwm::PwmPin;
use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, TimerChannel, TimerComplementaryPin};
use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin};
use crate::gpio::{AnyPin, OutputType};
use crate::time::Hertz;
use crate::timer::low_level::OutputCompareMode;
use crate::timer::Channel;
use crate::timer::TimerChannel;
use crate::Peri;
/// Complementary PWM pin wrapper.
@ -21,7 +21,7 @@ pub struct ComplementaryPwmPin<'d, T, C> {
phantom: PhantomData<(T, C)>,
}
impl<'d, T: AdvancedInstance4Channel, C: Channel> ComplementaryPwmPin<'d, T, C> {
impl<'d, T: AdvancedInstance4Channel, C: TimerChannel> ComplementaryPwmPin<'d, T, C> {
/// Create a new complementary PWM pin instance.
pub fn new(pin: Peri<'d, impl TimerComplementaryPin<T, C>>, output_type: OutputType) -> Self {
critical_section::with(|_| {
@ -71,29 +71,24 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
this.inner.enable_outputs();
[
TimerChannel::Ch1,
TimerChannel::Ch2,
TimerChannel::Ch3,
TimerChannel::Ch4,
]
.iter()
.for_each(|&channel| {
this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1);
this.inner.set_output_compare_preload(channel, true);
});
[Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
.iter()
.for_each(|&channel| {
this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1);
this.inner.set_output_compare_preload(channel, true);
});
this
}
/// Enable the given channel.
pub fn enable(&mut self, channel: TimerChannel) {
pub fn enable(&mut self, channel: Channel) {
self.inner.enable_channel(channel, true);
self.inner.enable_complementary_channel(channel, true);
}
/// Disable the given channel.
pub fn disable(&mut self, channel: TimerChannel) {
pub fn disable(&mut self, channel: Channel) {
self.inner.enable_complementary_channel(channel, false);
self.inner.enable_channel(channel, false);
}
@ -121,13 +116,13 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
/// Set the duty for a given channel.
///
/// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
pub fn set_duty(&mut self, channel: TimerChannel, duty: u16) {
pub fn set_duty(&mut self, channel: Channel, duty: u16) {
assert!(duty <= self.get_max_duty());
self.inner.set_compare_value(channel, duty as _)
}
/// Set the output polarity for a given channel.
pub fn set_polarity(&mut self, channel: TimerChannel, polarity: OutputPolarity) {
pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
self.inner.set_output_polarity(channel, polarity);
self.inner.set_complementary_output_polarity(channel, polarity);
}
@ -142,7 +137,7 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
}
impl<'d, T: AdvancedInstance4Channel> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> {
type Channel = TimerChannel;
type Channel = Channel;
type Time = Hertz;
type Duty = u16;

View File

@ -6,12 +6,12 @@ use core::pin::Pin;
use core::task::{Context, Poll};
use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer};
use super::{CaptureCompareInterruptHandler, GeneralInstance4Channel, TimerChannel, TimerPin};
use super::{CaptureCompareInterruptHandler, GeneralInstance4Channel, Channel, TimerPin};
pub use super::{Ch1, Ch2, Ch3, Ch4};
use crate::gpio::{AfType, AnyPin, Pull};
use crate::interrupt::typelevel::{Binding, Interrupt};
use crate::time::Hertz;
use crate::timer::Channel;
use crate::timer::TimerChannel;
use crate::Peri;
/// Capture pin wrapper.
@ -21,7 +21,7 @@ pub struct CapturePin<'d, T, C> {
_pin: Peri<'d, AnyPin>,
phantom: PhantomData<(T, C)>,
}
impl<'d, T: GeneralInstance4Channel, C: Channel> CapturePin<'d, T, C> {
impl<'d, T: GeneralInstance4Channel, C: TimerChannel> CapturePin<'d, T, C> {
/// Create a new capture pin instance.
pub fn new(pin: Peri<'d, impl TimerPin<T, C>>, pull: Pull) -> Self {
pin.set_as_af(pin.af_num(), AfType::input(pull));
@ -68,46 +68,41 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
}
/// Enable the given channel.
pub fn enable(&mut self, channel: TimerChannel) {
pub fn enable(&mut self, channel: Channel) {
self.inner.enable_channel(channel, true);
}
/// Disable the given channel.
pub fn disable(&mut self, channel: TimerChannel) {
pub fn disable(&mut self, channel: Channel) {
self.inner.enable_channel(channel, false);
}
/// Check whether given channel is enabled
pub fn is_enabled(&self, channel: TimerChannel) -> bool {
pub fn is_enabled(&self, channel: Channel) -> bool {
self.inner.get_channel_enable_state(channel)
}
/// Set the input capture mode for a given channel.
pub fn set_input_capture_mode(&mut self, channel: TimerChannel, mode: InputCaptureMode) {
pub fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
self.inner.set_input_capture_mode(channel, mode);
}
/// Set input TI selection.
pub fn set_input_ti_selection(&mut self, channel: TimerChannel, tisel: InputTISelection) {
pub fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
self.inner.set_input_ti_selection(channel, tisel)
}
/// Get capture value for a channel.
pub fn get_capture_value(&self, channel: TimerChannel) -> u32 {
pub fn get_capture_value(&self, channel: Channel) -> u32 {
self.inner.get_capture_value(channel)
}
/// Get input interrupt.
pub fn get_input_interrupt(&self, channel: TimerChannel) -> bool {
pub fn get_input_interrupt(&self, channel: Channel) -> bool {
self.inner.get_input_interrupt(channel)
}
fn new_future(
&self,
channel: TimerChannel,
mode: InputCaptureMode,
tisel: InputTISelection,
) -> InputCaptureFuture<T> {
fn new_future(&self, channel: Channel, mode: InputCaptureMode, tisel: InputTISelection) -> InputCaptureFuture<T> {
// Configuration steps from ST RM0390 (STM32F446) chapter 17.3.5
// or ST RM0008 (STM32F103) chapter 15.3.5 Input capture mode
self.inner.set_input_ti_selection(channel, tisel);
@ -124,37 +119,37 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
}
/// Asynchronously wait until the pin sees a rising edge.
pub async fn wait_for_rising_edge(&mut self, channel: TimerChannel) -> u32 {
pub async fn wait_for_rising_edge(&mut self, channel: Channel) -> u32 {
self.new_future(channel, InputCaptureMode::Rising, InputTISelection::Normal)
.await
}
/// Asynchronously wait until the pin sees a falling edge.
pub async fn wait_for_falling_edge(&mut self, channel: TimerChannel) -> u32 {
pub async fn wait_for_falling_edge(&mut self, channel: Channel) -> u32 {
self.new_future(channel, InputCaptureMode::Falling, InputTISelection::Normal)
.await
}
/// Asynchronously wait until the pin sees any edge.
pub async fn wait_for_any_edge(&mut self, channel: TimerChannel) -> u32 {
pub async fn wait_for_any_edge(&mut self, channel: Channel) -> u32 {
self.new_future(channel, InputCaptureMode::BothEdges, InputTISelection::Normal)
.await
}
/// Asynchronously wait until the (alternate) pin sees a rising edge.
pub async fn wait_for_rising_edge_alternate(&mut self, channel: TimerChannel) -> u32 {
pub async fn wait_for_rising_edge_alternate(&mut self, channel: Channel) -> u32 {
self.new_future(channel, InputCaptureMode::Rising, InputTISelection::Alternate)
.await
}
/// Asynchronously wait until the (alternate) pin sees a falling edge.
pub async fn wait_for_falling_edge_alternate(&mut self, channel: TimerChannel) -> u32 {
pub async fn wait_for_falling_edge_alternate(&mut self, channel: Channel) -> u32 {
self.new_future(channel, InputCaptureMode::Falling, InputTISelection::Alternate)
.await
}
/// Asynchronously wait until the (alternate) pin sees any edge.
pub async fn wait_for_any_edge_alternate(&mut self, channel: TimerChannel) -> u32 {
pub async fn wait_for_any_edge_alternate(&mut self, channel: Channel) -> u32 {
self.new_future(channel, InputCaptureMode::BothEdges, InputTISelection::Alternate)
.await
}
@ -162,7 +157,7 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
#[must_use = "futures do nothing unless you `.await` or poll them"]
struct InputCaptureFuture<T: GeneralInstance4Channel> {
channel: TimerChannel,
channel: Channel,
phantom: PhantomData<T>,
}

View File

@ -503,7 +503,7 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
}
/// Set input capture filter.
pub fn set_input_capture_filter(&self, channel: TimerChannel, icf: vals::FilterValue) {
pub fn set_input_capture_filter(&self, channel: Channel, icf: vals::FilterValue) {
let raw_channel = channel.index();
self.regs_gp16()
.ccmr_input(raw_channel / 2)
@ -511,22 +511,22 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
}
/// Clear input interrupt.
pub fn clear_input_interrupt(&self, channel: TimerChannel) {
pub fn clear_input_interrupt(&self, channel: Channel) {
self.regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false));
}
/// Get input interrupt.
pub fn get_input_interrupt(&self, channel: TimerChannel) -> bool {
pub fn get_input_interrupt(&self, channel: Channel) -> bool {
self.regs_gp16().sr().read().ccif(channel.index())
}
/// Enable input interrupt.
pub fn enable_input_interrupt(&self, channel: TimerChannel, enable: bool) {
pub fn enable_input_interrupt(&self, channel: Channel, enable: bool) {
self.regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable));
}
/// Set input capture prescaler.
pub fn set_input_capture_prescaler(&self, channel: TimerChannel, factor: u8) {
pub fn set_input_capture_prescaler(&self, channel: Channel, factor: u8) {
let raw_channel = channel.index();
self.regs_gp16()
.ccmr_input(raw_channel / 2)
@ -534,7 +534,7 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
}
/// Set input TI selection.
pub fn set_input_ti_selection(&self, channel: TimerChannel, tisel: InputTISelection) {
pub fn set_input_ti_selection(&self, channel: Channel, tisel: InputTISelection) {
let raw_channel = channel.index();
self.regs_gp16()
.ccmr_input(raw_channel / 2)
@ -542,7 +542,7 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
}
/// Set input capture mode.
pub fn set_input_capture_mode(&self, channel: TimerChannel, mode: InputCaptureMode) {
pub fn set_input_capture_mode(&self, channel: Channel, mode: InputCaptureMode) {
self.regs_gp16().ccer().modify(|r| match mode {
InputCaptureMode::Rising => {
r.set_ccnp(channel.index(), false);
@ -560,7 +560,7 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
}
/// Set output compare mode.
pub fn set_output_compare_mode(&self, channel: TimerChannel, mode: OutputCompareMode) {
pub fn set_output_compare_mode(&self, channel: Channel, mode: OutputCompareMode) {
let raw_channel: usize = channel.index();
self.regs_gp16()
.ccmr_output(raw_channel / 2)
@ -568,24 +568,24 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
}
/// Set output polarity.
pub fn set_output_polarity(&self, channel: TimerChannel, polarity: OutputPolarity) {
pub fn set_output_polarity(&self, channel: Channel, polarity: OutputPolarity) {
self.regs_gp16()
.ccer()
.modify(|w| w.set_ccp(channel.index(), polarity.into()));
}
/// Enable/disable a channel.
pub fn enable_channel(&self, channel: TimerChannel, enable: bool) {
pub fn enable_channel(&self, channel: Channel, enable: bool) {
self.regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable));
}
/// Get enable/disable state of a channel
pub fn get_channel_enable_state(&self, channel: TimerChannel) -> bool {
pub fn get_channel_enable_state(&self, channel: Channel) -> bool {
self.regs_gp16().ccer().read().cce(channel.index())
}
/// Set compare value for a channel.
pub fn set_compare_value(&self, channel: TimerChannel, value: u32) {
pub fn set_compare_value(&self, channel: Channel, value: u32) {
match T::BITS {
TimerBits::Bits16 => {
let value = unwrap!(u16::try_from(value));
@ -599,7 +599,7 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
}
/// Get compare value for a channel.
pub fn get_compare_value(&self, channel: TimerChannel) -> u32 {
pub fn get_compare_value(&self, channel: Channel) -> u32 {
match T::BITS {
TimerBits::Bits16 => self.regs_gp16().ccr(channel.index()).read().ccr() as u32,
#[cfg(not(stm32l0))]
@ -608,12 +608,12 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
}
/// Get capture value for a channel.
pub fn get_capture_value(&self, channel: TimerChannel) -> u32 {
pub fn get_capture_value(&self, channel: Channel) -> u32 {
self.get_compare_value(channel)
}
/// Set output compare preload.
pub fn set_output_compare_preload(&self, channel: TimerChannel, preload: bool) {
pub fn set_output_compare_preload(&self, channel: Channel, preload: bool) {
let channel_index = channel.index();
self.regs_gp16()
.ccmr_output(channel_index / 2)
@ -631,12 +631,12 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
}
/// Get capture compare DMA enable state
pub fn get_cc_dma_enable_state(&self, channel: TimerChannel) -> bool {
pub fn get_cc_dma_enable_state(&self, channel: Channel) -> bool {
self.regs_gp16().dier().read().ccde(channel.index())
}
/// Set capture compare DMA enable state
pub fn set_cc_dma_enable_state(&self, channel: TimerChannel, ccde: bool) {
pub fn set_cc_dma_enable_state(&self, channel: Channel, ccde: bool) {
self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde))
}
@ -713,14 +713,14 @@ impl<'d, T: AdvancedInstance4Channel> Timer<'d, T> {
}
/// Set complementary output polarity.
pub fn set_complementary_output_polarity(&self, channel: TimerChannel, polarity: OutputPolarity) {
pub fn set_complementary_output_polarity(&self, channel: Channel, polarity: OutputPolarity) {
self.regs_advanced()
.ccer()
.modify(|w| w.set_ccnp(channel.index(), polarity.into()));
}
/// Enable/disable a complementary channel.
pub fn enable_complementary_channel(&self, channel: TimerChannel, enable: bool) {
pub fn enable_complementary_channel(&self, channel: Channel, enable: bool) {
self.regs_advanced()
.ccer()
.modify(|w| w.set_ccne(channel.index(), enable));

View File

@ -19,7 +19,7 @@ use crate::rcc::RccPeripheral;
/// Timer channel.
#[derive(Clone, Copy)]
pub enum TimerChannel {
pub enum Channel {
/// Channel 1.
Ch1,
/// Channel 2.
@ -30,14 +30,14 @@ pub enum TimerChannel {
Ch4,
}
impl TimerChannel {
impl Channel {
/// Get the channel index (0..3)
pub fn index(&self) -> usize {
match self {
TimerChannel::Ch1 => 0,
TimerChannel::Ch2 => 1,
TimerChannel::Ch3 => 2,
TimerChannel::Ch4 => 3,
Channel::Ch1 => 0,
Channel::Ch2 => 1,
Channel::Ch3 => 2,
Channel::Ch4 => 3,
}
}
}
@ -53,33 +53,33 @@ pub enum Ch4 {}
/// Timer channel trait.
#[allow(private_bounds)]
pub trait Channel: SealedChannel {
pub trait TimerChannel: SealedTimerChannel {
/// The runtime channel.
const CHANNEL: TimerChannel;
const CHANNEL: Channel;
}
trait SealedChannel {}
trait SealedTimerChannel {}
impl Channel for Ch1 {
const CHANNEL: TimerChannel = TimerChannel::Ch1;
impl TimerChannel for Ch1 {
const CHANNEL: Channel = Channel::Ch1;
}
impl Channel for Ch2 {
const CHANNEL: TimerChannel = TimerChannel::Ch2;
impl TimerChannel for Ch2 {
const CHANNEL: Channel = Channel::Ch2;
}
impl Channel for Ch3 {
const CHANNEL: TimerChannel = TimerChannel::Ch3;
impl TimerChannel for Ch3 {
const CHANNEL: Channel = Channel::Ch3;
}
impl Channel for Ch4 {
const CHANNEL: TimerChannel = TimerChannel::Ch4;
impl TimerChannel for Ch4 {
const CHANNEL: Channel = Channel::Ch4;
}
impl SealedChannel for Ch1 {}
impl SealedChannel for Ch2 {}
impl SealedChannel for Ch3 {}
impl SealedChannel for Ch4 {}
impl SealedTimerChannel for Ch1 {}
impl SealedTimerChannel for Ch2 {}
impl SealedTimerChannel for Ch3 {}
impl SealedTimerChannel for Ch4 {}
/// Timer break input.
#[derive(Clone, Copy)]
@ -223,10 +223,10 @@ pub trait AdvancedInstance2Channel: BasicInstance + GeneralInstance2Channel + Ad
/// Advanced 16-bit timer with 4 channels instance.
pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {}
pin_trait!(TimerPin, GeneralInstance4Channel, Channel);
pin_trait!(TimerPin, GeneralInstance4Channel, TimerChannel);
pin_trait!(ExternalTriggerPin, GeneralInstance4Channel);
pin_trait!(TimerComplementaryPin, AdvancedInstance4Channel, Channel);
pin_trait!(TimerComplementaryPin, AdvancedInstance4Channel, TimerChannel);
pin_trait!(BreakInputPin, AdvancedInstance4Channel, BreakInput);
@ -236,7 +236,7 @@ pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel, BreakInput);
// Update Event trigger DMA for every timer
dma_trait!(UpDma, BasicInstance);
dma_trait!(Dma, GeneralInstance4Channel, Channel);
dma_trait!(Dma, GeneralInstance4Channel, TimerChannel);
#[allow(unused)]
macro_rules! impl_core_timer {

View File

@ -9,7 +9,7 @@ use core::task::{Context, Poll};
use super::low_level::{
CountingMode, FilterValue, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource as Ts,
};
use super::{CaptureCompareInterruptHandler, ExternalTriggerPin, GeneralInstance4Channel, TimerChannel, TimerPin};
use super::{CaptureCompareInterruptHandler, Channel, ExternalTriggerPin, GeneralInstance4Channel, TimerPin};
pub use super::{Ch1, Ch2};
use crate::gpio::{AfType, AnyPin, Pull};
use crate::interrupt::typelevel::{Binding, Interrupt};
@ -76,7 +76,7 @@ impl<T, P, C> TimerTriggerPin<T, C> for P
where
T: GeneralInstance4Channel,
P: TimerPin<T, C>,
C: super::Channel + TriggerSource,
C: super::TimerChannel + TriggerSource,
{
fn af_num(&self) -> u8 {
TimerPin::af_num(self)
@ -97,7 +97,7 @@ impl<T, P, C> SealedTimerTriggerPin<T, C> for P
where
T: GeneralInstance4Channel,
P: TimerPin<T, C>,
C: super::Channel + TriggerSource,
C: super::TimerChannel + TriggerSource,
{
}
@ -143,9 +143,9 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
this.inner.set_trigger_source(Ts::TI1F_ED);
this.inner
.set_input_ti_selection(TimerChannel::Ch1, InputTISelection::Normal);
.set_input_ti_selection(Channel::Ch1, InputTISelection::Normal);
this.inner
.set_input_capture_filter(TimerChannel::Ch1, FilterValue::NO_FILTER);
.set_input_capture_filter(Channel::Ch1, FilterValue::NO_FILTER);
this.new_inner(freq, pulse_end, counting_mode);
this
@ -168,10 +168,10 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
this.inner.set_trigger_source(Ts::TI1FP1);
this.inner
.set_input_ti_selection(TimerChannel::Ch1, InputTISelection::Normal);
.set_input_ti_selection(Channel::Ch1, InputTISelection::Normal);
this.inner
.set_input_capture_filter(TimerChannel::Ch1, FilterValue::NO_FILTER);
this.inner.set_input_capture_mode(TimerChannel::Ch1, capture_mode);
.set_input_capture_filter(Channel::Ch1, FilterValue::NO_FILTER);
this.inner.set_input_capture_mode(Channel::Ch1, capture_mode);
this.new_inner(freq, pulse_end, counting_mode);
this
@ -194,10 +194,10 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
this.inner.set_trigger_source(Ts::TI2FP2);
this.inner
.set_input_ti_selection(TimerChannel::Ch2, InputTISelection::Normal);
.set_input_ti_selection(Channel::Ch2, InputTISelection::Normal);
this.inner
.set_input_capture_filter(TimerChannel::Ch2, FilterValue::NO_FILTER);
this.inner.set_input_capture_mode(TimerChannel::Ch2, capture_mode);
.set_input_capture_filter(Channel::Ch2, FilterValue::NO_FILTER);
this.inner.set_input_capture_mode(Channel::Ch2, capture_mode);
this.new_inner(freq, pulse_end, counting_mode);
this
@ -269,7 +269,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
/// Get a single channel
///
/// If you need to use multiple channels, use [`Self::split`].
pub fn channel(&mut self, channel: TimerChannel) -> OnePulseChannel<'_, T> {
pub fn channel(&mut self, channel: Channel) -> OnePulseChannel<'_, T> {
OnePulseChannel {
inner: unsafe { self.inner.clone_unchecked() },
channel,
@ -282,7 +282,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
///
/// If you need to use multiple channels, use [`Self::split`].
pub fn ch1(&mut self) -> OnePulseChannel<'_, T> {
self.channel(TimerChannel::Ch1)
self.channel(Channel::Ch1)
}
/// Channel 2
@ -291,7 +291,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
///
/// If you need to use multiple channels, use [`Self::split`].
pub fn ch2(&mut self) -> OnePulseChannel<'_, T> {
self.channel(TimerChannel::Ch2)
self.channel(Channel::Ch2)
}
/// Channel 3
@ -300,7 +300,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
///
/// If you need to use multiple channels, use [`Self::split`].
pub fn ch3(&mut self) -> OnePulseChannel<'_, T> {
self.channel(TimerChannel::Ch3)
self.channel(Channel::Ch3)
}
/// Channel 4
@ -309,7 +309,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
///
/// If you need to use multiple channels, use [`Self::split`].
pub fn ch4(&mut self) -> OnePulseChannel<'_, T> {
self.channel(TimerChannel::Ch4)
self.channel(Channel::Ch4)
}
/// Splits a [`OnePulse`] into four output channels.
@ -328,10 +328,10 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
};
OnePulseChannels {
ch1: ch(TimerChannel::Ch1),
ch2: ch(TimerChannel::Ch2),
ch3: ch(TimerChannel::Ch3),
ch4: ch(TimerChannel::Ch4),
ch1: ch(Channel::Ch1),
ch2: ch(Channel::Ch2),
ch3: ch(Channel::Ch3),
ch4: ch(Channel::Ch4),
}
}
}
@ -355,7 +355,7 @@ pub struct OnePulseChannels<'d, T: GeneralInstance4Channel> {
/// configuration is shared with all four channels.
pub struct OnePulseChannel<'d, T: GeneralInstance4Channel> {
inner: ManuallyDrop<Timer<'d, T>>,
channel: TimerChannel,
channel: Channel,
}
impl<'d, T: GeneralInstance4Channel> OnePulseChannel<'d, T> {
@ -402,7 +402,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulseChannel<'d, T> {
#[must_use = "futures do nothing unless you `.await` or poll them"]
struct OnePulseFuture<T: GeneralInstance4Channel> {
channel: TimerChannel,
channel: Channel,
phantom: PhantomData<T>,
}

View File

@ -1,14 +1,14 @@
//! PWM Input driver.
use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource};
use super::{Ch1, Ch2, GeneralInstance4Channel, TimerChannel, TimerPin};
use super::{Ch1, Ch2, GeneralInstance4Channel, Channel, TimerPin};
use crate::gpio::{AfType, Pull};
use crate::time::Hertz;
use crate::Peri;
/// PWM Input driver.
pub struct PwmInput<'d, T: GeneralInstance4Channel> {
channel: TimerChannel,
channel: Channel,
inner: Timer<'d, T>,
}
@ -17,17 +17,17 @@ impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> {
pub fn new(tim: Peri<'d, T>, pin: Peri<'d, impl TimerPin<T, Ch1>>, pull: Pull, freq: Hertz) -> Self {
pin.set_as_af(pin.af_num(), AfType::input(pull));
Self::new_inner(tim, freq, TimerChannel::Ch1, TimerChannel::Ch2)
Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2)
}
/// Create a new PWM input driver.
pub fn new_alt(tim: Peri<'d, T>, pin: Peri<'d, impl TimerPin<T, Ch2>>, pull: Pull, freq: Hertz) -> Self {
pin.set_as_af(pin.af_num(), AfType::input(pull));
Self::new_inner(tim, freq, TimerChannel::Ch2, TimerChannel::Ch1)
Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1)
}
fn new_inner(tim: Peri<'d, T>, freq: Hertz, ch1: TimerChannel, ch2: TimerChannel) -> Self {
fn new_inner(tim: Peri<'d, T>, freq: Hertz, ch1: Channel, ch2: Channel) -> Self {
let mut inner = Timer::new(tim);
inner.set_counting_mode(CountingMode::EdgeAlignedUp);
@ -44,8 +44,8 @@ impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> {
inner.set_input_capture_mode(ch2, InputCaptureMode::Falling);
inner.set_trigger_source(match ch1 {
TimerChannel::Ch1 => TriggerSource::TI1FP1,
TimerChannel::Ch2 => TriggerSource::TI2FP2,
Channel::Ch1 => TriggerSource::TI1FP1,
Channel::Ch2 => TriggerSource::TI2FP2,
_ => panic!("Invalid channel for PWM input"),
});
@ -58,19 +58,19 @@ impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> {
/// Enable the given channel.
pub fn enable(&mut self) {
self.inner.enable_channel(TimerChannel::Ch1, true);
self.inner.enable_channel(TimerChannel::Ch2, true);
self.inner.enable_channel(Channel::Ch1, true);
self.inner.enable_channel(Channel::Ch2, true);
}
/// Disable the given channel.
pub fn disable(&mut self) {
self.inner.enable_channel(TimerChannel::Ch1, false);
self.inner.enable_channel(TimerChannel::Ch2, false);
self.inner.enable_channel(Channel::Ch1, false);
self.inner.enable_channel(Channel::Ch2, false);
}
/// Check whether given channel is enabled
pub fn is_enabled(&self) -> bool {
self.inner.get_channel_enable_state(TimerChannel::Ch1)
self.inner.get_channel_enable_state(Channel::Ch1)
}
/// Get the period tick count
@ -81,8 +81,8 @@ impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> {
/// Get the pulse width tick count
pub fn get_width_ticks(&self) -> u32 {
self.inner.get_capture_value(match self.channel {
TimerChannel::Ch1 => TimerChannel::Ch2,
TimerChannel::Ch2 => TimerChannel::Ch1,
Channel::Ch1 => Channel::Ch2,
Channel::Ch2 => Channel::Ch1,
_ => panic!("Invalid channel for PWM input"),
})
}

View File

@ -8,7 +8,7 @@ use super::low_level::Timer;
pub use super::{Ch1, Ch2};
use super::{GeneralInstance4Channel, TimerPin};
use crate::gpio::{AfType, AnyPin, Pull};
use crate::timer::Channel;
use crate::timer::TimerChannel;
use crate::Peri;
/// Counting direction
@ -39,7 +39,7 @@ impl<'d, T: GeneralInstance4Channel, C: QeiChannel> QeiPin<'d, T, C> {
}
}
trait SealedQeiChannel: Channel {}
trait SealedQeiChannel: TimerChannel {}
/// Marker trait for a timer channel eligible for use with QEI.
#[expect(private_bounds)]

View File

@ -4,7 +4,7 @@ use core::marker::PhantomData;
use core::mem::ManuallyDrop;
use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer};
use super::{Ch1, Ch2, Ch3, Ch4, GeneralInstance4Channel, TimerBits, TimerChannel, TimerPin};
use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerBits, TimerChannel, TimerPin};
#[cfg(gpio_v2)]
use crate::gpio::Pull;
use crate::gpio::{AfType, AnyPin, OutputType, Speed};
@ -34,46 +34,37 @@ pub struct PwmPinConfig {
pub pull: Pull,
}
macro_rules! channel_impl {
($new_chx:ident, $new_chx_with_config:ident, $channel:ident, $pin_trait:ident) => {
impl<'d, T: GeneralInstance4Channel> PwmPin<'d, T, $channel> {
#[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T, $channel>>, output_type: OutputType) -> Self {
critical_section::with(|_| {
pin.set_low();
pin.set_as_af(pin.af_num(), AfType::output(output_type, Speed::VeryHigh));
});
PwmPin {
_pin: pin.into(),
phantom: PhantomData,
}
}
#[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance with config.")]
pub fn $new_chx_with_config(pin: Peri<'d, impl $pin_trait<T, $channel>>, pin_config: PwmPinConfig) -> Self {
critical_section::with(|_| {
pin.set_low();
pin.set_as_af(
pin.af_num(),
#[cfg(gpio_v1)]
AfType::output(pin_config.output_type, pin_config.speed),
#[cfg(gpio_v2)]
AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull),
);
});
PwmPin {
_pin: pin.into(),
phantom: PhantomData,
}
}
impl<'d, T: GeneralInstance4Channel, C: TimerChannel> PwmPin<'d, T, C> {
/// Create a new PWM pin instance.
pub fn new(pin: Peri<'d, impl TimerPin<T, C>>, output_type: OutputType) -> Self {
critical_section::with(|_| {
pin.set_low();
pin.set_as_af(pin.af_num(), AfType::output(output_type, Speed::VeryHigh));
});
PwmPin {
_pin: pin.into(),
phantom: PhantomData,
}
};
}
}
channel_impl!(new_ch1, new_ch1_with_config, Ch1, TimerPin);
channel_impl!(new_ch2, new_ch2_with_config, Ch2, TimerPin);
channel_impl!(new_ch3, new_ch3_with_config, Ch3, TimerPin);
channel_impl!(new_ch4, new_ch4_with_config, Ch4, TimerPin);
/// Create a new PWM pin instance with config.
pub fn new_with_config(pin: Peri<'d, impl TimerPin<T, C>>, pin_config: PwmPinConfig) -> Self {
critical_section::with(|_| {
pin.set_low();
pin.set_as_af(
pin.af_num(),
#[cfg(gpio_v1)]
AfType::output(pin_config.output_type, pin_config.speed),
#[cfg(gpio_v2)]
AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull),
);
});
PwmPin {
_pin: pin.into(),
phantom: PhantomData,
}
}
}
/// A single channel of a pwm, obtained from [`SimplePwm::split`],
/// [`SimplePwm::channel`], [`SimplePwm::ch1`], etc.
@ -82,7 +73,7 @@ channel_impl!(new_ch4, new_ch4_with_config, Ch4, TimerPin);
/// the frequency configuration is shared with all four channels.
pub struct SimplePwmChannel<'d, T: GeneralInstance4Channel> {
timer: ManuallyDrop<Timer<'d, T>>,
channel: TimerChannel,
channel: Channel,
}
// TODO: check for RMW races
@ -207,18 +198,13 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
this.inner.start();
[
TimerChannel::Ch1,
TimerChannel::Ch2,
TimerChannel::Ch3,
TimerChannel::Ch4,
]
.iter()
.for_each(|&channel| {
this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1);
[Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
.iter()
.for_each(|&channel| {
this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1);
this.inner.set_output_compare_preload(channel, true);
});
this.inner.set_output_compare_preload(channel, true);
});
this
}
@ -226,7 +212,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
/// Get a single channel
///
/// If you need to use multiple channels, use [`Self::split`].
pub fn channel(&mut self, channel: TimerChannel) -> SimplePwmChannel<'_, T> {
pub fn channel(&mut self, channel: Channel) -> SimplePwmChannel<'_, T> {
SimplePwmChannel {
timer: unsafe { self.inner.clone_unchecked() },
channel,
@ -239,7 +225,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
///
/// If you need to use multiple channels, use [`Self::split`].
pub fn ch1(&mut self) -> SimplePwmChannel<'_, T> {
self.channel(TimerChannel::Ch1)
self.channel(Channel::Ch1)
}
/// Channel 2
@ -248,7 +234,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
///
/// If you need to use multiple channels, use [`Self::split`].
pub fn ch2(&mut self) -> SimplePwmChannel<'_, T> {
self.channel(TimerChannel::Ch2)
self.channel(Channel::Ch2)
}
/// Channel 3
@ -257,7 +243,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
///
/// If you need to use multiple channels, use [`Self::split`].
pub fn ch3(&mut self) -> SimplePwmChannel<'_, T> {
self.channel(TimerChannel::Ch3)
self.channel(Channel::Ch3)
}
/// Channel 4
@ -266,7 +252,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
///
/// If you need to use multiple channels, use [`Self::split`].
pub fn ch4(&mut self) -> SimplePwmChannel<'_, T> {
self.channel(TimerChannel::Ch4)
self.channel(Channel::Ch4)
}
/// Splits a [`SimplePwm`] into four pwm channels.
@ -288,10 +274,10 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
};
SimplePwmChannels {
ch1: ch(TimerChannel::Ch1),
ch2: ch(TimerChannel::Ch2),
ch3: ch(TimerChannel::Ch3),
ch4: ch(TimerChannel::Ch4),
ch1: ch(Channel::Ch1),
ch2: ch(Channel::Ch2),
ch3: ch(Channel::Ch3),
ch4: ch(Channel::Ch4),
}
}
@ -322,7 +308,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
///
/// Note:
/// you will need to provide corresponding TIMx_UP DMA channel to use this method.
pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: TimerChannel, duty: &[u16]) {
pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) {
#[allow(clippy::let_unit_value)] // eg. stm32f334
let req = dma.request();
@ -405,8 +391,8 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
pub async fn waveform_up_multi_channel(
&mut self,
dma: Peri<'_, impl super::UpDma<T>>,
starting_channel: TimerChannel,
ending_channel: TimerChannel,
starting_channel: Channel,
ending_channel: Channel,
duty: &[u16],
) {
let cr1_addr = self.inner.regs_gp16().cr1().as_ptr() as u32;
@ -462,106 +448,97 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
}
}
macro_rules! impl_waveform_chx {
($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => {
impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
/// Generate a sequence of PWM waveform
pub async fn $fn_name(&mut self, dma: Peri<'_, impl super::$dma_ch<T, $cc_ch>>, duty: &[u16]) {
use crate::pac::timer::vals::Ccds;
impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
/// Generate a sequence of PWM waveform
pub async fn waveform<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) {
use crate::pac::timer::vals::Ccds;
#[allow(clippy::let_unit_value)] // eg. stm32f334
let req = dma.request();
#[allow(clippy::let_unit_value)] // eg. stm32f334
let req = dma.request();
let cc_channel = TimerChannel::$cc_ch;
let cc_channel = C::CHANNEL;
let original_duty_state = self.channel(cc_channel).current_duty_cycle();
let original_enable_state = self.channel(cc_channel).is_enabled();
let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ON_UPDATE;
let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel);
let original_duty_state = self.channel(cc_channel).current_duty_cycle();
let original_enable_state = self.channel(cc_channel).is_enabled();
let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ON_UPDATE;
let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel);
// redirect CC DMA request onto Update Event
if !original_cc_dma_on_update {
self.inner.set_cc_dma_selection(Ccds::ON_UPDATE)
}
if !original_cc_dma_enabled {
self.inner.set_cc_dma_enable_state(cc_channel, true);
}
if !original_enable_state {
self.channel(cc_channel).enable();
}
unsafe {
#[cfg(not(any(bdma, gpdma)))]
use crate::dma::{Burst, FifoThreshold};
use crate::dma::{Transfer, TransferOptions};
let dma_transfer_option = TransferOptions {
#[cfg(not(any(bdma, gpdma)))]
fifo_threshold: Some(FifoThreshold::Full),
#[cfg(not(any(bdma, gpdma)))]
mburst: Burst::Incr8,
..Default::default()
};
match self.inner.bits() {
TimerBits::Bits16 => {
Transfer::new_write(
dma,
req,
duty,
self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u16,
dma_transfer_option,
)
.await
}
#[cfg(not(any(stm32l0)))]
TimerBits::Bits32 => {
#[cfg(not(any(bdma, gpdma)))]
panic!("unsupported timer bits");
#[cfg(any(bdma, gpdma))]
Transfer::new_write(
dma,
req,
duty,
self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u32,
dma_transfer_option,
)
.await
}
};
};
// restore output compare state
if !original_enable_state {
self.channel(cc_channel).disable();
}
self.channel(cc_channel).set_duty_cycle(original_duty_state);
// Since DMA is closed before timer Capture Compare Event trigger DMA is turn off,
// this can almost always trigger a DMA FIFO error.
//
// optional TODO:
// clean FEIF after disable UDE
if !original_cc_dma_enabled {
self.inner.set_cc_dma_enable_state(cc_channel, false);
}
if !original_cc_dma_on_update {
self.inner.set_cc_dma_selection(Ccds::ON_COMPARE)
}
}
// redirect CC DMA request onto Update Event
if !original_cc_dma_on_update {
self.inner.set_cc_dma_selection(Ccds::ON_UPDATE)
}
};
}
impl_waveform_chx!(waveform_ch1, Dma, Ch1);
impl_waveform_chx!(waveform_ch2, Dma, Ch2);
impl_waveform_chx!(waveform_ch3, Dma, Ch3);
impl_waveform_chx!(waveform_ch4, Dma, Ch4);
if !original_cc_dma_enabled {
self.inner.set_cc_dma_enable_state(cc_channel, true);
}
if !original_enable_state {
self.channel(cc_channel).enable();
}
unsafe {
#[cfg(not(any(bdma, gpdma)))]
use crate::dma::{Burst, FifoThreshold};
use crate::dma::{Transfer, TransferOptions};
let dma_transfer_option = TransferOptions {
#[cfg(not(any(bdma, gpdma)))]
fifo_threshold: Some(FifoThreshold::Full),
#[cfg(not(any(bdma, gpdma)))]
mburst: Burst::Incr8,
..Default::default()
};
match self.inner.bits() {
TimerBits::Bits16 => {
Transfer::new_write(
dma,
req,
duty,
self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u16,
dma_transfer_option,
)
.await
}
#[cfg(not(any(stm32l0)))]
TimerBits::Bits32 => {
#[cfg(not(any(bdma, gpdma)))]
panic!("unsupported timer bits");
#[cfg(any(bdma, gpdma))]
Transfer::new_write(
dma,
req,
duty,
self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u32,
dma_transfer_option,
)
.await
}
};
};
// restore output compare state
if !original_enable_state {
self.channel(cc_channel).disable();
}
self.channel(cc_channel).set_duty_cycle(original_duty_state);
// Since DMA is closed before timer Capture Compare Event trigger DMA is turn off,
// this can almost always trigger a DMA FIFO error.
//
// optional TODO:
// clean FEIF after disable UDE
if !original_cc_dma_enabled {
self.inner.set_cc_dma_enable_state(cc_channel, false);
}
if !original_cc_dma_on_update {
self.inner.set_cc_dma_selection(Ccds::ON_COMPARE)
}
}
}
impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePwmChannel<'d, T> {
type Error = core::convert::Infallible;
@ -599,7 +576,7 @@ impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::SetDutyCycle for Simpl
}
impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> {
type Channel = TimerChannel;
type Channel = Channel;
type Time = Hertz;
type Duty = u32;