diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs index a1c1486f9..0258d4077 100644 --- a/embassy-stm32/src/timer/input_capture.rs +++ b/embassy-stm32/src/timer/input_capture.rs @@ -7,7 +7,7 @@ use core::task::{Context, Poll}; use embassy_hal_internal::{into_ref, PeripheralRef}; -use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, Timer}; +use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer}; use super::{ CaptureCompareInterruptHandler, Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel, @@ -40,11 +40,9 @@ macro_rules! channel_impl { #[doc = concat!("Create a new ", stringify!($channel), " capture pin instance.")] pub fn $new_chx(pin: impl Peripheral
> + 'd, pull_type: Pull) -> Self {
into_ref!(pin);
- critical_section::with(|_| {
- pin.set_as_af_pull(pin.af_num(), AFType::Input, pull_type);
- #[cfg(gpio_v2)]
- pin.set_speed(crate::gpio::Speed::VeryHigh);
- });
+
+ pin.set_as_af_pull(pin.af_num(), AFType::Input, pull_type);
+
CapturePin {
_pin: pin.map_into(),
phantom: PhantomData,
@@ -83,7 +81,7 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
let mut this = Self { inner: Timer::new(tim) };
this.inner.set_counting_mode(counting_mode);
- this.set_tick_freq(freq);
+ this.inner.set_tick_freq(freq);
this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
this.inner.start();
@@ -109,24 +107,6 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
self.inner.get_channel_enable_state(channel)
}
- /// Set tick frequency.
- ///
- /// Note: when you call this, the max period value changes
- pub fn set_tick_freq(&mut self, freq: Hertz) {
- let f = freq;
- assert!(f.0 > 0);
- let timer_f = self.inner.get_clock_frequency();
-
- let pclk_ticks_per_timer_period = timer_f / f;
- let psc: u16 = unwrap!((pclk_ticks_per_timer_period - 1).try_into());
-
- let regs = self.inner.regs_core();
- regs.psc().write_value(psc);
-
- // Generate an Update Request
- regs.egr().write(|r| r.set_ug(true));
- }
-
/// Set the input capture mode for a given channel.
pub fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
self.inner.set_input_capture_mode(channel, mode);
@@ -148,10 +128,13 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
}
fn new_future(&self, channel: Channel, mode: InputCaptureMode, tisel: InputTISelection) -> InputCaptureFuture + 'd,
+ pin: impl Peripheral > + 'd,
+ pull_type: Pull,
+ freq: Hertz,
+ ) -> Self {
+ into_ref!(pin);
+
+ pin.set_as_af_pull(pin.af_num(), AFType::Input, pull_type);
+
+ Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2)
+ }
+
+ /// Create a new PWM input driver.
+ pub fn new_alt(
+ tim: impl Peripheral + 'd,
+ pin: impl Peripheral > + 'd,
+ pull_type: Pull,
+ freq: Hertz,
+ ) -> Self {
+ into_ref!(pin);
+
+ pin.set_as_af_pull(pin.af_num(), AFType::Input, pull_type);
+
+ Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1)
+ }
+
+ fn new_inner(tim: impl Peripheral + 'd, freq: Hertz, ch1: Channel, ch2: Channel) -> Self {
+ let mut inner = Timer::new(tim);
+
+ inner.set_counting_mode(CountingMode::EdgeAlignedUp);
+ inner.set_tick_freq(freq);
+ inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
+ inner.start();
+
+ // Configuration steps from ST RM0390 (STM32F446) chapter 17.3.6
+ // or ST RM0008 (STM32F103) chapter 15.3.6 Input capture mode
+ inner.set_input_ti_selection(ch1, InputTISelection::Normal);
+ inner.set_input_capture_mode(ch1, InputCaptureMode::Rising);
+
+ inner.set_input_ti_selection(ch2, InputTISelection::Alternate);
+ inner.set_input_capture_mode(ch2, InputCaptureMode::Falling);
+
+ inner.set_trigger_source(match ch1 {
+ Channel::Ch1 => TriggerSource::TI1FP1,
+ Channel::Ch2 => TriggerSource::TI2FP2,
+ _ => panic!("Invalid channel for PWM input"),
+ });
+
+ inner.set_slave_mode(SlaveMode::RESET_MODE);
+
+ // Must call the `enable` function after
+
+ Self { channel: ch1, inner }
+ }
+
+ /// Enable the given channel.
+ pub fn enable(&mut self) {
+ 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(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(Channel::Ch1)
+ }
+
+ /// Get the period tick count
+ pub fn get_period_ticks(&self) -> u32 {
+ self.inner.get_capture_value(self.channel)
+ }
+
+ /// Get the pulse width tick count
+ pub fn get_width_ticks(&self) -> u32 {
+ self.inner.get_capture_value(match self.channel {
+ Channel::Ch1 => Channel::Ch2,
+ Channel::Ch2 => Channel::Ch1,
+ _ => panic!("Invalid channel for PWM input"),
+ })
+ }
+
+ /// Get the duty cycle in 100%
+ pub fn get_duty_cycle(&self) -> f32 {
+ let period = self.get_period_ticks();
+ if period == 0 {
+ return 0.;
+ }
+ 100. * (self.get_width_ticks() as f32) / (period as f32)
+ }
+}
diff --git a/examples/stm32f1/src/bin/input_capture.rs b/examples/stm32f1/src/bin/input_capture.rs
new file mode 100644
index 000000000..5e2dab9e6
--- /dev/null
+++ b/examples/stm32f1/src/bin/input_capture.rs
@@ -0,0 +1,52 @@
+#![no_std]
+#![no_main]
+
+use defmt::*;
+use embassy_executor::Spawner;
+use embassy_stm32::gpio::{Level, Output, Pull, Speed};
+use embassy_stm32::time::khz;
+use embassy_stm32::timer::input_capture::{CapturePin, InputCapture};
+use embassy_stm32::timer::{self, Channel};
+use embassy_stm32::{bind_interrupts, peripherals};
+use embassy_time::Timer;
+use {defmt_rtt as _, panic_probe as _};
+
+/// Connect PA2 and PC13 with a 1k Ohm resistor
+
+#[embassy_executor::task]
+async fn blinky(led: peripherals::PC13) {
+ let mut led = Output::new(led, Level::High, Speed::Low);
+
+ loop {
+ info!("high");
+ led.set_high();
+ Timer::after_millis(300).await;
+
+ info!("low");
+ led.set_low();
+ Timer::after_millis(300).await;
+ }
+}
+
+bind_interrupts!(struct Irqs {
+ TIM2 => timer::CaptureCompareInterruptHandler