Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

- Bump `synopsys-usb-otg` to 0.3.2 (bug fix)
- Update readme, clippy fixes
- Added possibility to pass complementary pins to `Pwm` and change pwm channel polarity [#571]
- Added possibility to pass complementary pins to `Pwm` and change pwm channel polarity [#571],
set dead time and idle state for advanced timers [#578]

### Added

Expand All @@ -27,6 +28,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
[#571]: https://github.com/stm32-rs/stm32f4xx-hal/pull/571
[#572]: https://github.com/stm32-rs/stm32f4xx-hal/pull/572
[#577]: https://github.com/stm32-rs/stm32f4xx-hal/pull/577
[#578]: https://github.com/stm32-rs/stm32f4xx-hal/pull/578


## [v0.14.0] - 2022-12-12

Expand Down
38 changes: 35 additions & 3 deletions src/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ pub enum Polarity {
ActiveLow,
}

/// Output Idle state
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum IdleState {
Reset,
Set,
}

/// Interrupt events
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
Expand Down Expand Up @@ -239,7 +246,7 @@ pub type CCR4<T> = CCR<T, 3>;
pub struct DMAR<T>(T);

mod sealed {
use super::{Channel, Event, Ocm, Polarity};
use super::{Channel, Event, IdleState, Ocm, Polarity};
pub trait General {
type Width: Into<u32> + From<u16>;
fn max_auto_reload() -> u32;
Expand All @@ -266,6 +273,7 @@ mod sealed {

pub trait WithPwmCommon: General {
const CH_NUMBER: u8;
const COMP_CH_NUMBER: u8;
fn read_cc_value(channel: u8) -> u32;
fn set_cc_value(channel: u8, value: u32);
fn enable_channel(channel: u8, b: bool);
Expand All @@ -275,6 +283,9 @@ mod sealed {

pub trait Advanced: WithPwmCommon {
fn enable_nchannel(channel: u8, b: bool);
fn set_dtg_value(value: u8);
fn read_dtg_value() -> u8;
fn idle_state(channel: u8, comp: bool, s: IdleState);
}

pub trait WithPwm: WithPwmCommon {
Expand Down Expand Up @@ -409,6 +420,7 @@ macro_rules! hal {
$(
impl WithPwmCommon for $TIM {
const CH_NUMBER: u8 = $cnum;
const COMP_CH_NUMBER: u8 = $cnum;

#[inline(always)]
fn read_cc_value(c: u8) -> u32 {
Expand Down Expand Up @@ -448,7 +460,7 @@ macro_rules! hal {
#[inline(always)]
fn set_nchannel_polarity(c: u8, p: Polarity) {
let tim = unsafe { &*<$TIM>::ptr() };
if c < Self::CH_NUMBER {
if c < Self::COMP_CH_NUMBER {
unsafe { bb::write(&tim.ccer, c*4 + 3, p == Polarity::ActiveLow); }
}
}
Expand All @@ -459,10 +471,30 @@ macro_rules! hal {
fn enable_nchannel(c: u8, b: bool) {
let $aoe = ();
let tim = unsafe { &*<$TIM>::ptr() };
if c < Self::CH_NUMBER {
if c < Self::COMP_CH_NUMBER {
unsafe { bb::write(&tim.ccer, c*4 + 2, b); }
}
}
fn set_dtg_value(value: u8) {
let tim = unsafe { &*<$TIM>::ptr() };
tim.bdtr.modify(|_,w| unsafe { w.dtg().bits(value) });
}
fn read_dtg_value() -> u8 {
let tim = unsafe { &*<$TIM>::ptr() };
tim.bdtr.read().dtg().bits()
}
fn idle_state(c: u8, comp: bool, s: IdleState) {
let tim = unsafe { &*<$TIM>::ptr() };
if !comp {
if c < Self::CH_NUMBER {
unsafe { bb::write(&tim.cr2, c*2 + 8, s == IdleState::Set); }
}
} else {
if c < Self::COMP_CH_NUMBER {
unsafe { bb::write(&tim.cr2, c*2 + 9, s == IdleState::Set); }
}
}
}
}
)?

Expand Down
123 changes: 122 additions & 1 deletion src/timer/pwm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
//! and change their polarity with `set_polarity` and `set_complementary_polarity`.

use super::{
compute_arr_presc, Advanced, Channel, FTimer, Instance, Ocm, Polarity, Timer, WithPwm,
compute_arr_presc, Advanced, Channel, FTimer, IdleState, Instance, Ocm, Polarity, Timer,
WithPwm,
};
use crate::rcc::Clocks;
use core::marker::PhantomData;
Expand Down Expand Up @@ -263,6 +264,16 @@ impl<TIM: Instance + WithPwm + Advanced, const C: u8> PwmChannel<TIM, C, true> {
pub fn enable_complementary(&mut self) {
TIM::enable_nchannel(C, true);
}

#[inline]
pub fn set_idle_state(&mut self, s: IdleState) {
TIM::idle_state(C, false, s);
}

#[inline]
pub fn set_complementary_idle_state(&mut self, s: IdleState) {
TIM::idle_state(C, true, s);
}
}

pub struct PwmHz<TIM, P, PINS>
Expand Down Expand Up @@ -359,22 +370,27 @@ where
TIM: Instance + WithPwm,
PINS: Pins<TIM, P>,
{
#[inline]
pub fn enable(&mut self, channel: Channel) {
TIM::enable_channel(PINS::check_used(channel) as u8, true)
}

#[inline]
pub fn disable(&mut self, channel: Channel) {
TIM::enable_channel(PINS::check_used(channel) as u8, false)
}

#[inline]
pub fn set_polarity(&mut self, channel: Channel, p: Polarity) {
TIM::set_channel_polarity(PINS::check_used(channel) as u8, p);
}

#[inline]
pub fn get_duty(&self, channel: Channel) -> u16 {
TIM::read_cc_value(PINS::check_used(channel) as u8) as u16
}

#[inline]
pub fn set_duty(&mut self, channel: Channel, duty: u16) {
TIM::set_cc_value(PINS::check_used(channel) as u8, duty as u32)
}
Expand Down Expand Up @@ -402,6 +418,7 @@ where
self.tim.cnt_reset();
}

#[inline]
pub fn set_complementary_polarity(&mut self, channel: Channel, p: Polarity) {
TIM::set_channel_polarity(PINS::check_complementary_used(channel) as u8, p);
}
Expand All @@ -412,13 +429,50 @@ where
TIM: Instance + WithPwm + Advanced,
PINS: Pins<TIM, P>,
{
#[inline]
pub fn enable_complementary(&mut self, channel: Channel) {
TIM::enable_nchannel(PINS::check_complementary_used(channel) as u8, true)
}

#[inline]
pub fn disable_complementary(&mut self, channel: Channel) {
TIM::enable_nchannel(PINS::check_complementary_used(channel) as u8, false)
}

/// Set number DTS ticks during that complementary pin is `dead`
#[inline]
pub fn set_dead_time(&mut self, dts_ticks: u16) {
let bits = pack_ceil_dead_time(dts_ticks);
TIM::set_dtg_value(bits);
}

/// Set raw dead time (DTG) bits
#[inline]
pub fn set_dead_time_bits(&mut self, bits: u8) {
TIM::set_dtg_value(bits);
}

/// Return dead time for complementary pins in DTS ticks
#[inline]
pub fn get_dead_time(&self) -> u16 {
unpack_dead_time(TIM::read_dtg_value())
}

/// Get raw dead time (DTG) bits
#[inline]
pub fn get_dead_time_bits(&self) -> u8 {
TIM::read_dtg_value()
}

#[inline]
pub fn set_idle_state(&mut self, channel: Channel, s: IdleState) {
TIM::idle_state(PINS::check_used(channel) as u8, false, s);
}

#[inline]
pub fn set_complementary_idle_state(&mut self, channel: Channel, s: IdleState) {
TIM::idle_state(PINS::check_complementary_used(channel) as u8, true, s);
}
}

pub struct Pwm<TIM, P, PINS, const FREQ: u32>
Expand Down Expand Up @@ -517,30 +571,37 @@ where
TIM: Instance + WithPwm,
PINS: Pins<TIM, P>,
{
#[inline]
pub fn enable(&mut self, channel: Channel) {
TIM::enable_channel(PINS::check_used(channel) as u8, true)
}

#[inline]
pub fn disable(&mut self, channel: Channel) {
TIM::enable_channel(PINS::check_used(channel) as u8, false)
}

#[inline]
pub fn set_polarity(&mut self, channel: Channel, p: Polarity) {
TIM::set_channel_polarity(PINS::check_used(channel) as u8, p);
}

#[inline]
pub fn get_duty(&self, channel: Channel) -> u16 {
TIM::read_cc_value(PINS::check_used(channel) as u8) as u16
}

#[inline]
pub fn get_duty_time(&self, channel: Channel) -> TimerDurationU32<FREQ> {
TimerDurationU32::from_ticks(TIM::read_cc_value(PINS::check_used(channel) as u8))
}

#[inline]
pub fn set_duty(&mut self, channel: Channel, duty: u16) {
TIM::set_cc_value(PINS::check_used(channel) as u8, duty.into())
}

#[inline]
pub fn set_duty_time(&mut self, channel: Channel, duty: TimerDurationU32<FREQ>) {
TIM::set_cc_value(PINS::check_used(channel) as u8, duty.ticks())
}
Expand All @@ -559,6 +620,7 @@ where
self.tim.cnt_reset();
}

#[inline]
pub fn set_complementary_polarity(&mut self, channel: Channel, p: Polarity) {
TIM::set_channel_polarity(PINS::check_complementary_used(channel) as u8, p);
}
Expand All @@ -569,11 +631,70 @@ where
TIM: Instance + WithPwm + Advanced,
PINS: Pins<TIM, P>,
{
#[inline]
pub fn enable_complementary(&mut self, channel: Channel) {
TIM::enable_nchannel(PINS::check_complementary_used(channel) as u8, true)
}

#[inline]
pub fn disable_complementary(&mut self, channel: Channel) {
TIM::enable_nchannel(PINS::check_complementary_used(channel) as u8, false)
}

/// Set number DTS ticks during that complementary pin is `dead`
#[inline]
pub fn set_dead_time(&mut self, dts_ticks: u16) {
let bits = pack_ceil_dead_time(dts_ticks);
TIM::set_dtg_value(bits);
}

/// Set raw dead time (DTG) bits
#[inline]
pub fn set_dead_time_bits(&mut self, bits: u8) {
TIM::set_dtg_value(bits);
}

/// Return dead time for complementary pins in DTS ticks
#[inline]
pub fn get_dead_time(&self) -> u16 {
unpack_dead_time(TIM::read_dtg_value())
}

/// Get raw dead time (DTG) bits
#[inline]
pub fn get_dead_time_bits(&self) -> u8 {
TIM::read_dtg_value()
}

#[inline]
pub fn set_idle_state(&mut self, channel: Channel, s: IdleState) {
TIM::idle_state(PINS::check_used(channel) as u8, false, s);
}

#[inline]
pub fn set_complementary_idle_state(&mut self, channel: Channel, s: IdleState) {
TIM::idle_state(PINS::check_complementary_used(channel) as u8, true, s);
}
}

const fn pack_ceil_dead_time(dts_ticks: u16) -> u8 {
match dts_ticks {
0..=127 => dts_ticks as u8,
128..=254 => ((((dts_ticks + 1) >> 1) - 64) as u8) | 0b_1000_0000,
255..=504 => ((((dts_ticks + 7) >> 3) - 32) as u8) | 0b_1100_0000,
505..=1008 => ((((dts_ticks + 15) >> 4) - 32) as u8) | 0b_1110_0000,
1009.. => 0xff,
}
}

const fn unpack_dead_time(bits: u8) -> u16 {
if bits & 0b_1000_0000 == 0 {
bits as u16
} else if bits & 0b_0100_0000 == 0 {
(((bits & !0b_1000_0000) as u16) + 64) * 2
} else if bits & 0b_0010_0000 == 0 {
(((bits & !0b_1100_0000) as u16) + 32) * 8
} else {
(((bits & !0b_1110_0000) as u16) + 32) * 16
}
}