diff --git a/CHANGELOG.md b/CHANGELOG.md index d688384..186828e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,11 +16,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Provide getters to serial status flags idle/txe/rxne/tc. - Provide ability to reset timer UIF interrupt flag - PWM complementary output capability for TIM1 with new example to demonstrate +- Very simple dead time control of complementary PWM channels ### Fixed - Wrong mode when using PWM channel 2 of a two-channel timer - `adc_values` example conversion error +- Fixed typo in setup of complementary channels ## [v0.18.0] - 2021-11-14 diff --git a/examples/pwm_complementary.rs b/examples/pwm_complementary.rs index 919f1e4..47d6417 100644 --- a/examples/pwm_complementary.rs +++ b/examples/pwm_complementary.rs @@ -10,7 +10,12 @@ use cortex_m_rt::entry; use stm32f0xx_hal as hal; -use hal::{delay::Delay, pac, prelude::*, pwm}; +use hal::{ + delay::Delay, + pac, + prelude::*, + pwm::{self, DTInterval::*, *}, +}; #[entry] fn main() -> ! { @@ -31,6 +36,8 @@ fn main() -> ! { let max_duty = ch1.get_max_duty(); ch1.set_duty(max_duty / 2); ch1.enable(); + + ch1n.set_dead_time(DT_2); ch1n.enable(); // simple duty sweep diff --git a/src/pwm.rs b/src/pwm.rs index d83067f..8672642 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -32,6 +32,24 @@ pub struct C3; pub struct C3N; pub struct C4; +pub enum DTInterval { + DT_0 = 0, + DT_1 = 1, + DT_2 = 2, + DT_3 = 3, + DT_4 = 4, + DT_5 = 5, + DT_6 = 6, + DT_7 = 7, +} + +pub trait ComplementaryPwm { + fn disable(&mut self); + fn enable(&mut self); + + fn set_dead_time(&mut self, duration: DTInterval); +} + pub struct PwmChannels { _channel: PhantomData, _tim: PhantomData, @@ -321,7 +339,7 @@ macro_rules! pwm_4_channels_with_3_complementary_outputs { rcc.regs.$apbrstr.modify(|_, w| w.$timXrst().set_bit()); rcc.regs.$apbrstr.modify(|_, w| w.$timXrst().clear_bit()); - if PINS::C1N | PINS::C1N | PINS::C1N { + if PINS::C1N | PINS::C2N | PINS::C3N { tim.bdtr.modify(|_, w| w.ossr().set_bit()); } if PINS::C1 { @@ -406,9 +424,7 @@ macro_rules! pwm_4_channels_with_3_complementary_outputs { } } - impl hal::PwmPin for PwmChannels<$TIMX, C1N> { - type Duty = u16; - + impl ComplementaryPwm for PwmChannels<$TIMX, C1N> { //NOTE(unsafe) atomic write with no side effects fn disable(&mut self) { unsafe { (*($TIMX::ptr())).ccer.modify(|_, w| w.cc1ne().clear_bit()) }; @@ -419,19 +435,9 @@ macro_rules! pwm_4_channels_with_3_complementary_outputs { unsafe { (*($TIMX::ptr())).ccer.modify(|_, w| w.cc1ne().set_bit()) }; } - //NOTE(unsafe) atomic read with no side effects - fn get_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).ccr1.read().ccr().bits() as u16 } - } - - //NOTE(unsafe) atomic read with no side effects - fn get_max_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 } - } - - //NOTE(unsafe) atomic write with no side effects - fn set_duty(&mut self, duty: u16) { - unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr().bits(duty.into())) } + // NOTE: dead time insertion is per timer not per channel + fn set_dead_time(&mut self, duration: DTInterval) { + unsafe { (*($TIMX::ptr())).bdtr.modify(|_, w| w.dtg().bits(duration as u8)) }; } } @@ -464,9 +470,7 @@ macro_rules! pwm_4_channels_with_3_complementary_outputs { } } - impl hal::PwmPin for PwmChannels<$TIMX, C2N> { - type Duty = u16; - + impl ComplementaryPwm for PwmChannels<$TIMX, C2N> { //NOTE(unsafe) atomic write with no side effects fn disable(&mut self) { unsafe { (*($TIMX::ptr())).ccer.modify(|_, w| w.cc2ne().clear_bit()) }; @@ -477,19 +481,9 @@ macro_rules! pwm_4_channels_with_3_complementary_outputs { unsafe { (*($TIMX::ptr())).ccer.modify(|_, w| w.cc2ne().set_bit()) }; } - //NOTE(unsafe) atomic read with no side effects - fn get_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).ccr2.read().ccr().bits() as u16 } - } - - //NOTE(unsafe) atomic read with no side effects - fn get_max_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 } - } - - //NOTE(unsafe) atomic write with no side effects - fn set_duty(&mut self, duty: u16) { - unsafe { (*$TIMX::ptr()).ccr2.write(|w| w.ccr().bits(duty.into())) } + // NOTE: dead time insertion is per timer not per channel + fn set_dead_time(&mut self, duration: DTInterval) { + unsafe { (*($TIMX::ptr())).bdtr.modify(|_, w| w.dtg().bits(duration as u8)) }; } } @@ -522,9 +516,7 @@ macro_rules! pwm_4_channels_with_3_complementary_outputs { } } - impl hal::PwmPin for PwmChannels<$TIMX, C3N> { - type Duty = u16; - + impl ComplementaryPwm for PwmChannels<$TIMX, C3N> { //NOTE(unsafe) atomic write with no side effects fn disable(&mut self) { unsafe { (*($TIMX::ptr())).ccer.modify(|_, w| w.cc3ne().clear_bit()) }; @@ -535,19 +527,9 @@ macro_rules! pwm_4_channels_with_3_complementary_outputs { unsafe { (*($TIMX::ptr())).ccer.modify(|_, w| w.cc3ne().set_bit()) }; } - //NOTE(unsafe) atomic read with no side effects - fn get_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).ccr3.read().ccr().bits() as u16 } - } - - //NOTE(unsafe) atomic read with no side effects - fn get_max_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 } - } - - //NOTE(unsafe) atomic write with no side effects - fn set_duty(&mut self, duty: u16) { - unsafe { (*$TIMX::ptr()).ccr3.write(|w| w.ccr().bits(duty.into())) } + // NOTE: dead time insertion is per timer not per channel + fn set_dead_time(&mut self, duration: DTInterval) { + unsafe { (*($TIMX::ptr())).bdtr.modify(|_, w| w.dtg().bits(duration as u8)) }; } }