From e056bedd553e7fbc7d28f8f516c87fcd12859aef Mon Sep 17 00:00:00 2001 From: Matous Hybl Date: Wed, 8 Dec 2021 17:39:59 +0100 Subject: [PATCH] Port the PWM example to H7, add low-level API example implementing 32-bit PWM. --- examples/stm32g4/src/bin/pwm.rs | 4 +- examples/stm32h7/Cargo.toml | 3 +- .../stm32h7/src/bin/low_level_timer_api.rs | 147 ++++++++++++++++++ examples/stm32h7/src/bin/pwm.rs | 48 ++++++ 4 files changed, 199 insertions(+), 3 deletions(-) create mode 100644 examples/stm32h7/src/bin/low_level_timer_api.rs create mode 100644 examples/stm32h7/src/bin/pwm.rs diff --git a/examples/stm32g4/src/bin/pwm.rs b/examples/stm32g4/src/bin/pwm.rs index 1aa7b85f3..3dd45318d 100644 --- a/examples/stm32g4/src/bin/pwm.rs +++ b/examples/stm32g4/src/bin/pwm.rs @@ -7,7 +7,7 @@ mod example_common; use embassy::executor::Spawner; use embassy::time::{Duration, Timer}; use embassy_stm32::gpio::NoPin; -use embassy_stm32::pwm::{Channel, Pwm}; +use embassy_stm32::pwm::{simple_pwm::SimplePwm, Channel}; use embassy_stm32::time::U32Ext; use embassy_stm32::Peripherals; use example_common::*; @@ -16,7 +16,7 @@ use example_common::*; async fn main(_spawner: Spawner, p: Peripherals) { info!("Hello World!"); - let mut pwm = Pwm::new(p.TIM2, p.PA5, NoPin, NoPin, NoPin, 10000.hz()); + let mut pwm = SimplePwm::new(p.TIM2, p.PA5, NoPin, NoPin, NoPin, 10000.hz()); let max = pwm.get_max_duty(); pwm.enable(Channel::Ch1); diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index a34ac6ad9..de294318f 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -10,8 +10,9 @@ resolver = "2" [dependencies] embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt"] } embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] } -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743zi", "net", "time-driver-tim2", "exti"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743zi", "net", "time-driver-tim2", "exti", "unstable-pac"] } embassy-net = { path = "../../embassy-net", default-features = false, features = ["defmt", "tcp", "medium-ethernet", "pool-16"] } +embassy-hal-common = { path = "../../embassy-hal-common", default-features = false, features = ["defmt"] } defmt = "0.3" defmt-rtt = "0.3" diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs new file mode 100644 index 000000000..2640f249d --- /dev/null +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs @@ -0,0 +1,147 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use core::marker::PhantomData; + +use embassy::executor::Spawner; +use embassy::time::{Duration, Timer}; +use embassy::util::Unborrow; +use embassy_hal_common::unborrow; +use embassy_stm32::gpio::NoPin; +use embassy_stm32::pwm::{pins::*, Channel, OutputCompareMode}; +use embassy_stm32::time::{Hertz, U32Ext}; +use embassy_stm32::timer::GeneralPurpose32bitInstance; +use embassy_stm32::{Config, Peripherals}; +use example_common::*; + +pub fn config() -> Config { + let mut config = Config::default(); + config.rcc.sys_ck = Some(400.mhz().into()); + config.rcc.hclk = Some(400.mhz().into()); + config.rcc.pll1.q_ck = Some(100.mhz().into()); + config.rcc.pclk1 = Some(100.mhz().into()); + config.rcc.pclk2 = Some(100.mhz().into()); + config.rcc.pclk3 = Some(100.mhz().into()); + config.rcc.pclk4 = Some(100.mhz().into()); + config +} + +#[embassy::main(config = "config()")] +async fn main(_spawner: Spawner, p: Peripherals) { + info!("Hello World!"); + + let mut pwm = SimplePwm32::new(p.TIM5, p.PA0, NoPin, NoPin, NoPin, 10000.hz()); + let max = pwm.get_max_duty(); + pwm.enable(Channel::Ch1); + + info!("PWM initialized"); + info!("PWM max duty {}", max); + + loop { + pwm.set_duty(Channel::Ch1, 0); + Timer::after(Duration::from_millis(300)).await; + pwm.set_duty(Channel::Ch1, max / 4); + Timer::after(Duration::from_millis(300)).await; + pwm.set_duty(Channel::Ch1, max / 2); + Timer::after(Duration::from_millis(300)).await; + pwm.set_duty(Channel::Ch1, max - 1); + Timer::after(Duration::from_millis(300)).await; + } +} +pub struct SimplePwm32<'d, T: GeneralPurpose32bitInstance> { + phantom: PhantomData<&'d mut T>, + inner: T, +} + +impl<'d, T: GeneralPurpose32bitInstance> SimplePwm32<'d, T> { + pub fn new>( + tim: impl Unborrow + 'd, + ch1: impl Unborrow> + 'd, + ch2: impl Unborrow> + 'd, + ch3: impl Unborrow> + 'd, + ch4: impl Unborrow> + 'd, + freq: F, + ) -> Self { + unborrow!(tim, ch1, ch2, ch3, ch4); + + T::enable(); + ::reset(); + + unsafe { + ch1.configure(); + ch2.configure(); + ch3.configure(); + ch4.configure(); + } + + let mut this = Self { + inner: tim, + phantom: PhantomData, + }; + + this.set_freq(freq); + this.inner.start(); + + unsafe { + this.inner + .regs_gp32() + .ccmr_output(0) + .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); + this.inner + .regs_gp32() + .ccmr_output(0) + .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into())); + this.inner + .regs_gp32() + .ccmr_output(1) + .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); + this.inner + .regs_gp32() + .ccmr_output(1) + .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into())); + } + this + } + + pub fn enable(&mut self, channel: Channel) { + unsafe { + self.inner + .regs_gp32() + .ccer() + .modify(|w| w.set_cce(channel.raw(), true)); + } + } + + pub fn disable(&mut self, channel: Channel) { + unsafe { + self.inner + .regs_gp32() + .ccer() + .modify(|w| w.set_cce(channel.raw(), false)); + } + } + + pub fn set_freq>(&mut self, freq: F) { + ::set_frequency( + &mut self.inner, + freq, + ); + } + + pub fn get_max_duty(&self) -> u32 { + unsafe { self.inner.regs_gp32().arr().read().arr() } + } + + pub fn set_duty(&mut self, channel: Channel, duty: u32) { + defmt::assert!(duty < self.get_max_duty()); + unsafe { + self.inner + .regs_gp32() + .ccr(channel.raw()) + .modify(|w| w.set_ccr(duty)) + } + } +} diff --git a/examples/stm32h7/src/bin/pwm.rs b/examples/stm32h7/src/bin/pwm.rs new file mode 100644 index 000000000..020150a39 --- /dev/null +++ b/examples/stm32h7/src/bin/pwm.rs @@ -0,0 +1,48 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use embassy::executor::Spawner; +use embassy::time::{Duration, Timer}; +use embassy_stm32::gpio::NoPin; +use embassy_stm32::pwm::{simple_pwm::SimplePwm, Channel}; +use embassy_stm32::time::U32Ext; +use embassy_stm32::{Config, Peripherals}; +use example_common::*; + +pub fn config() -> Config { + let mut config = Config::default(); + config.rcc.sys_ck = Some(400.mhz().into()); + config.rcc.hclk = Some(400.mhz().into()); + config.rcc.pll1.q_ck = Some(100.mhz().into()); + config.rcc.pclk1 = Some(100.mhz().into()); + config.rcc.pclk2 = Some(100.mhz().into()); + config.rcc.pclk3 = Some(100.mhz().into()); + config.rcc.pclk4 = Some(100.mhz().into()); + config +} + +#[embassy::main(config = "config()")] +async fn main(_spawner: Spawner, p: Peripherals) { + info!("Hello World!"); + + let mut pwm = SimplePwm::new(p.TIM3, p.PA6, NoPin, NoPin, NoPin, 10000.hz()); + let max = pwm.get_max_duty(); + pwm.enable(Channel::Ch1); + + info!("PWM initialized"); + info!("PWM max duty {}", max); + + loop { + pwm.set_duty(Channel::Ch1, 0); + Timer::after(Duration::from_millis(300)).await; + pwm.set_duty(Channel::Ch1, max / 4); + Timer::after(Duration::from_millis(300)).await; + pwm.set_duty(Channel::Ch1, max / 2); + Timer::after(Duration::from_millis(300)).await; + pwm.set_duty(Channel::Ch1, max - 1); + Timer::after(Duration::from_millis(300)).await; + } +}