stm32/pwm: initial commit
This commit is contained in:
parent
88d4b0c00d
commit
8211d58ee2
2 changed files with 197 additions and 0 deletions
|
@ -51,6 +51,8 @@ pub mod sdmmc;
|
|||
pub mod spi;
|
||||
#[cfg(usart)]
|
||||
pub mod usart;
|
||||
//#[cfg(pwm)]
|
||||
pub mod pwm;
|
||||
|
||||
#[cfg(feature = "subghz")]
|
||||
pub mod subghz;
|
||||
|
|
195
embassy-stm32/src/pwm/mod.rs
Normal file
195
embassy-stm32/src/pwm/mod.rs
Normal file
|
@ -0,0 +1,195 @@
|
|||
use crate::gpio;
|
||||
use crate::rcc::RccPeripheral;
|
||||
use crate::time::Hertz;
|
||||
use core::marker::PhantomData;
|
||||
use embassy::util::Unborrow;
|
||||
use embassy_hal_common::unborrow;
|
||||
use stm32_metapac::timer::vals::Ocm;
|
||||
|
||||
pub struct Pwm<'d, T: Instance> {
|
||||
phantom: PhantomData<&'d mut T>,
|
||||
}
|
||||
|
||||
// TIM2
|
||||
|
||||
pub struct Ch1 {}
|
||||
pub struct Ch2 {}
|
||||
pub struct Ch3 {}
|
||||
pub struct Ch4 {}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Channel {
|
||||
Ch1,
|
||||
Ch2,
|
||||
Ch3,
|
||||
Ch4,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Pwm<'d, T> {
|
||||
pub fn new<F: Into<Hertz>>(
|
||||
_tim: impl Unborrow<Target = T> + 'd,
|
||||
ch1: impl Unborrow<Target = impl PwmPin<T, Ch1>> + 'd,
|
||||
ch2: impl Unborrow<Target = impl PwmPin<T, Ch2>> + 'd,
|
||||
ch3: impl Unborrow<Target = impl PwmPin<T, Ch3>> + 'd,
|
||||
ch4: impl Unborrow<Target = impl PwmPin<T, Ch4>> + 'd,
|
||||
freq: F,
|
||||
) -> Self {
|
||||
unborrow!(ch1, ch2, ch3, ch4);
|
||||
|
||||
T::enable();
|
||||
T::reset();
|
||||
let r = T::regs();
|
||||
|
||||
let mut this = Pwm {
|
||||
phantom: PhantomData,
|
||||
};
|
||||
unsafe {
|
||||
ch1.configure();
|
||||
ch2.configure();
|
||||
ch3.configure();
|
||||
ch4.configure();
|
||||
}
|
||||
|
||||
unsafe {
|
||||
use stm32_metapac::timer::vals::Dir;
|
||||
this.set_freq(freq);
|
||||
r.cr1().write(|w| {
|
||||
w.set_cen(true);
|
||||
w.set_dir(Dir::UP)
|
||||
});
|
||||
|
||||
this.set_ocm(Channel::Ch1, Ocm::PWMMODE1);
|
||||
this.set_ocm(Channel::Ch2, Ocm::PWMMODE1);
|
||||
this.set_ocm(Channel::Ch3, Ocm::PWMMODE1);
|
||||
this.set_ocm(Channel::Ch4, Ocm::PWMMODE1);
|
||||
}
|
||||
this
|
||||
}
|
||||
|
||||
unsafe fn set_ocm(&mut self, channel: Channel, mode: Ocm) {
|
||||
let r = T::regs();
|
||||
match channel {
|
||||
Channel::Ch1 => r.ccmr_output(0).modify(|w| w.set_ocm(0, mode)),
|
||||
Channel::Ch2 => r.ccmr_output(0).modify(|w| w.set_ocm(1, mode)),
|
||||
Channel::Ch3 => r.ccmr_output(1).modify(|w| w.set_ocm(0, mode)),
|
||||
Channel::Ch4 => r.ccmr_output(1).modify(|w| w.set_ocm(1, mode)),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn set_enable(&mut self, channel: Channel, enable: bool) {
|
||||
let r = T::regs();
|
||||
match channel {
|
||||
Channel::Ch1 => r.ccer().modify(|w| w.set_cce(0, enable)),
|
||||
Channel::Ch2 => r.ccer().modify(|w| w.set_cce(1, enable)),
|
||||
Channel::Ch3 => r.ccer().modify(|w| w.set_cce(2, enable)),
|
||||
Channel::Ch4 => r.ccer().modify(|w| w.set_cce(3, enable)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enable(&mut self, channel: Channel) {
|
||||
unsafe {
|
||||
self.set_enable(channel, true);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn disable(&mut self, channel: Channel) {
|
||||
unsafe {
|
||||
self.set_enable(channel, false);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_freq<F: Into<Hertz>>(&mut self, freq: F) {
|
||||
use core::convert::TryInto;
|
||||
let clk = T::frequency();
|
||||
let r = T::regs();
|
||||
let freq: Hertz = freq.into();
|
||||
let ticks: u32 = clk.0 / freq.0;
|
||||
let psc: u16 = (ticks / (1 << 16)).try_into().unwrap();
|
||||
let arr: u16 = (ticks / (u32::from(psc) + 1)).try_into().unwrap();
|
||||
unsafe {
|
||||
r.psc().write(|w| w.set_psc(psc));
|
||||
r.arr().write(|w| w.set_arr(arr));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_max_duty(&self) -> u32 {
|
||||
let r = T::regs();
|
||||
unsafe { r.arr().read().arr() as u32 }
|
||||
}
|
||||
|
||||
pub fn set_duty(&mut self, channel: Channel, duty: u32) {
|
||||
use core::convert::TryInto;
|
||||
assert!(duty < self.get_max_duty());
|
||||
let duty: u16 = duty.try_into().unwrap();
|
||||
let r = T::regs();
|
||||
unsafe {
|
||||
match channel {
|
||||
Channel::Ch1 => r.ccr(0).modify(|w| w.set_ccr(duty)),
|
||||
Channel::Ch2 => r.ccr(1).modify(|w| w.set_ccr(duty)),
|
||||
Channel::Ch3 => r.ccr(2).modify(|w| w.set_ccr(duty)),
|
||||
Channel::Ch4 => r.ccr(3).modify(|w| w.set_ccr(duty)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod sealed {
|
||||
pub trait Instance {
|
||||
fn regs() -> crate::pac::timer::TimGp16;
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Instance: sealed::Instance + Sized + RccPeripheral + 'static {}
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! impl_timer {
|
||||
($inst:ident) => {
|
||||
impl crate::pwm::sealed::Instance for crate::peripherals::$inst {
|
||||
fn regs() -> crate::pac::timer::TimGp16 {
|
||||
crate::pac::$inst
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::pwm::Instance for crate::peripherals::$inst {}
|
||||
};
|
||||
}
|
||||
|
||||
pub trait PwmPin<Timer, Channel>: gpio::OptionalPin {
|
||||
unsafe fn configure(&mut self);
|
||||
}
|
||||
|
||||
impl<Timer, Channel> PwmPin<Timer, Channel> for gpio::NoPin {
|
||||
unsafe fn configure(&mut self) {}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! impl_pwm_pin {
|
||||
($timer:ident, $channel:ident, $pin:ident, $af:expr) => {
|
||||
impl crate::pwm::PwmPin<crate::peripherals::$timer, crate::pwm::$channel>
|
||||
for crate::peripherals::$pin
|
||||
{
|
||||
unsafe fn configure(&mut self) {
|
||||
use crate::gpio::sealed::{AFType, Pin};
|
||||
use crate::gpio::Speed;
|
||||
self.set_low();
|
||||
self.set_speed(Speed::VeryHigh);
|
||||
self.set_as_af($af, AFType::OutputPushPull);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(rcc_g0)]
|
||||
mod impls {
|
||||
crate::pac::peripherals!(
|
||||
(timer, TIM2) => { impl_timer!(TIM2); };
|
||||
(timer, TIM3) => { impl_timer!(TIM3); };
|
||||
(timer, TIM4) => { impl_timer!(TIM4); };
|
||||
(timer, TIM5) => { impl_timer!(TIM5); };
|
||||
);
|
||||
|
||||
impl_pwm_pin!(TIM2, Ch1, PA0, 2);
|
||||
impl_pwm_pin!(TIM2, Ch2, PA1, 2);
|
||||
impl_pwm_pin!(TIM2, Ch3, PA2, 2);
|
||||
impl_pwm_pin!(TIM2, Ch4, PA3, 2);
|
||||
}
|
Loading…
Reference in a new issue