From 9f4af99b576324208eb70206564200e0aff926ee Mon Sep 17 00:00:00 2001 From: anton smeenk Date: Fri, 10 Nov 2023 16:32:37 +0100 Subject: [PATCH] Removed global static signal and added signal to interrupt state. Nice: signaling can be done in immutable environment. Added extra pin to test to be able to measure with logic scope --- embassy-stm32/src/timer/mod.rs | 27 +++++++++++++++++++ embassy-stm32/src/timer/simple_pwm.rs | 12 +++------ .../stm32g0/src/bin/pwm_interrupt_blinky.rs | 20 +++++++++++--- 3 files changed, 47 insertions(+), 12 deletions(-) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 913bfed2..81950e4e 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -2,12 +2,24 @@ pub mod complementary_pwm; pub mod qei; pub mod simple_pwm; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::signal::Signal; use stm32_metapac::timer::vals; use crate::interrupt; use crate::rcc::RccPeripheral; use crate::time::Hertz; +pub struct State { + signal: Signal, +} + +impl State { + pub(crate) const fn new() -> Self { + Self { signal: Signal::new() } + } +} + #[cfg(feature = "unstable-pac")] pub mod low_level { pub use super::sealed::*; @@ -91,6 +103,7 @@ pub(crate) mod sealed { pub trait GeneralPurpose16bitInstance: Basic16bitInstance { fn regs_gp16() -> crate::pac::timer::TimGp16; + fn state() -> &'static State; fn set_counting_mode(&mut self, mode: CountingMode) { let (cms, dir) = mode.into(); @@ -510,6 +523,11 @@ foreach_interrupt! { fn regs_gp16() -> crate::pac::timer::TimGp16 { crate::pac::$inst } + fn state() -> &'static State { + static STATE: State = State::new(); + &STATE + } + } }; @@ -528,6 +546,11 @@ foreach_interrupt! { fn regs_gp16() -> crate::pac::timer::TimGp16 { unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } } + fn state() -> &'static State { + static STATE: State = State::new(); + &STATE + } + } }; @@ -551,6 +574,10 @@ foreach_interrupt! { fn regs_gp16() -> crate::pac::timer::TimGp16 { unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } } + fn state() -> &'static State { + static STATE: State = State::new(); + &STATE + } } impl sealed::AdvancedControlInstance for crate::peripherals::$inst { diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 04aaf108..5e212c75 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -1,8 +1,7 @@ +use core::future::Future; use core::marker::PhantomData; use embassy_hal_internal::{into_ref, PeripheralRef}; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use embassy_sync::signal::Signal; use super::*; #[allow(unused_imports)] @@ -12,9 +11,6 @@ use crate::time::Hertz; use crate::Peripheral; use crate::_generated::interrupt::typelevel::Interrupt; -// Declare a signal to awake user code for signaling the update interrupt id happen -static SIGNAL_UPDATE: Signal = Signal::new(); - pub struct InterruptHandler { _phantom: PhantomData, } @@ -24,7 +20,7 @@ impl interrupt::typelevel::Handler let regs = T::regs(); let sr = regs.sr().read(); if sr.uif() { - SIGNAL_UPDATE.signal(0); + T::state().signal.signal(0); // clear the flag critical_section::with(|_| { regs.sr().modify(|w| w.set_uif(false)); @@ -137,8 +133,8 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { self.inner.enable_update_interrupt(enable); } - pub async fn wait_update_interrupt(&self) { - _ = SIGNAL_UPDATE.wait().await; + pub fn wait_update_interrupt(&self) -> impl Future { + T::state().signal.wait() } pub fn set_duty(&mut self, channel: Channel, duty: u16) { diff --git a/examples/stm32g0/src/bin/pwm_interrupt_blinky.rs b/examples/stm32g0/src/bin/pwm_interrupt_blinky.rs index 9eaaa1d6..c289b661 100644 --- a/examples/stm32g0/src/bin/pwm_interrupt_blinky.rs +++ b/examples/stm32g0/src/bin/pwm_interrupt_blinky.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, OutputType, Speed}; -use embassy_stm32::peripherals::PA5; +use embassy_stm32::peripherals::{PA5, PB4}; use embassy_stm32::time::Hertz; use embassy_stm32::timer::simple_pwm::{InterruptHandler, PwmPin, SimplePwm}; use embassy_stm32::timer::{self, Channel}; @@ -14,8 +14,10 @@ use {defmt_rtt as _, panic_probe as _}; // This test is meant for the target nucleo G070 RB // On arduino pin d4 (pb5) a pwm signal of about 0.3 hz can me measured. -// Attach a led and a resistor of 330 ohm in series to watch the pwm +// On arduino pin d5 (pb4) a sync pulse high for 1 ms after each interrupt. +// With a logic scope one can measure the syncing // The user led arduino pin d13 (pa5) will flash with exactly 1 hrz. +// 390 us after the pwm going up (causing the update interrupt) the task is awoken in line 67. bind_interrupts!( struct Irqs { @@ -31,13 +33,18 @@ async fn pwm_task(mut pwm_test: PwmTest) { pub struct PwmTest { pwm3: SimplePwm<'static, peripherals::TIM3>, led: Output<'static, PA5>, + d5_pb4: Output<'static, PB4>, max3: u16, duty: u16, counter: usize, } impl PwmTest { - fn new(mut pwm3: SimplePwm<'static, peripherals::TIM3>, led: Output<'static, PA5>) -> Self { + fn new( + mut pwm3: SimplePwm<'static, peripherals::TIM3>, + led: Output<'static, PA5>, + d5_pb4: Output<'static, PB4>, + ) -> Self { let max3 = pwm3.get_max_duty(); pwm3.enable(timer::Channel::Ch2); pwm3.enable_update_interrupt(true); @@ -47,6 +54,7 @@ impl PwmTest { duty: 0, counter: 0, led, + d5_pb4, } } async fn task(&mut self) { @@ -56,11 +64,14 @@ impl PwmTest { // note that the update interrupt will be call exact 100 times per second! self.pwm3.wait_update_interrupt().await; self.counter = (self.counter + 1) % 100; + self.d5_pb4.set_high(); match self.counter { 10 => self.led.set_high(), 30 => self.led.set_low(), _ => (), } + Timer::after_millis(1).await; + self.d5_pb4.set_low(); } } } @@ -80,7 +91,8 @@ async fn main(spawner: Spawner) { embassy_stm32::timer::CountingMode::EdgeAlignedUp, ); let led_g = Output::new(p.PA5, Level::High, Speed::Low); - let pwm_test = PwmTest::new(pwm3, led_g); + let d5_pb4 = Output::new(p.PB4, Level::High, Speed::Low); + let pwm_test = PwmTest::new(pwm3, led_g, d5_pb4); // note that at the end the pwmTest task is the owner of pwmTest. // PwmTest is the owner of the pwm and the led. spawner.spawn(pwm_task(pwm_test)).unwrap();