mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-21 22:32:29 +00:00
Merge pull request #3317 from GrantM11235/simplepwmchannel
embassy-stm32: Add SimplePwmChannel
This commit is contained in:
commit
8803128707
@ -6,6 +6,8 @@
|
|||||||
//!
|
//!
|
||||||
//! The available functionality depends on the timer type.
|
//! The available functionality depends on the timer type.
|
||||||
|
|
||||||
|
use core::mem::ManuallyDrop;
|
||||||
|
|
||||||
use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
|
use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
|
||||||
// Re-export useful enums
|
// Re-export useful enums
|
||||||
pub use stm32_metapac::timer::vals::{FilterValue, Sms as SlaveMode, Ts as TriggerSource};
|
pub use stm32_metapac::timer::vals::{FilterValue, Sms as SlaveMode, Ts as TriggerSource};
|
||||||
@ -198,6 +200,11 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
|
|||||||
Self { tim }
|
Self { tim }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn clone_unchecked(&self) -> ManuallyDrop<Self> {
|
||||||
|
let tim = unsafe { self.tim.clone_unchecked() };
|
||||||
|
ManuallyDrop::new(Self { tim })
|
||||||
|
}
|
||||||
|
|
||||||
/// Get access to the virutal core 16bit timer registers.
|
/// Get access to the virutal core 16bit timer registers.
|
||||||
///
|
///
|
||||||
/// Note: This works even if the timer is more capable, because registers
|
/// Note: This works even if the timer is more capable, because registers
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use embassy_hal_internal::Peripheral;
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
#[cfg(not(stm32l0))]
|
#[cfg(not(stm32l0))]
|
||||||
@ -66,7 +67,7 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait SealedInstance: RccPeripheral {
|
trait SealedInstance: RccPeripheral + Peripheral<P = Self> {
|
||||||
/// Async state for this timer
|
/// Async state for this timer
|
||||||
fn state() -> &'static State;
|
fn state() -> &'static State;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! Simple PWM driver.
|
//! Simple PWM driver.
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
use core::mem::ManuallyDrop;
|
||||||
|
|
||||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||||
|
|
||||||
@ -51,6 +52,111 @@ channel_impl!(new_ch2, Ch2, Channel2Pin);
|
|||||||
channel_impl!(new_ch3, Ch3, Channel3Pin);
|
channel_impl!(new_ch3, Ch3, Channel3Pin);
|
||||||
channel_impl!(new_ch4, Ch4, Channel4Pin);
|
channel_impl!(new_ch4, Ch4, Channel4Pin);
|
||||||
|
|
||||||
|
/// A single channel of a pwm, obtained from [`SimplePwm::split`],
|
||||||
|
/// [`SimplePwm::channel`], [`SimplePwm::ch1`], etc.
|
||||||
|
///
|
||||||
|
/// It is not possible to change the pwm frequency because
|
||||||
|
/// the frequency configuration is shared with all four channels.
|
||||||
|
pub struct SimplePwmChannel<'d, T: GeneralInstance4Channel> {
|
||||||
|
timer: ManuallyDrop<Timer<'d, T>>,
|
||||||
|
channel: Channel,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check for RMW races
|
||||||
|
impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> {
|
||||||
|
/// Enable the given channel.
|
||||||
|
pub fn enable(&mut self) {
|
||||||
|
self.timer.enable_channel(self.channel, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Disable the given channel.
|
||||||
|
pub fn disable(&mut self) {
|
||||||
|
self.timer.enable_channel(self.channel, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check whether given channel is enabled
|
||||||
|
pub fn is_enabled(&self) -> bool {
|
||||||
|
self.timer.get_channel_enable_state(self.channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get max duty value.
|
||||||
|
///
|
||||||
|
/// This value depends on the configured frequency and the timer's clock rate from RCC.
|
||||||
|
pub fn max_duty_cycle(&self) -> u16 {
|
||||||
|
let max = self.timer.get_max_compare_value();
|
||||||
|
assert!(max < u16::MAX as u32);
|
||||||
|
max as u16 + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the duty for a given channel.
|
||||||
|
///
|
||||||
|
/// The value ranges from 0 for 0% duty, to [`max_duty_cycle`](Self::max_duty_cycle) for 100% duty, both included.
|
||||||
|
pub fn set_duty_cycle(&mut self, duty: u16) {
|
||||||
|
assert!(duty <= (*self).max_duty_cycle());
|
||||||
|
self.timer.set_compare_value(self.channel, duty.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the duty cycle to 0%, or always inactive.
|
||||||
|
pub fn set_duty_cycle_fully_off(&mut self) {
|
||||||
|
self.set_duty_cycle(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the duty cycle to 100%, or always active.
|
||||||
|
pub fn set_duty_cycle_fully_on(&mut self) {
|
||||||
|
self.set_duty_cycle((*self).max_duty_cycle());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the duty cycle to `num / denom`.
|
||||||
|
///
|
||||||
|
/// The caller is responsible for ensuring that `num` is less than or equal to `denom`,
|
||||||
|
/// and that `denom` is not zero.
|
||||||
|
pub fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) {
|
||||||
|
assert!(denom != 0);
|
||||||
|
assert!(num <= denom);
|
||||||
|
let duty = u32::from(num) * u32::from(self.max_duty_cycle()) / u32::from(denom);
|
||||||
|
|
||||||
|
// This is safe because we know that `num <= denom`, so `duty <= self.max_duty_cycle()` (u16)
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
self.set_duty_cycle(duty as u16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the duty cycle to `percent / 100`
|
||||||
|
///
|
||||||
|
/// The caller is responsible for ensuring that `percent` is less than or equal to 100.
|
||||||
|
pub fn set_duty_cycle_percent(&mut self, percent: u8) {
|
||||||
|
self.set_duty_cycle_fraction(u16::from(percent), 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the duty for a given channel.
|
||||||
|
///
|
||||||
|
/// The value ranges from 0 for 0% duty, to [`max_duty_cycle`](Self::max_duty_cycle) for 100% duty, both included.
|
||||||
|
pub fn current_duty_cycle(&self) -> u16 {
|
||||||
|
unwrap!(self.timer.get_compare_value(self.channel).try_into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the output polarity for a given channel.
|
||||||
|
pub fn set_polarity(&mut self, polarity: OutputPolarity) {
|
||||||
|
self.timer.set_output_polarity(self.channel, polarity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the output compare mode for a given channel.
|
||||||
|
pub fn set_output_compare_mode(&mut self, mode: OutputCompareMode) {
|
||||||
|
self.timer.set_output_compare_mode(self.channel, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A group of four [`SimplePwmChannel`]s, obtained from [`SimplePwm::split`].
|
||||||
|
pub struct SimplePwmChannels<'d, T: GeneralInstance4Channel> {
|
||||||
|
/// Channel 1
|
||||||
|
pub ch1: SimplePwmChannel<'d, T>,
|
||||||
|
/// Channel 2
|
||||||
|
pub ch2: SimplePwmChannel<'d, T>,
|
||||||
|
/// Channel 3
|
||||||
|
pub ch3: SimplePwmChannel<'d, T>,
|
||||||
|
/// Channel 4
|
||||||
|
pub ch4: SimplePwmChannel<'d, T>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Simple PWM driver.
|
/// Simple PWM driver.
|
||||||
pub struct SimplePwm<'d, T: GeneralInstance4Channel> {
|
pub struct SimplePwm<'d, T: GeneralInstance4Channel> {
|
||||||
inner: Timer<'d, T>,
|
inner: Timer<'d, T>,
|
||||||
@ -89,19 +195,76 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
|
|||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enable the given channel.
|
/// Get a single channel
|
||||||
pub fn enable(&mut self, channel: Channel) {
|
///
|
||||||
self.inner.enable_channel(channel, true);
|
/// If you need to use multiple channels, use [`Self::split`].
|
||||||
|
pub fn channel(&mut self, channel: Channel) -> SimplePwmChannel<'_, T> {
|
||||||
|
SimplePwmChannel {
|
||||||
|
timer: unsafe { self.inner.clone_unchecked() },
|
||||||
|
channel,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Disable the given channel.
|
/// Channel 1
|
||||||
pub fn disable(&mut self, channel: Channel) {
|
///
|
||||||
self.inner.enable_channel(channel, false);
|
/// This is just a convenience wrapper around [`Self::channel`].
|
||||||
|
///
|
||||||
|
/// If you need to use multiple channels, use [`Self::split`].
|
||||||
|
pub fn ch1(&mut self) -> SimplePwmChannel<'_, T> {
|
||||||
|
self.channel(Channel::Ch1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether given channel is enabled
|
/// Channel 2
|
||||||
pub fn is_enabled(&self, channel: Channel) -> bool {
|
///
|
||||||
self.inner.get_channel_enable_state(channel)
|
/// This is just a convenience wrapper around [`Self::channel`].
|
||||||
|
///
|
||||||
|
/// If you need to use multiple channels, use [`Self::split`].
|
||||||
|
pub fn ch2(&mut self) -> SimplePwmChannel<'_, T> {
|
||||||
|
self.channel(Channel::Ch2)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Channel 3
|
||||||
|
///
|
||||||
|
/// This is just a convenience wrapper around [`Self::channel`].
|
||||||
|
///
|
||||||
|
/// If you need to use multiple channels, use [`Self::split`].
|
||||||
|
pub fn ch3(&mut self) -> SimplePwmChannel<'_, T> {
|
||||||
|
self.channel(Channel::Ch3)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Channel 4
|
||||||
|
///
|
||||||
|
/// This is just a convenience wrapper around [`Self::channel`].
|
||||||
|
///
|
||||||
|
/// If you need to use multiple channels, use [`Self::split`].
|
||||||
|
pub fn ch4(&mut self) -> SimplePwmChannel<'_, T> {
|
||||||
|
self.channel(Channel::Ch4)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Splits a [`SimplePwm`] into four pwm channels.
|
||||||
|
///
|
||||||
|
/// This returns all four channels, including channels that
|
||||||
|
/// aren't configured with a [`PwmPin`].
|
||||||
|
// TODO: I hate the name "split"
|
||||||
|
pub fn split(self) -> SimplePwmChannels<'static, T>
|
||||||
|
where
|
||||||
|
// must be static because the timer will never be dropped/disabled
|
||||||
|
'd: 'static,
|
||||||
|
{
|
||||||
|
// without this, the timer would be disabled at the end of this function
|
||||||
|
let timer = ManuallyDrop::new(self.inner);
|
||||||
|
|
||||||
|
let ch = |channel| SimplePwmChannel {
|
||||||
|
timer: unsafe { timer.clone_unchecked() },
|
||||||
|
channel,
|
||||||
|
};
|
||||||
|
|
||||||
|
SimplePwmChannels {
|
||||||
|
ch1: ch(Channel::Ch1),
|
||||||
|
ch2: ch(Channel::Ch2),
|
||||||
|
ch3: ch(Channel::Ch3),
|
||||||
|
ch4: ch(Channel::Ch4),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set PWM frequency.
|
/// Set PWM frequency.
|
||||||
@ -109,6 +272,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
|
|||||||
/// Note: when you call this, the max duty value changes, so you will have to
|
/// Note: when you call this, the max duty value changes, so you will have to
|
||||||
/// call `set_duty` on all channels with the duty calculated based on the new max duty.
|
/// call `set_duty` on all channels with the duty calculated based on the new max duty.
|
||||||
pub fn set_frequency(&mut self, freq: Hertz) {
|
pub fn set_frequency(&mut self, freq: Hertz) {
|
||||||
|
// TODO: prevent ARR = u16::MAX?
|
||||||
let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
|
let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
|
||||||
2u8
|
2u8
|
||||||
} else {
|
} else {
|
||||||
@ -120,33 +284,10 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
|
|||||||
/// Get max duty value.
|
/// Get max duty value.
|
||||||
///
|
///
|
||||||
/// This value depends on the configured frequency and the timer's clock rate from RCC.
|
/// This value depends on the configured frequency and the timer's clock rate from RCC.
|
||||||
pub fn get_max_duty(&self) -> u32 {
|
pub fn max_duty_cycle(&self) -> u16 {
|
||||||
self.inner.get_max_compare_value() + 1
|
let max = self.inner.get_max_compare_value();
|
||||||
}
|
assert!(max < u16::MAX as u32);
|
||||||
|
max as u16 + 1
|
||||||
/// Set the duty for a given channel.
|
|
||||||
///
|
|
||||||
/// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
|
|
||||||
pub fn set_duty(&mut self, channel: Channel, duty: u32) {
|
|
||||||
assert!(duty <= self.get_max_duty());
|
|
||||||
self.inner.set_compare_value(channel, duty)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the duty for a given channel.
|
|
||||||
///
|
|
||||||
/// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
|
|
||||||
pub fn get_duty(&self, channel: Channel) -> u32 {
|
|
||||||
self.inner.get_compare_value(channel)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the output polarity for a given channel.
|
|
||||||
pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
|
|
||||||
self.inner.set_output_polarity(channel, polarity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the output compare mode for a given channel.
|
|
||||||
pub fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
|
|
||||||
self.inner.set_output_compare_mode(channel, mode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a sequence of PWM waveform
|
/// Generate a sequence of PWM waveform
|
||||||
@ -164,8 +305,8 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
|
|||||||
#[allow(clippy::let_unit_value)] // eg. stm32f334
|
#[allow(clippy::let_unit_value)] // eg. stm32f334
|
||||||
let req = dma.request();
|
let req = dma.request();
|
||||||
|
|
||||||
let original_duty_state = self.get_duty(channel);
|
let original_duty_state = self.channel(channel).current_duty_cycle();
|
||||||
let original_enable_state = self.is_enabled(channel);
|
let original_enable_state = self.channel(channel).is_enabled();
|
||||||
let original_update_dma_state = self.inner.get_update_dma_state();
|
let original_update_dma_state = self.inner.get_update_dma_state();
|
||||||
|
|
||||||
if !original_update_dma_state {
|
if !original_update_dma_state {
|
||||||
@ -173,7 +314,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !original_enable_state {
|
if !original_enable_state {
|
||||||
self.enable(channel);
|
self.channel(channel).enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -201,10 +342,10 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
|
|||||||
|
|
||||||
// restore output compare state
|
// restore output compare state
|
||||||
if !original_enable_state {
|
if !original_enable_state {
|
||||||
self.disable(channel);
|
self.channel(channel).disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.set_duty(channel, original_duty_state);
|
self.channel(channel).set_duty_cycle(original_duty_state);
|
||||||
|
|
||||||
// Since DMA is closed before timer update event trigger DMA is turn off,
|
// Since DMA is closed before timer update event trigger DMA is turn off,
|
||||||
// this can almost always trigger a DMA FIFO error.
|
// this can almost always trigger a DMA FIFO error.
|
||||||
@ -234,8 +375,8 @@ macro_rules! impl_waveform_chx {
|
|||||||
|
|
||||||
let cc_channel = Channel::$cc_ch;
|
let cc_channel = Channel::$cc_ch;
|
||||||
|
|
||||||
let original_duty_state = self.get_duty(cc_channel);
|
let original_duty_state = self.channel(cc_channel).current_duty_cycle();
|
||||||
let original_enable_state = self.is_enabled(cc_channel);
|
let original_enable_state = self.channel(cc_channel).is_enabled();
|
||||||
let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ONUPDATE;
|
let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ONUPDATE;
|
||||||
let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel);
|
let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel);
|
||||||
|
|
||||||
@ -249,7 +390,7 @@ macro_rules! impl_waveform_chx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !original_enable_state {
|
if !original_enable_state {
|
||||||
self.enable(cc_channel);
|
self.channel(cc_channel).enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -277,10 +418,10 @@ macro_rules! impl_waveform_chx {
|
|||||||
|
|
||||||
// restore output compare state
|
// restore output compare state
|
||||||
if !original_enable_state {
|
if !original_enable_state {
|
||||||
self.disable(cc_channel);
|
self.channel(cc_channel).disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.set_duty(cc_channel, original_duty_state);
|
self.channel(cc_channel).set_duty_cycle(original_duty_state);
|
||||||
|
|
||||||
// Since DMA is closed before timer Capture Compare Event trigger DMA is turn off,
|
// Since DMA is closed before timer Capture Compare Event trigger DMA is turn off,
|
||||||
// this can almost always trigger a DMA FIFO error.
|
// this can almost always trigger a DMA FIFO error.
|
||||||
@ -304,6 +445,41 @@ impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2);
|
|||||||
impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3);
|
impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3);
|
||||||
impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4);
|
impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4);
|
||||||
|
|
||||||
|
impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePwmChannel<'d, T> {
|
||||||
|
type Error = core::convert::Infallible;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::SetDutyCycle for SimplePwmChannel<'d, T> {
|
||||||
|
fn max_duty_cycle(&self) -> u16 {
|
||||||
|
self.max_duty_cycle()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
|
||||||
|
self.set_duty_cycle(duty);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_duty_cycle_fully_off(&mut self) -> Result<(), Self::Error> {
|
||||||
|
self.set_duty_cycle_fully_off();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_duty_cycle_fully_on(&mut self) -> Result<(), Self::Error> {
|
||||||
|
self.set_duty_cycle_fully_on();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) -> Result<(), Self::Error> {
|
||||||
|
self.set_duty_cycle_fraction(num, denom);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_duty_cycle_percent(&mut self, percent: u8) -> Result<(), Self::Error> {
|
||||||
|
self.set_duty_cycle_percent(percent);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> {
|
impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> {
|
||||||
type Channel = Channel;
|
type Channel = Channel;
|
||||||
type Time = Hertz;
|
type Time = Hertz;
|
||||||
@ -330,7 +506,7 @@ impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
|
fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
|
||||||
assert!(duty <= self.get_max_duty());
|
assert!(duty <= self.max_duty_cycle() as u32);
|
||||||
self.inner.set_compare_value(channel, duty)
|
self.inner.set_compare_value(channel, duty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ use embassy_executor::Spawner;
|
|||||||
use embassy_stm32::gpio::OutputType;
|
use embassy_stm32::gpio::OutputType;
|
||||||
use embassy_stm32::time::khz;
|
use embassy_stm32::time::khz;
|
||||||
use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
|
use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
|
||||||
use embassy_stm32::timer::Channel;
|
|
||||||
use embassy_time::Timer;
|
use embassy_time::Timer;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
@ -15,22 +14,22 @@ async fn main(_spawner: Spawner) {
|
|||||||
let p = embassy_stm32::init(Default::default());
|
let p = embassy_stm32::init(Default::default());
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
let ch1 = PwmPin::new_ch1(p.PE9, OutputType::PushPull);
|
let ch1_pin = PwmPin::new_ch1(p.PE9, OutputType::PushPull);
|
||||||
let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(10), Default::default());
|
let mut pwm = SimplePwm::new(p.TIM1, Some(ch1_pin), None, None, None, khz(10), Default::default());
|
||||||
let max = pwm.get_max_duty();
|
let mut ch1 = pwm.ch1();
|
||||||
pwm.enable(Channel::Ch1);
|
ch1.enable();
|
||||||
|
|
||||||
info!("PWM initialized");
|
info!("PWM initialized");
|
||||||
info!("PWM max duty {}", max);
|
info!("PWM max duty {}", ch1.max_duty_cycle());
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
pwm.set_duty(Channel::Ch1, 0);
|
ch1.set_duty_cycle_fully_off();
|
||||||
Timer::after_millis(300).await;
|
Timer::after_millis(300).await;
|
||||||
pwm.set_duty(Channel::Ch1, max / 4);
|
ch1.set_duty_cycle_fraction(1, 4);
|
||||||
Timer::after_millis(300).await;
|
Timer::after_millis(300).await;
|
||||||
pwm.set_duty(Channel::Ch1, max / 2);
|
ch1.set_duty_cycle_fraction(1, 2);
|
||||||
Timer::after_millis(300).await;
|
Timer::after_millis(300).await;
|
||||||
pwm.set_duty(Channel::Ch1, max - 1);
|
ch1.set_duty_cycle(ch1.max_duty_cycle() - 1);
|
||||||
Timer::after_millis(300).await;
|
Timer::after_millis(300).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
// construct ws2812 non-return-to-zero (NRZ) code bit by bit
|
// construct ws2812 non-return-to-zero (NRZ) code bit by bit
|
||||||
// ws2812 only need 24 bits for each LED, but we add one bit more to keep PWM output low
|
// ws2812 only need 24 bits for each LED, but we add one bit more to keep PWM output low
|
||||||
|
|
||||||
let max_duty = ws2812_pwm.get_max_duty() as u16;
|
let max_duty = ws2812_pwm.max_duty_cycle();
|
||||||
let n0 = 8 * max_duty / 25; // ws2812 Bit 0 high level timing
|
let n0 = 8 * max_duty / 25; // ws2812 Bit 0 high level timing
|
||||||
let n1 = 2 * n0; // ws2812 Bit 1 high level timing
|
let n1 = 2 * n0; // ws2812 Bit 1 high level timing
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let pwm_channel = Channel::Ch1;
|
let pwm_channel = Channel::Ch1;
|
||||||
|
|
||||||
// make sure PWM output keep low on first start
|
// make sure PWM output keep low on first start
|
||||||
ws2812_pwm.set_duty(pwm_channel, 0);
|
ws2812_pwm.channel(pwm_channel).set_duty_cycle(0);
|
||||||
|
|
||||||
// flip color at 2 Hz
|
// flip color at 2 Hz
|
||||||
let mut ticker = Ticker::every(Duration::from_millis(500));
|
let mut ticker = Ticker::every(Duration::from_millis(500));
|
||||||
|
@ -47,10 +47,10 @@ async fn main(spawner: Spawner) {
|
|||||||
unwrap!(spawner.spawn(blinky(p.PB1)));
|
unwrap!(spawner.spawn(blinky(p.PB1)));
|
||||||
|
|
||||||
// Connect PB1 and PA8 with a 1k Ohm resistor
|
// Connect PB1 and PA8 with a 1k Ohm resistor
|
||||||
let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull);
|
let ch1_pin = PwmPin::new_ch1(p.PA8, OutputType::PushPull);
|
||||||
let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(1), Default::default());
|
let mut pwm = SimplePwm::new(p.TIM1, Some(ch1_pin), None, None, None, khz(1), Default::default());
|
||||||
pwm.enable(Channel::Ch1);
|
pwm.ch1().enable();
|
||||||
pwm.set_duty(Channel::Ch1, 50);
|
pwm.ch1().set_duty_cycle(50);
|
||||||
|
|
||||||
let ch1 = CapturePin::new_ch1(p.PA0, Pull::None);
|
let ch1 = CapturePin::new_ch1(p.PA0, Pull::None);
|
||||||
let mut ic = InputCapture::new(p.TIM2, Some(ch1), None, None, None, Irqs, khz(1000), Default::default());
|
let mut ic = InputCapture::new(p.TIM2, Some(ch1), None, None, None, Irqs, khz(1000), Default::default());
|
||||||
|
@ -14,7 +14,6 @@ use embassy_stm32::gpio::{Level, Output, OutputType, Pull, Speed};
|
|||||||
use embassy_stm32::time::khz;
|
use embassy_stm32::time::khz;
|
||||||
use embassy_stm32::timer::pwm_input::PwmInput;
|
use embassy_stm32::timer::pwm_input::PwmInput;
|
||||||
use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
|
use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
|
||||||
use embassy_stm32::timer::Channel;
|
|
||||||
use embassy_stm32::{bind_interrupts, peripherals, timer};
|
use embassy_stm32::{bind_interrupts, peripherals, timer};
|
||||||
use embassy_time::Timer;
|
use embassy_time::Timer;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
@ -43,11 +42,10 @@ async fn main(spawner: Spawner) {
|
|||||||
|
|
||||||
unwrap!(spawner.spawn(blinky(p.PB1)));
|
unwrap!(spawner.spawn(blinky(p.PB1)));
|
||||||
// Connect PA8 and PA6 with a 1k Ohm resistor
|
// Connect PA8 and PA6 with a 1k Ohm resistor
|
||||||
let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull);
|
let ch1_pin = PwmPin::new_ch1(p.PA8, OutputType::PushPull);
|
||||||
let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(1), Default::default());
|
let mut pwm = SimplePwm::new(p.TIM1, Some(ch1_pin), None, None, None, khz(1), Default::default());
|
||||||
let max = pwm.get_max_duty();
|
pwm.ch1().set_duty_cycle_fraction(1, 4);
|
||||||
pwm.set_duty(Channel::Ch1, max / 4);
|
pwm.ch1().enable();
|
||||||
pwm.enable(Channel::Ch1);
|
|
||||||
|
|
||||||
let mut pwm_input = PwmInput::new(p.TIM2, p.PA0, Pull::None, khz(1000));
|
let mut pwm_input = PwmInput::new(p.TIM2, p.PA0, Pull::None, khz(1000));
|
||||||
pwm_input.enable();
|
pwm_input.enable();
|
||||||
|
@ -6,7 +6,6 @@ use embassy_executor::Spawner;
|
|||||||
use embassy_stm32::gpio::OutputType;
|
use embassy_stm32::gpio::OutputType;
|
||||||
use embassy_stm32::time::khz;
|
use embassy_stm32::time::khz;
|
||||||
use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
|
use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
|
||||||
use embassy_stm32::timer::Channel;
|
|
||||||
use embassy_time::Timer;
|
use embassy_time::Timer;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
@ -15,22 +14,22 @@ async fn main(_spawner: Spawner) {
|
|||||||
let p = embassy_stm32::init(Default::default());
|
let p = embassy_stm32::init(Default::default());
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
let ch1 = PwmPin::new_ch1(p.PC0, OutputType::PushPull);
|
let ch1_pin = PwmPin::new_ch1(p.PC0, OutputType::PushPull);
|
||||||
let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(10), Default::default());
|
let mut pwm = SimplePwm::new(p.TIM1, Some(ch1_pin), None, None, None, khz(10), Default::default());
|
||||||
let max = pwm.get_max_duty();
|
let mut ch1 = pwm.ch1();
|
||||||
pwm.enable(Channel::Ch1);
|
ch1.enable();
|
||||||
|
|
||||||
info!("PWM initialized");
|
info!("PWM initialized");
|
||||||
info!("PWM max duty {}", max);
|
info!("PWM max duty {}", ch1.max_duty_cycle());
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
pwm.set_duty(Channel::Ch1, 0);
|
ch1.set_duty_cycle_fully_off();
|
||||||
Timer::after_millis(300).await;
|
Timer::after_millis(300).await;
|
||||||
pwm.set_duty(Channel::Ch1, max / 4);
|
ch1.set_duty_cycle_fraction(1, 4);
|
||||||
Timer::after_millis(300).await;
|
Timer::after_millis(300).await;
|
||||||
pwm.set_duty(Channel::Ch1, max / 2);
|
ch1.set_duty_cycle_fraction(1, 2);
|
||||||
Timer::after_millis(300).await;
|
Timer::after_millis(300).await;
|
||||||
pwm.set_duty(Channel::Ch1, max - 1);
|
ch1.set_duty_cycle(ch1.max_duty_cycle() - 1);
|
||||||
Timer::after_millis(300).await;
|
Timer::after_millis(300).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ use embassy_executor::Spawner;
|
|||||||
use embassy_stm32::gpio::OutputType;
|
use embassy_stm32::gpio::OutputType;
|
||||||
use embassy_stm32::time::khz;
|
use embassy_stm32::time::khz;
|
||||||
use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
|
use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
|
||||||
use embassy_stm32::timer::Channel;
|
|
||||||
use embassy_stm32::Config;
|
use embassy_stm32::Config;
|
||||||
use embassy_time::Timer;
|
use embassy_time::Timer;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
@ -37,22 +36,22 @@ async fn main(_spawner: Spawner) {
|
|||||||
let p = embassy_stm32::init(config);
|
let p = embassy_stm32::init(config);
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
let ch1 = PwmPin::new_ch1(p.PA6, OutputType::PushPull);
|
let ch1_pin = PwmPin::new_ch1(p.PA6, OutputType::PushPull);
|
||||||
let mut pwm = SimplePwm::new(p.TIM3, Some(ch1), None, None, None, khz(10), Default::default());
|
let mut pwm = SimplePwm::new(p.TIM3, Some(ch1_pin), None, None, None, khz(10), Default::default());
|
||||||
let max = pwm.get_max_duty();
|
let mut ch1 = pwm.ch1();
|
||||||
pwm.enable(Channel::Ch1);
|
ch1.enable();
|
||||||
|
|
||||||
info!("PWM initialized");
|
info!("PWM initialized");
|
||||||
info!("PWM max duty {}", max);
|
info!("PWM max duty {}", ch1.max_duty_cycle());
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
pwm.set_duty(Channel::Ch1, 0);
|
ch1.set_duty_cycle_fully_off();
|
||||||
Timer::after_millis(300).await;
|
Timer::after_millis(300).await;
|
||||||
pwm.set_duty(Channel::Ch1, max / 4);
|
ch1.set_duty_cycle_fraction(1, 4);
|
||||||
Timer::after_millis(300).await;
|
Timer::after_millis(300).await;
|
||||||
pwm.set_duty(Channel::Ch1, max / 2);
|
ch1.set_duty_cycle_fraction(1, 2);
|
||||||
Timer::after_millis(300).await;
|
Timer::after_millis(300).await;
|
||||||
pwm.set_duty(Channel::Ch1, max - 1);
|
ch1.set_duty_cycle(ch1.max_duty_cycle() - 1);
|
||||||
Timer::after_millis(300).await;
|
Timer::after_millis(300).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user