From e056bedd553e7fbc7d28f8f516c87fcd12859aef Mon Sep 17 00:00:00 2001 From: Matous Hybl Date: Wed, 8 Dec 2021 17:39:59 +0100 Subject: Port the PWM example to H7, add low-level API example implementing 32-bit PWM. --- examples/stm32h7/src/bin/low_level_timer_api.rs | 147 ++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 examples/stm32h7/src/bin/low_level_timer_api.rs (limited to 'examples/stm32h7/src/bin/low_level_timer_api.rs') 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)) + } + } +} -- cgit