Skip to content

Commit

Permalink
const channel
Browse files Browse the repository at this point in the history
  • Loading branch information
burrbull committed Feb 6, 2022
1 parent 8fa1bef commit c274f72
Show file tree
Hide file tree
Showing 7 changed files with 381 additions and 372 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

- Move `i2c` `embedded-hal` trait impls to `I2c` methods [#431]
- Reexport pins in `gpio` module
- Pwm channels now constants [#432]
- Add channel events, make Event use bitflags (simplify interrupt handling) [#425]
- reexport `digital::v2::PinState` again [#428]
- Timer impls with time based on `fugit` moved to `fugit` module, added `Pwm` and `fugit-timer` impls [#423]
Expand All @@ -34,6 +35,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
[#425]: https://github.com/stm32-rs/stm32f4xx-hal/pull/425
[#429]: https://github.com/stm32-rs/stm32f4xx-hal/pull/429
[#431]: https://github.com/stm32-rs/stm32f4xx-hal/pull/431
[#432]: https://github.com/stm32-rs/stm32f4xx-hal/pull/432

### Changed

Expand Down
14 changes: 6 additions & 8 deletions src/fugit/pwm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,31 +145,29 @@ where
type Time = TimerDurationU32<FREQ>;

fn enable(&mut self, channel: Self::Channel) {
self.tim.enable_channel(PINS::check_used(channel), true)
TIM::enable_channel(PINS::check_used(channel) as u8, true)
}

fn disable(&mut self, channel: Self::Channel) {
self.tim.enable_channel(PINS::check_used(channel), false)
TIM::enable_channel(PINS::check_used(channel) as u8, false)
}

fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
let duty: u32 = self.tim.read_cc_value(PINS::check_used(channel)).into();
let duty: u32 = TIM::read_cc_value(PINS::check_used(channel) as u8).into();
duty as u16
}

fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
self.tim
.set_cc_value(PINS::check_used(channel), duty.into())
TIM::set_cc_value(PINS::check_used(channel) as u8, duty.into())
}

/// If `0` returned means max_duty is 2^16
fn get_max_duty(&self) -> Self::Duty {
let arr: u32 = self.tim.read_auto_reload().into();
(arr as u16).wrapping_add(1)
(TIM::read_auto_reload() as u16).wrapping_add(1)
}

fn get_period(&self) -> Self::Time {
Self::Time::from_ticks(self.tim.read_auto_reload().into() + 1)
Self::Time::from_ticks(TIM::read_auto_reload() + 1)
}

fn set_period<T>(&mut self, period: T)
Expand Down
152 changes: 81 additions & 71 deletions src/pwm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,25 @@ pub trait Pins<TIM, P> {

fn split() -> Self::Channels;
}
pub use crate::timer::{CPin, C1, C2, C3, C4};
pub use crate::timer::{CPin, Ch, C1, C2, C3, C4};

pub struct PwmChannel<TIM, CHANNEL> {
_channel: PhantomData<CHANNEL>,
_tim: PhantomData<TIM>,
pub struct PwmChannel<TIM, const C: u8> {
pub(super) _tim: PhantomData<TIM>,
}

macro_rules! pins_impl {
( $( ( $($PINX:ident),+ ), ( $($ENCHX:ident),* ); )+ ) => {
( $( ( $($PINX:ident),+ ), ( $($ENCHX:ident),+ ); )+ ) => {
$(
#[allow(unused_parens)]
impl<TIM, $($PINX,)+> Pins<TIM, ($($ENCHX),+)> for ($($PINX),+)
impl<TIM, $($PINX,)+> Pins<TIM, ($(Ch<$ENCHX>),+)> for ($($PINX),+)
where
$($PINX: CPin<$ENCHX, TIM>,)+
TIM: WithPwm,
$($PINX: CPin<TIM, $ENCHX>,)+
{
$(const $ENCHX: bool = true;)+
type Channels = ($(PwmChannel<TIM, $ENCHX>),+);
fn split() -> Self::Channels {
($(PwmChannel::<TIM, $ENCHX> { _channel: PhantomData, _tim: PhantomData }),+)
($(PwmChannel::<TIM, $ENCHX>::new()),+)
}
}
)+
Expand All @@ -68,71 +68,83 @@ pins_impl!(
(P4), (C4);
);

impl<C, TIM, P1: CPin<C, TIM>, P2: CPin<C, TIM>> CPin<C, TIM> for (P1, P2) {}
impl<C, TIM, P1: CPin<C, TIM>, P2: CPin<C, TIM>, P3: CPin<C, TIM>> CPin<C, TIM> for (P1, P2, P3) {}
impl<C, TIM, P1: CPin<C, TIM>, P2: CPin<C, TIM>, P3: CPin<C, TIM>, P4: CPin<C, TIM>> CPin<C, TIM>
for (P1, P2, P3, P4)
impl<TIM, P1, P2, const C: u8> CPin<TIM, C> for (P1, P2)
where
P1: CPin<TIM, C>,
P2: CPin<TIM, C>,
{
}
impl<TIM, P1, P2, P3, const C: u8> CPin<TIM, C> for (P1, P2, P3)
where
P1: CPin<TIM, C>,
P2: CPin<TIM, C>,
P3: CPin<TIM, C>,
{
}
impl<TIM, P1, P2, P3, P4, const C: u8> CPin<TIM, C> for (P1, P2, P3, P4)
where
P1: CPin<TIM, C>,
P2: CPin<TIM, C>,
P3: CPin<TIM, C>,
P4: CPin<TIM, C>,
{
}

macro_rules! pwm_pin {
($TIMX:ty, $C:ty, $ccr: ident, $bit:literal) => {
impl PwmChannel<$TIMX, $C> {
#[inline]
pub fn disable(&mut self) {
//NOTE(unsafe) atomic write with no side effects
unsafe { bb::clear(&(*<$TIMX>::ptr()).ccer, $bit) }
}

#[inline]
pub fn enable(&mut self) {
//NOTE(unsafe) atomic write with no side effects
unsafe { bb::set(&(*<$TIMX>::ptr()).ccer, $bit) }
}
impl<TIM: WithPwm, const C: u8> PwmChannel<TIM, C> {
pub(crate) fn new() -> Self {
Self {
_tim: core::marker::PhantomData,
}
}
}

#[inline]
pub fn get_duty(&self) -> u16 {
//NOTE(unsafe) atomic read with no side effects
unsafe { (*<$TIMX>::ptr()).$ccr.read().bits() as u16 }
}
impl<TIM: WithPwm, const C: u8> PwmChannel<TIM, C> {
#[inline]
pub fn disable(&mut self) {
TIM::enable_channel(C, false);
}

/// If `0` returned means max_duty is 2^16
#[inline]
pub fn get_max_duty(&self) -> u16 {
//NOTE(unsafe) atomic read with no side effects
unsafe { ((*<$TIMX>::ptr()).arr.read().bits() as u16).wrapping_add(1) }
}
#[inline]
pub fn enable(&mut self) {
TIM::enable_channel(C, true);
}

#[inline]
pub fn set_duty(&mut self, duty: u16) {
//NOTE(unsafe) atomic write with no side effects
unsafe { (*<$TIMX>::ptr()).$ccr.write(|w| w.bits(duty.into())) }
}
}
#[inline]
pub fn get_duty(&self) -> u16 {
TIM::read_cc_value(C) as u16
}

impl embedded_hal::PwmPin for PwmChannel<$TIMX, $C> {
type Duty = u16;
/// If `0` returned means max_duty is 2^16
#[inline]
pub fn get_max_duty(&self) -> u16 {
(TIM::read_auto_reload() as u16).wrapping_add(1)
}

fn disable(&mut self) {
self.disable()
}
fn enable(&mut self) {
self.enable()
}
fn get_duty(&self) -> Self::Duty {
self.get_duty()
}
fn get_max_duty(&self) -> Self::Duty {
self.get_max_duty()
}
fn set_duty(&mut self, duty: Self::Duty) {
self.set_duty(duty)
}
}
};
#[inline]
pub fn set_duty(&mut self, duty: u16) {
TIM::set_cc_value(C, duty as u32)
}
}

pub(crate) use pwm_pin;
impl<TIM: WithPwm, const C: u8> embedded_hal::PwmPin for PwmChannel<TIM, C> {
type Duty = u16;

fn disable(&mut self) {
self.disable()
}
fn enable(&mut self) {
self.enable()
}
fn get_duty(&self) -> Self::Duty {
self.get_duty()
}
fn get_max_duty(&self) -> Self::Duty {
self.get_max_duty()
}
fn set_duty(&mut self, duty: Self::Duty) {
self.set_duty(duty)
}
}

impl<TIM: Instance + WithPwm> Timer<TIM> {
pub fn pwm<P, PINS, T>(mut self, _pins: PINS, freq: T) -> Pwm<TIM, P, PINS>
Expand Down Expand Up @@ -207,33 +219,31 @@ where
type Time = Hertz;

fn enable(&mut self, channel: Self::Channel) {
self.tim.enable_channel(PINS::check_used(channel), true)
TIM::enable_channel(PINS::check_used(channel) as u8, true)
}

fn disable(&mut self, channel: Self::Channel) {
self.tim.enable_channel(PINS::check_used(channel), false)
TIM::enable_channel(PINS::check_used(channel) as u8, false)
}

fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
let duty: u32 = self.tim.read_cc_value(PINS::check_used(channel)).into();
let duty: u32 = TIM::read_cc_value(PINS::check_used(channel) as u8).into();
duty as u16
}

fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
self.tim
.set_cc_value(PINS::check_used(channel), duty.into())
TIM::set_cc_value(PINS::check_used(channel) as u8, duty as u32)
}

/// If `0` returned means max_duty is 2^16
fn get_max_duty(&self) -> Self::Duty {
let arr: u32 = self.tim.read_auto_reload().into();
(arr as u16).wrapping_add(1)
(TIM::read_auto_reload() as u16).wrapping_add(1)
}

fn get_period(&self) -> Self::Time {
let clk = self.clk;
let psc = self.tim.read_prescaler() as u32;
let arr: u32 = self.tim.read_auto_reload().into();
let arr = TIM::read_auto_reload();

// Length in ms of an internal clock pulse
(clk.0 / (psc * arr)).hz()
Expand Down
4 changes: 2 additions & 2 deletions src/pwm_input.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use crate::{
time::Hertz,
timer::{CPin, General, Timer, C1},
timer::{CPin, General, Timer},
};
use cast::u16;

pub trait Pins<TIM> {}

// implement the `Pins` trait wherever PC1 implements CPin<C1>
impl<TIM, PC1> Pins<TIM> for PC1 where PC1: CPin<C1, TIM> {}
impl<TIM, PC1> Pins<TIM> for PC1 where PC1: CPin<TIM, 0> {}

/// Represents a TIMer configured as a PWM input.
/// This peripheral will emit an interrupt on CC2 events, which occurs at two times in this mode:
Expand Down
12 changes: 6 additions & 6 deletions src/qei.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
use crate::{pac::RCC, rcc, timer::General};

pub trait Pins<TIM> {}
use crate::timer::{CPin, C1, C2};
use crate::timer::CPin;

impl<TIM, PC1, PC2> Pins<TIM> for (PC1, PC2)
where
PC1: CPin<C1, TIM>,
PC2: CPin<C2, TIM>,
PC1: CPin<TIM, 0>,
PC2: CPin<TIM, 1>,
{
}

Expand All @@ -19,8 +19,8 @@ pub struct Qei<TIM, PINS> {

impl<TIM: Instance, PC1, PC2> Qei<TIM, (PC1, PC2)>
where
PC1: CPin<C1, TIM>,
PC2: CPin<C2, TIM>,
PC1: CPin<TIM, 0>,
PC2: CPin<TIM, 1>,
{
/// Configures a TIM peripheral as a quadrature encoder interface input
pub fn new(mut tim: TIM, pins: (PC1, PC2)) -> Self {
Expand All @@ -47,7 +47,7 @@ impl<TIM: Instance, PINS> embedded_hal::Qei for Qei<TIM, PINS> {
type Count = TIM::Width;

fn count(&self) -> Self::Count {
self.tim.read_count() as Self::Count
self.tim.read_count()
}

fn direction(&self) -> embedded_hal::Direction {
Expand Down
Loading

0 comments on commit c274f72

Please sign in to comment.