Added a pwm update event interrupt and one test to show the functionality
This commit is contained in:
parent
6ff91851b1
commit
17ab454c8e
@ -1,6 +1,8 @@
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||||
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
|
use embassy_sync::signal::Signal;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
@ -8,6 +10,28 @@ use crate::gpio::sealed::{AFType, Pin};
|
|||||||
use crate::gpio::{AnyPin, OutputType};
|
use crate::gpio::{AnyPin, OutputType};
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
use crate::Peripheral;
|
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<CriticalSectionRawMutex, usize> = Signal::new();
|
||||||
|
|
||||||
|
pub struct InterruptHandler<T: CaptureCompare16bitInstance> {
|
||||||
|
_phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: CaptureCompare16bitInstance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
|
unsafe fn on_interrupt() {
|
||||||
|
let regs = T::regs();
|
||||||
|
let sr = regs.sr().read();
|
||||||
|
if sr.uif() {
|
||||||
|
SIGNAL_UPDATE.signal(0);
|
||||||
|
// clear the flag
|
||||||
|
critical_section::with(|_| {
|
||||||
|
regs.sr().modify(|w| w.set_uif(false));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Ch1;
|
pub struct Ch1;
|
||||||
pub struct Ch2;
|
pub struct Ch2;
|
||||||
@ -82,6 +106,9 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
|
|||||||
.set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
|
.set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
|
||||||
this.inner
|
this.inner
|
||||||
.set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
|
.set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
|
||||||
|
|
||||||
|
T::Interrupt::unpend();
|
||||||
|
unsafe { T::Interrupt::enable() };
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,6 +133,14 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
|
|||||||
self.inner.get_max_compare_value() + 1
|
self.inner.get_max_compare_value() + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn enable_update_interrupt(&mut self, enable: bool) {
|
||||||
|
self.inner.enable_update_interrupt(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn wait_update_interrupt(&self) {
|
||||||
|
_ = SIGNAL_UPDATE.wait().await;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_duty(&mut self, channel: Channel, duty: u16) {
|
pub fn set_duty(&mut self, channel: Channel, duty: u16) {
|
||||||
assert!(duty <= self.get_max_duty());
|
assert!(duty <= self.get_max_duty());
|
||||||
self.inner.set_compare_value(channel, duty)
|
self.inner.set_compare_value(channel, duty)
|
||||||
|
43
examples/stm32g0/Embed.toml
Normal file
43
examples/stm32g0/Embed.toml
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
[default.probe]
|
||||||
|
protocol = "Swd"
|
||||||
|
# USB vendor ID
|
||||||
|
# usb_vid = "6790"
|
||||||
|
# USB product ID
|
||||||
|
# usb_pid = "29987"
|
||||||
|
|
||||||
|
[default.flashing]
|
||||||
|
enabled = true
|
||||||
|
|
||||||
|
[default.reset]
|
||||||
|
# Whether or not the target should be reset.
|
||||||
|
# When flashing is enabled as well, the target will be reset after flashing.
|
||||||
|
enabled = true
|
||||||
|
# Whether or not the target should be halted after reset.
|
||||||
|
halt_afterwards = false
|
||||||
|
|
||||||
|
[default.general]
|
||||||
|
# The chip name of the chip to be debugged.
|
||||||
|
#chip = "STM32G030J6Mx"
|
||||||
|
chip = "STM32G070CBTx"
|
||||||
|
# A list of chip descriptions to be loaded during runtime.
|
||||||
|
chip_descriptions = []
|
||||||
|
# The default log level to be used.
|
||||||
|
log_level = "Warn"
|
||||||
|
|
||||||
|
[default.rtt]
|
||||||
|
enabled = false
|
||||||
|
# A list of channel associations to be displayed. If left empty, all channels are displayed.
|
||||||
|
channels = [
|
||||||
|
# { up = 0, down = 0, name = "name" }
|
||||||
|
]
|
||||||
|
# The duration in ms for which the logger should retry to attach to RTT.
|
||||||
|
timeout = 3000
|
||||||
|
# Whether timestamps in the RTTUI are enabled
|
||||||
|
show_timestamps = true
|
||||||
|
|
||||||
|
[default.gdb]
|
||||||
|
# Whether or not a GDB server should be opened after flashing.
|
||||||
|
# This is exclusive and cannot be used with RTT at the moment.
|
||||||
|
enabled = false
|
||||||
|
# The connection string in host:port format wher the GDB server will open a socket.
|
||||||
|
# gdb_connection_string
|
95
examples/stm32g0/src/bin/pwm_interrupt_blinky.rs
Normal file
95
examples/stm32g0/src/bin/pwm_interrupt_blinky.rs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
use defmt::*;
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_stm32::gpio::{Level, Output, OutputType, Speed};
|
||||||
|
use embassy_stm32::peripherals::PA5;
|
||||||
|
use embassy_stm32::time::Hertz;
|
||||||
|
use embassy_stm32::timer::simple_pwm::{InterruptHandler, PwmPin, SimplePwm};
|
||||||
|
use embassy_stm32::timer::{self, Channel};
|
||||||
|
use embassy_stm32::{bind_interrupts, peripherals};
|
||||||
|
use embassy_time::Timer;
|
||||||
|
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
|
||||||
|
// The user led arduino pin d13 (pa5) will flash with exactly 1 hrz.
|
||||||
|
|
||||||
|
bind_interrupts!(
|
||||||
|
struct Irqs {
|
||||||
|
TIM3 => InterruptHandler<peripherals::TIM3>;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn pwm_task(mut pwm_test: PwmTest) {
|
||||||
|
pwm_test.task().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PwmTest {
|
||||||
|
pwm3: SimplePwm<'static, peripherals::TIM3>,
|
||||||
|
led: Output<'static, PA5>,
|
||||||
|
max3: u16,
|
||||||
|
duty: u16,
|
||||||
|
counter: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PwmTest {
|
||||||
|
fn new(mut pwm3: SimplePwm<'static, peripherals::TIM3>, led: Output<'static, PA5>) -> Self {
|
||||||
|
let max3 = pwm3.get_max_duty();
|
||||||
|
pwm3.enable(timer::Channel::Ch2);
|
||||||
|
pwm3.enable_update_interrupt(true);
|
||||||
|
PwmTest {
|
||||||
|
pwm3,
|
||||||
|
max3,
|
||||||
|
duty: 0,
|
||||||
|
counter: 0,
|
||||||
|
led,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async fn task(&mut self) {
|
||||||
|
loop {
|
||||||
|
self.duty = (self.duty + 200) % self.max3;
|
||||||
|
self.pwm3.set_duty(Channel::Ch2, self.duty);
|
||||||
|
// 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;
|
||||||
|
match self.counter {
|
||||||
|
10 => self.led.set_high(),
|
||||||
|
30 => self.led.set_low(),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(spawner: Spawner) {
|
||||||
|
let p = embassy_stm32::init(Default::default());
|
||||||
|
info!("Hello World!");
|
||||||
|
let d4_pb5 = PwmPin::new_ch2(p.PB5, OutputType::PushPull);
|
||||||
|
let pwm3 = SimplePwm::<'static>::new(
|
||||||
|
p.TIM3,
|
||||||
|
None,
|
||||||
|
Some(d4_pb5),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
Hertz(100),
|
||||||
|
embassy_stm32::timer::CountingMode::EdgeAlignedUp,
|
||||||
|
);
|
||||||
|
let led_g = Output::new(p.PA5, Level::High, Speed::Low);
|
||||||
|
let pwm_test = PwmTest::new(pwm3, led_g);
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
info!("high");
|
||||||
|
Timer::after_millis(300).await;
|
||||||
|
|
||||||
|
info!("low");
|
||||||
|
Timer::after_millis(300).await;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user