diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs index 000938a70..b3434ae63 100644 --- a/embassy-stm32/src/timer/input_capture.rs +++ b/embassy-stm32/src/timer/input_capture.rs @@ -80,18 +80,18 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> { } fn new_inner(tim: impl Peripheral
+ 'd, freq: Hertz, counting_mode: CountingMode) -> Self {
- let mut this = Self { inner: Timer::new(tim) };
+ let mut inner = Timer::new(tim);
- this.inner.set_counting_mode(counting_mode);
- this.set_tick_freq(freq);
- this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
- this.inner.start();
+ inner.set_counting_mode(counting_mode);
+ inner.set_tick_freq(freq);
+ inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
+ inner.start();
// enable NVIC interrupt
T::CaptureCompareInterrupt::unpend();
unsafe { T::CaptureCompareInterrupt::enable() };
- this
+ Self { inner }
}
/// Enable the given channel.
@@ -109,24 +109,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);
@@ -150,7 +132,8 @@ 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);
+ 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);
+ });
+
+ Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2)
+ }
+
+ /// Create a new input capture driver.
+ pub fn new_alt(
+ tim: impl Peripheral + 'd,
+ pin: impl Peripheral > + 'd,
+ pull_type: Pull,
+ freq: Hertz,
+ ) -> 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);
+ });
+
+ Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1)
+ }
+
+ fn new_inner(tim: impl Peripheral + 'd, freq: Hertz, ch1: Channel, ch2: Channel) -> Self {
+ use stm32_metapac::timer::vals::{Sms, Ts};
+
+ 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);
+
+ let regs = regs_gp16(T::regs());
+ regs.smcr().modify(|r| {
+ // Select the valid trigger input: write the TS bits to 101 in the TIMx_SMCR register
+ // (TI1FP1 selected).
+ r.set_ts(match ch1 {
+ Channel::Ch1 => Ts::TI1FP1,
+ Channel::Ch2 => Ts::TI2FP2,
+ _ => panic!("Invalid channel for PWM input"),
+ });
+
+ // Configure the slave mode controller in reset mode: write the SMS bits to 100 in the
+ // TIMx_SMCR register.
+ r.set_sms(Sms::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 duty tick count
+ pub fn get_duty_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_duty_ticks() as f32) / (period as f32)
+ }
+}
diff --git a/examples/stm32f1/.vscode/launch.json b/examples/stm32f1/.vscode/launch.json
index 7d1504a39..998508867 100644
--- a/examples/stm32f1/.vscode/launch.json
+++ b/examples/stm32f1/.vscode/launch.json
@@ -15,7 +15,7 @@
"cwd": "${workspaceRoot}",
"preLaunchTask": "Cargo Build (debug)",
"runToEntryPoint": "main",
- "executable": "./target/thumbv7m-none-eabi/debug/input_capture",
+ "executable": "./target/thumbv7m-none-eabi/debug/pwm_input",
/* Run `cargo build --example itm` and uncomment this line to run itm example */
// "executable": "./target/thumbv7em-none-eabihf/debug/examples/itm",
"device": "STM32F103TB",
diff --git a/examples/stm32f1/.vscode/tasks.json b/examples/stm32f1/.vscode/tasks.json
index e153722da..de7013b12 100644
--- a/examples/stm32f1/.vscode/tasks.json
+++ b/examples/stm32f1/.vscode/tasks.json
@@ -9,7 +9,7 @@
],
"args": [
"--bin",
- "input_capture"
+ "pwm_input"
],
"group": {
"kind": "build",
diff --git a/examples/stm32f1/src/bin/pwm_input.rs b/examples/stm32f1/src/bin/pwm_input.rs
new file mode 100644
index 000000000..14978f817
--- /dev/null
+++ b/examples/stm32f1/src/bin/pwm_input.rs
@@ -0,0 +1,50 @@
+#![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::{self, pwm_input::PwmInput};
+use embassy_stm32::{bind_interrupts, peripherals};
+use embassy_time::Timer;
+use {defmt_rtt as _, panic_probe as _};
+
+/// Connect PB2 and PB10 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