Skip to content
Closed
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
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ pub mod watchdog;
))]
pub mod can;

#[cfg(feature = "device-selected")]
pub mod qei;

#[cfg(feature = "device-selected")]
#[deprecated(since = "0.17.0", note = "please use `pac` instead")]
pub use pac as stm32;
202 changes: 202 additions & 0 deletions src/pwm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ use crate::rcc::Rcc;
use crate::time::Hertz;
use embedded_hal as hal;

/// Trait for complementary PWM pins that allows the setting of dead time
pub trait ComplementaryPwm {
/// Set the dead time for the pwm timer in ns (not the specific pin)
fn set_dead_time(&mut self, rcc: &mut Rcc, duration: u32);
}

pub trait Pins<TIM, P> {
const C1: bool = false;
const C1N: bool = false;
Expand Down Expand Up @@ -409,6 +415,27 @@ macro_rules! pwm_4_channels_with_3_complementary_outputs {
}
}

impl ComplementaryPwm for PwmChannels<$TIMX, C1> {
//NOTE(unsafe) atomic write with no side effects
fn set_dead_time(&mut self, rcc: &mut Rcc, duration: u32) {
// Convert frequency to period in ns
let period = if rcc.clocks.hclk().0 == rcc.clocks.pclk().0 {
1000000000 / rcc.clocks.pclk().0
} else {
1000000000 / rcc.clocks.pclk().0 * 2
};
let t = duration / period;
let dtg = match t {
0..=127 => t,
128..=255 => t / 2 - 64 + 0b1000_0000,
256..=504 => t / 8 - 32 + 0b1100_0000,
512..=1008 => t / 16 - 32 + 0b1110_0000,
_ => 0,
};
unsafe { (*($TIMX::ptr())).bdtr.modify(|_, w| w.dtg().bits(dtg as u8)) };
}
}

impl hal::PwmPin for PwmChannels<$TIMX, C1N> {
type Duty = u16;

Expand Down Expand Up @@ -438,6 +465,31 @@ macro_rules! pwm_4_channels_with_3_complementary_outputs {
}
}

impl ComplementaryPwm for PwmChannels<$TIMX, C1N> {
//NOTE(unsafe) atomic write with no side effects
fn set_dead_time(&mut self, rcc: &mut Rcc, duration: u32) {
let tclk = if rcc.clocks.hclk().0 == rcc.clocks.pclk().0 {
1000000000 / rcc.clocks.pclk().0
} else {
1000000000 / rcc.clocks.pclk().0 * 2
};
let t = duration / tclk;
let dtg = match t {
0..=127 => t,
128..=255 => t / 2 - 64 + 0b1000_0000,
256..=504 => t / 8 - 32 + 0b1100_0000,
512..=1008 => t / 16 - 32 + 0b1110_0000,
_ => 0,
};

unsafe { (*($TIMX::ptr())).bdtr.modify(|_, w| w.dtg().bits(dtg as u8)) };
}

fn calc_dead_time(&mut self) -> u8 {
unsafe { (*($TIMX::ptr())).bdtr.read().dtg().bits() as u8 }
}
}

impl hal::PwmPin for PwmChannels<$TIMX, C2> {
type Duty = u16;

Expand Down Expand Up @@ -467,6 +519,31 @@ macro_rules! pwm_4_channels_with_3_complementary_outputs {
}
}

impl ComplementaryPwm for PwmChannels<$TIMX, C2> {
//NOTE(unsafe) atomic write with no side effects
fn set_dead_time(&mut self, rcc: &mut Rcc, duration: u32) {
let tclk = if rcc.clocks.hclk().0 == rcc.clocks.pclk().0 {
1000000000 / rcc.clocks.pclk().0
} else {
1000000000 / rcc.clocks.pclk().0 * 2
};
let t = duration / tclk;
let dtg = match t {
0..=127 => t,
128..=255 => t / 2 - 64 + 0b1000_0000,
256..=504 => t / 8 - 32 + 0b1100_0000,
512..=1008 => t / 16 - 32 + 0b1110_0000,
_ => 0,
};

unsafe { (*($TIMX::ptr())).bdtr.modify(|_, w| w.dtg().bits(dtg as u8)) };
}

fn calc_dead_time(&mut self) -> u8 {
unsafe { (*($TIMX::ptr())).bdtr.read().dtg().bits() as u8 }
}
}

impl hal::PwmPin for PwmChannels<$TIMX, C2N> {
type Duty = u16;

Expand Down Expand Up @@ -496,6 +573,31 @@ macro_rules! pwm_4_channels_with_3_complementary_outputs {
}
}

impl ComplementaryPwm for PwmChannels<$TIMX, C2N> {
//NOTE(unsafe) atomic write with no side effects
fn set_dead_time(&mut self, rcc: &mut Rcc, duration: u32) {
let tclk = if rcc.clocks.hclk().0 == rcc.clocks.pclk().0 {
1000000000 / rcc.clocks.pclk().0
} else {
1000000000 / rcc.clocks.pclk().0 * 2
};
let t = duration / tclk;
let dtg = match t {
0..=127 => t,
128..=255 => t / 2 - 64 + 0b1000_0000,
256..=504 => t / 8 - 32 + 0b1100_0000,
512..=1008 => t / 16 - 32 + 0b1110_0000,
_ => 0,
};

unsafe { (*($TIMX::ptr())).bdtr.modify(|_, w| w.dtg().bits(dtg as u8)) };
}

fn calc_dead_time(&mut self) -> u8 {
unsafe { (*($TIMX::ptr())).bdtr.read().dtg().bits() as u8 }
}
}

impl hal::PwmPin for PwmChannels<$TIMX, C3> {
type Duty = u16;

Expand Down Expand Up @@ -525,6 +627,31 @@ macro_rules! pwm_4_channels_with_3_complementary_outputs {
}
}

impl ComplementaryPwm for PwmChannels<$TIMX, C3> {
//NOTE(unsafe) atomic write with no side effects
fn set_dead_time(&mut self, rcc: &mut Rcc, duration: u32) {
let tclk = if rcc.clocks.hclk().0 == rcc.clocks.pclk().0 {
1000000000 / rcc.clocks.pclk().0
} else {
1000000000 / rcc.clocks.pclk().0 * 2
};
let t = duration / tclk;
let dtg = match t {
0..=127 => t,
128..=255 => t / 2 - 64 + 0b1000_0000,
256..=504 => t / 8 - 32 + 0b1100_0000,
512..=1008 => t / 16 - 32 + 0b1110_0000,
_ => 0,
};

unsafe { (*($TIMX::ptr())).bdtr.modify(|_, w| w.dtg().bits(dtg as u8)) };
}

fn calc_dead_time(&mut self) -> u8 {
unsafe { (*($TIMX::ptr())).bdtr.read().dtg().bits() as u8 }
}
}

impl hal::PwmPin for PwmChannels<$TIMX, C3N> {
type Duty = u16;

Expand Down Expand Up @@ -554,6 +681,31 @@ macro_rules! pwm_4_channels_with_3_complementary_outputs {
}
}

impl ComplementaryPwm for PwmChannels<$TIMX, C3N> {
//NOTE(unsafe) atomic write with no side effects
fn set_dead_time(&mut self, rcc: &mut Rcc, duration: u32) {
let tclk = if rcc.clocks.hclk().0 == rcc.clocks.pclk().0 {
1000000000 / rcc.clocks.pclk().0
} else {
1000000000 / rcc.clocks.pclk().0 * 2
};
let t = duration / tclk;
let dtg = match t {
0..=127 => t,
128..=255 => t / 2 - 64 + 0b1000_0000,
256..=504 => t / 8 - 32 + 0b1100_0000,
512..=1008 => t / 16 - 32 + 0b1110_0000,
_ => 0,
};

unsafe { (*($TIMX::ptr())).bdtr.modify(|_, w| w.dtg().bits(dtg as u8)) };
}

fn calc_dead_time(&mut self) -> u8 {
unsafe { (*($TIMX::ptr())).bdtr.read().dtg().bits() as u8 }
}
}

impl hal::PwmPin for PwmChannels<$TIMX, C4> {
type Duty = u16;

Expand Down Expand Up @@ -872,6 +1024,31 @@ macro_rules! pwm_1_channel_with_complementary_outputs {
}
}

impl ComplementaryPwm for PwmChannels<$TIMX, C1> {
//NOTE(unsafe) atomic write with no side effects
fn set_dead_time(&mut self, rcc: &mut Rcc, duration: u32) {
let tclk = if rcc.clocks.hclk().0 == rcc.clocks.pclk().0 {
1000000000 / rcc.clocks.pclk().0
} else {
1000000000 / rcc.clocks.pclk().0 * 2
};
let t = duration / tclk;
let dtg = match t {
0..=127 => t,
128..=255 => t / 2 - 64 + 0b1000_0000,
256..=504 => t / 8 - 32 + 0b1100_0000,
512..=1008 => t / 16 - 32 + 0b1110_0000,
_ => 0,
};

unsafe { (*($TIMX::ptr())).bdtr.modify(|_, w| w.dtg().bits(dtg as u8)) };
}

fn calc_dead_time(&mut self) -> u8 {
unsafe { (*($TIMX::ptr())).bdtr.read().dtg().bits() as u8 }
}
}

impl hal::PwmPin for PwmChannels<$TIMX, C1N> {
type Duty = u16;

Expand Down Expand Up @@ -900,6 +1077,31 @@ macro_rules! pwm_1_channel_with_complementary_outputs {
unsafe { (*$TIMX::ptr()).ccr1().write(|w| w.ccr().bits(duty.into())) }
}
}

impl ComplementaryPwm for PwmChannels<$TIMX, C1N> {
//NOTE(unsafe) atomic write with no side effects
fn set_dead_time(&mut self, rcc: &mut Rcc, duration: u32) {
let tclk = if rcc.clocks.hclk().0 == rcc.clocks.pclk().0 {
1000000000 / rcc.clocks.pclk().0
} else {
1000000000 / rcc.clocks.pclk().0 * 2
};
let t = duration / tclk;
let dtg = match t {
0..=127 => t,
128..=255 => t / 2 - 64 + 0b1000_0000,
256..=504 => t / 8 - 32 + 0b1100_0000,
512..=1008 => t / 16 - 32 + 0b1110_0000,
_ => 0,
};

unsafe { (*($TIMX::ptr())).bdtr.modify(|_, w| w.dtg().bits(dtg as u8)) };
}

fn calc_dead_time(&mut self) -> u8 {
unsafe { (*($TIMX::ptr())).bdtr.read().dtg().bits() as u8 }
}
}
)+
};
}
Expand Down
101 changes: 101 additions & 0 deletions src/qei.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//! API for using an integrated timer as a quadrature encoder



use crate::rcc::Rcc;
use crate::pwm::Pins;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// The direction the quadrature encoder is counting
pub enum Direction {
/// The encoder is counting down
Downcounting,
/// The encoder is counting up
Upcounting,
}

/// Quadrature Encoder using an advanted timer periperal
pub struct Qei<TIMER> {
timer: TIMER,
}

macro_rules! qei {
($($TIM: ident: ($tim:ident, $timXen:ident, $timXrst:ident, $apbenr:ident, $apbrstr:ident, $width:ident),)+) => {
$(
use crate::pac::$TIM;
impl Qei<$TIM> {
/// Configures a TIM peripheral as a quadrature encoder
pub fn $tim<P, PINS>(tim: $TIM, _pins: PINS, rcc: &mut Rcc) -> Self
where
PINS: Pins<$TIM, P>,
{
// enable and reset peripherals to a clean slate state
rcc.regs.$apbenr.modify(|_, w| w.$timXen().set_bit());
rcc.regs.$apbrstr.modify(|_, w| w.$timXrst().set_bit());
rcc.regs.$apbrstr.modify(|_, w| w.$timXrst().clear_bit());

if PINS::C1 && PINS::C2 {
tim.ccmr1_input().modify(|_, w| w
.cc1s().ti1()
.cc2s().ti2()
);
tim.ccer.write(|w| w
.cc1p().set_bit()
.cc2p().set_bit()
);
tim.smcr.write(|w| w.sms().encoder_mode_3());
} else if PINS::C1 {
tim.ccmr1_input().modify(|_, w| w.cc1s().ti1());
tim.ccer.write(|w| w.cc1p().set_bit());
tim.smcr.write(|w| w.sms().encoder_mode_1());
} else if PINS::C2 {
tim.ccmr1_input().modify(|_, w| w.cc2s().ti2());
tim.ccer.write(|w| w.cc2p().set_bit());
tim.smcr.write(|w| w.sms().encoder_mode_2());
}

tim.arr.write(|w| w.arr().variant($width::MAX));
tim.cr1.write(|w| w.cen().set_bit());

Self {
timer: tim,
}
}

/// Read the direction the encoder is counting
pub fn read_direction(&self) -> Direction {
match self.timer.cr1.read().dir().bit_is_set() {
true => Direction::Downcounting,
false => Direction::Upcounting,
}
}

/// Get the current count of the encoder
pub fn count(&self) -> $width {
self.timer.cnt.read().cnt().bits()
}
}
)+
}
}

qei! {
TIM3: (tim3, tim3en, tim3rst, apb1enr, apb1rstr, u16),
}

#[cfg(any(
feature = "stm32f031",
feature = "stm32f038",
feature = "stm32f042",
feature = "stm32f048",
feature = "stm32f051",
feature = "stm32f058",
feature = "stm32f071",
feature = "stm32f072",
feature = "stm32f078",
feature = "stm32f091",
feature = "stm32f098"
))]
qei! {
TIM2: (tim2, tim2en, tim2rst, apb1enr, apb1rstr, u32),
}
Loading