diff options
| author | Matous Hybl <[email protected]> | 2021-12-08 17:39:59 +0100 |
|---|---|---|
| committer | Matous Hybl <[email protected]> | 2022-01-13 16:53:55 +0100 |
| commit | e056bedd553e7fbc7d28f8f516c87fcd12859aef (patch) | |
| tree | 3a86254c58afa1ab790475b32b53debce7dcaec4 /examples/stm32h7/src/bin | |
| parent | e07df92651f58eb001ea8c22cae0130435877b17 (diff) | |
Port the PWM example to H7, add low-level API example implementing 32-bit PWM.
Diffstat (limited to 'examples/stm32h7/src/bin')
| -rw-r--r-- | examples/stm32h7/src/bin/low_level_timer_api.rs | 147 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/pwm.rs | 48 |
2 files changed, 195 insertions, 0 deletions
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 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | #[path = "../example_common.rs"] | ||
| 6 | mod example_common; | ||
| 7 | use core::marker::PhantomData; | ||
| 8 | |||
| 9 | use embassy::executor::Spawner; | ||
| 10 | use embassy::time::{Duration, Timer}; | ||
| 11 | use embassy::util::Unborrow; | ||
| 12 | use embassy_hal_common::unborrow; | ||
| 13 | use embassy_stm32::gpio::NoPin; | ||
| 14 | use embassy_stm32::pwm::{pins::*, Channel, OutputCompareMode}; | ||
| 15 | use embassy_stm32::time::{Hertz, U32Ext}; | ||
| 16 | use embassy_stm32::timer::GeneralPurpose32bitInstance; | ||
| 17 | use embassy_stm32::{Config, Peripherals}; | ||
| 18 | use example_common::*; | ||
| 19 | |||
| 20 | pub fn config() -> Config { | ||
| 21 | let mut config = Config::default(); | ||
| 22 | config.rcc.sys_ck = Some(400.mhz().into()); | ||
| 23 | config.rcc.hclk = Some(400.mhz().into()); | ||
| 24 | config.rcc.pll1.q_ck = Some(100.mhz().into()); | ||
| 25 | config.rcc.pclk1 = Some(100.mhz().into()); | ||
| 26 | config.rcc.pclk2 = Some(100.mhz().into()); | ||
| 27 | config.rcc.pclk3 = Some(100.mhz().into()); | ||
| 28 | config.rcc.pclk4 = Some(100.mhz().into()); | ||
| 29 | config | ||
| 30 | } | ||
| 31 | |||
| 32 | #[embassy::main(config = "config()")] | ||
| 33 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 34 | info!("Hello World!"); | ||
| 35 | |||
| 36 | let mut pwm = SimplePwm32::new(p.TIM5, p.PA0, NoPin, NoPin, NoPin, 10000.hz()); | ||
| 37 | let max = pwm.get_max_duty(); | ||
| 38 | pwm.enable(Channel::Ch1); | ||
| 39 | |||
| 40 | info!("PWM initialized"); | ||
| 41 | info!("PWM max duty {}", max); | ||
| 42 | |||
| 43 | loop { | ||
| 44 | pwm.set_duty(Channel::Ch1, 0); | ||
| 45 | Timer::after(Duration::from_millis(300)).await; | ||
| 46 | pwm.set_duty(Channel::Ch1, max / 4); | ||
| 47 | Timer::after(Duration::from_millis(300)).await; | ||
| 48 | pwm.set_duty(Channel::Ch1, max / 2); | ||
| 49 | Timer::after(Duration::from_millis(300)).await; | ||
| 50 | pwm.set_duty(Channel::Ch1, max - 1); | ||
| 51 | Timer::after(Duration::from_millis(300)).await; | ||
| 52 | } | ||
| 53 | } | ||
| 54 | pub struct SimplePwm32<'d, T: GeneralPurpose32bitInstance> { | ||
| 55 | phantom: PhantomData<&'d mut T>, | ||
| 56 | inner: T, | ||
| 57 | } | ||
| 58 | |||
| 59 | impl<'d, T: GeneralPurpose32bitInstance> SimplePwm32<'d, T> { | ||
| 60 | pub fn new<F: Into<Hertz>>( | ||
| 61 | tim: impl Unborrow<Target = T> + 'd, | ||
| 62 | ch1: impl Unborrow<Target = impl Channel1Pin<T>> + 'd, | ||
| 63 | ch2: impl Unborrow<Target = impl Channel2Pin<T>> + 'd, | ||
| 64 | ch3: impl Unborrow<Target = impl Channel3Pin<T>> + 'd, | ||
| 65 | ch4: impl Unborrow<Target = impl Channel4Pin<T>> + 'd, | ||
| 66 | freq: F, | ||
| 67 | ) -> Self { | ||
| 68 | unborrow!(tim, ch1, ch2, ch3, ch4); | ||
| 69 | |||
| 70 | T::enable(); | ||
| 71 | <T as embassy_stm32::rcc::low_level::RccPeripheral>::reset(); | ||
| 72 | |||
| 73 | unsafe { | ||
| 74 | ch1.configure(); | ||
| 75 | ch2.configure(); | ||
| 76 | ch3.configure(); | ||
| 77 | ch4.configure(); | ||
| 78 | } | ||
| 79 | |||
| 80 | let mut this = Self { | ||
| 81 | inner: tim, | ||
| 82 | phantom: PhantomData, | ||
| 83 | }; | ||
| 84 | |||
| 85 | this.set_freq(freq); | ||
| 86 | this.inner.start(); | ||
| 87 | |||
| 88 | unsafe { | ||
| 89 | this.inner | ||
| 90 | .regs_gp32() | ||
| 91 | .ccmr_output(0) | ||
| 92 | .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); | ||
| 93 | this.inner | ||
| 94 | .regs_gp32() | ||
| 95 | .ccmr_output(0) | ||
| 96 | .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into())); | ||
| 97 | this.inner | ||
| 98 | .regs_gp32() | ||
| 99 | .ccmr_output(1) | ||
| 100 | .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); | ||
| 101 | this.inner | ||
| 102 | .regs_gp32() | ||
| 103 | .ccmr_output(1) | ||
| 104 | .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into())); | ||
| 105 | } | ||
| 106 | this | ||
| 107 | } | ||
| 108 | |||
| 109 | pub fn enable(&mut self, channel: Channel) { | ||
| 110 | unsafe { | ||
| 111 | self.inner | ||
| 112 | .regs_gp32() | ||
| 113 | .ccer() | ||
| 114 | .modify(|w| w.set_cce(channel.raw(), true)); | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | pub fn disable(&mut self, channel: Channel) { | ||
| 119 | unsafe { | ||
| 120 | self.inner | ||
| 121 | .regs_gp32() | ||
| 122 | .ccer() | ||
| 123 | .modify(|w| w.set_cce(channel.raw(), false)); | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | pub fn set_freq<F: Into<Hertz>>(&mut self, freq: F) { | ||
| 128 | <T as embassy_stm32::timer::low_level::GeneralPurpose32bitInstance>::set_frequency( | ||
| 129 | &mut self.inner, | ||
| 130 | freq, | ||
| 131 | ); | ||
| 132 | } | ||
| 133 | |||
| 134 | pub fn get_max_duty(&self) -> u32 { | ||
| 135 | unsafe { self.inner.regs_gp32().arr().read().arr() } | ||
| 136 | } | ||
| 137 | |||
| 138 | pub fn set_duty(&mut self, channel: Channel, duty: u32) { | ||
| 139 | defmt::assert!(duty < self.get_max_duty()); | ||
| 140 | unsafe { | ||
| 141 | self.inner | ||
| 142 | .regs_gp32() | ||
| 143 | .ccr(channel.raw()) | ||
| 144 | .modify(|w| w.set_ccr(duty)) | ||
| 145 | } | ||
| 146 | } | ||
| 147 | } | ||
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 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | #[path = "../example_common.rs"] | ||
| 6 | mod example_common; | ||
| 7 | use embassy::executor::Spawner; | ||
| 8 | use embassy::time::{Duration, Timer}; | ||
| 9 | use embassy_stm32::gpio::NoPin; | ||
| 10 | use embassy_stm32::pwm::{simple_pwm::SimplePwm, Channel}; | ||
| 11 | use embassy_stm32::time::U32Ext; | ||
| 12 | use embassy_stm32::{Config, Peripherals}; | ||
| 13 | use example_common::*; | ||
| 14 | |||
| 15 | pub fn config() -> Config { | ||
| 16 | let mut config = Config::default(); | ||
| 17 | config.rcc.sys_ck = Some(400.mhz().into()); | ||
| 18 | config.rcc.hclk = Some(400.mhz().into()); | ||
| 19 | config.rcc.pll1.q_ck = Some(100.mhz().into()); | ||
| 20 | config.rcc.pclk1 = Some(100.mhz().into()); | ||
| 21 | config.rcc.pclk2 = Some(100.mhz().into()); | ||
| 22 | config.rcc.pclk3 = Some(100.mhz().into()); | ||
| 23 | config.rcc.pclk4 = Some(100.mhz().into()); | ||
| 24 | config | ||
| 25 | } | ||
| 26 | |||
| 27 | #[embassy::main(config = "config()")] | ||
| 28 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 29 | info!("Hello World!"); | ||
| 30 | |||
| 31 | let mut pwm = SimplePwm::new(p.TIM3, p.PA6, NoPin, NoPin, NoPin, 10000.hz()); | ||
| 32 | let max = pwm.get_max_duty(); | ||
| 33 | pwm.enable(Channel::Ch1); | ||
| 34 | |||
| 35 | info!("PWM initialized"); | ||
| 36 | info!("PWM max duty {}", max); | ||
| 37 | |||
| 38 | loop { | ||
| 39 | pwm.set_duty(Channel::Ch1, 0); | ||
| 40 | Timer::after(Duration::from_millis(300)).await; | ||
| 41 | pwm.set_duty(Channel::Ch1, max / 4); | ||
| 42 | Timer::after(Duration::from_millis(300)).await; | ||
| 43 | pwm.set_duty(Channel::Ch1, max / 2); | ||
| 44 | Timer::after(Duration::from_millis(300)).await; | ||
| 45 | pwm.set_duty(Channel::Ch1, max - 1); | ||
| 46 | Timer::after(Duration::from_millis(300)).await; | ||
| 47 | } | ||
| 48 | } | ||
