From ed4f6f0f548c6b00b33c0eb4726ee287e718d1e6 Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 05:33:20 -0500 Subject: [PATCH 01/30] Add a MicroSecond time unit --- src/time.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/time.rs b/src/time.rs index ec95b0a2..b9dbfd90 100644 --- a/src/time.rs +++ b/src/time.rs @@ -24,6 +24,9 @@ pub struct MegaHertz(pub u32); #[derive(PartialEq, PartialOrd, Clone, Copy)] pub struct MilliSeconds(pub u32); +#[derive(PartialEq, PartialOrd, Clone, Copy)] +pub struct MicroSeconds(pub u32); + /// Extension trait that adds convenience methods to the `u32` type pub trait U32Ext { /// Wrap in `Bps` @@ -40,6 +43,9 @@ pub trait U32Ext { /// Wrap in `MilliSeconds` fn ms(self) -> MilliSeconds; + + /// Wrap in `MicroSeconds` + fn us(self) -> MicroSeconds; } impl U32Ext for u32 { @@ -62,6 +68,10 @@ impl U32Ext for u32 { fn ms(self) -> MilliSeconds { MilliSeconds(self) } + + fn us(self) -> MicroSeconds { + MicroSeconds(self) +} } impl Into for KiloHertz { From 5050ddacb35fd0b50eb9fb33675a9c2c5f304f3b Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 05:34:04 -0500 Subject: [PATCH 02/30] Implement Into for the different time types --- src/time.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/time.rs b/src/time.rs index b9dbfd90..a6b2ac0a 100644 --- a/src/time.rs +++ b/src/time.rs @@ -92,6 +92,18 @@ impl Into for MegaHertz { } } +impl Into for MilliSeconds { + fn into(self) -> Hertz { + Hertz(1_000_000 / self.0) + } +} + +impl Into for MicroSeconds { + fn into(self) -> Hertz { + Hertz(1_000 / self.0) + } +} + /// A monotonic nondecreasing timer #[derive(Clone, Copy)] pub struct MonoTimer { From f37b17cb58ec98ac39c29521f45a7ca4da07843a Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 05:34:37 -0500 Subject: [PATCH 03/30] Adjust whitespace --- src/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/time.rs b/src/time.rs index a6b2ac0a..bbdce586 100644 --- a/src/time.rs +++ b/src/time.rs @@ -71,7 +71,7 @@ impl U32Ext for u32 { fn us(self) -> MicroSeconds { MicroSeconds(self) -} + } } impl Into for KiloHertz { From 8d0012c98b61008276414e3a713e2d49b00b43c9 Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 05:40:01 -0500 Subject: [PATCH 04/30] Change the Pwm struct to be PwmChannel to make room for a new Pwm struct --- src/pwm.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pwm.rs b/src/pwm.rs index eba5a189..58dc7f48 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -93,7 +93,7 @@ macro_rules! pins_impl { $($PINX: $TRAIT + gpio::Mode>,)+ { $(const $ENCHX: bool = true;)+ - type Channels = ($(Pwm),+); + type Channels = ($(PwmChannel),+); } )+ }; @@ -199,7 +199,7 @@ impl Timer { } } -pub struct Pwm { +pub struct PwmChannel { _channel: PhantomData, _tim: PhantomData, } @@ -261,7 +261,7 @@ macro_rules! hal { unsafe { mem::MaybeUninit::uninit().assume_init() } } - impl hal::PwmPin for Pwm<$TIMX, C1> { + impl hal::PwmPin for PwmChannel<$TIMX, C1> { type Duty = u16; fn disable(&mut self) { @@ -285,7 +285,7 @@ macro_rules! hal { } } - impl hal::PwmPin for Pwm<$TIMX, C2> { + impl hal::PwmPin for PwmChannel<$TIMX, C2> { type Duty = u16; fn disable(&mut self) { @@ -309,7 +309,7 @@ macro_rules! hal { } } - impl hal::PwmPin for Pwm<$TIMX, C3> { + impl hal::PwmPin for PwmChannel<$TIMX, C3> { type Duty = u16; fn disable(&mut self) { @@ -333,7 +333,7 @@ macro_rules! hal { } } - impl hal::PwmPin for Pwm<$TIMX, C4> { + impl hal::PwmPin for PwmChannel<$TIMX, C4> { type Duty = u16; fn disable(&mut self) { From 5a2f9f637f71117387b6a2833470e2ee34389519 Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 05:44:36 -0500 Subject: [PATCH 05/30] Make PwmChannel Copy --- src/pwm.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pwm.rs b/src/pwm.rs index 58dc7f48..278dd00e 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -54,6 +54,7 @@ */ use core::marker::PhantomData; +use core::marker::{Copy}; use core::mem; use cast::{u16, u32}; @@ -199,6 +200,7 @@ impl Timer { } } +#[derive(Copy, Clone)] pub struct PwmChannel { _channel: PhantomData, _tim: PhantomData, From bb0113d050d609bc223f39d16adadc27496cf56e Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 05:47:21 -0500 Subject: [PATCH 06/30] Actually add the Copy/Clone implementations for the specific types --- src/pwm.rs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/pwm.rs b/src/pwm.rs index 278dd00e..7571aad4 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -260,7 +260,34 @@ macro_rules! hal { .set_bit() ); - unsafe { mem::MaybeUninit::uninit().assume_init() } + impl Copy for PwmChannel<$TIMX, C1> {} + impl Clone for PwmChannel<$TIMX, C1> { + fn clone(&self) -> Self { + unsafe { mem::MaybeUninit::uninit().assume_init() } + } + } + + impl Copy for PwmChannel<$TIMX, C2> {} + impl Clone for PwmChannel<$TIMX, C2> { + fn clone(&self) -> Self { + unsafe { mem::MaybeUninit::uninit().assume_init() } + } + } + } + } + + impl Copy for PwmChannel<$TIMX, C3> {} + impl Clone for PwmChannel<$TIMX, C3> { + fn clone(&self) -> Self { + unsafe { mem::MaybeUninit::uninit().assume_init() } + } + } + + impl Copy for PwmChannel<$TIMX, C4> {} + impl Clone for PwmChannel<$TIMX, C4> { + fn clone(&self) -> Self { + unsafe { mem::MaybeUninit::uninit().assume_init() } + } } impl hal::PwmPin for PwmChannel<$TIMX, C1> { From 4dfe2677b277014008e392da96477c8e4dad8b26 Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 05:50:17 -0500 Subject: [PATCH 07/30] Add new Pwm struct and fix return types --- src/pwm.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/pwm.rs b/src/pwm.rs index 7571aad4..a73e7fda 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -129,7 +129,7 @@ impl Timer { _pins: PINS, mapr: &mut MAPR, freq: T, - ) -> PINS::Channels + ) -> Pwm where REMAP: Remap, PINS: Pins, @@ -148,7 +148,7 @@ impl Timer { _pins: PINS, mapr: &mut MAPR, freq: T, - ) -> PINS::Channels + ) -> Pwm where REMAP: Remap, PINS: Pins, @@ -167,7 +167,7 @@ impl Timer { _pins: PINS, mapr: &mut MAPR, freq: T, - ) -> PINS::Channels + ) -> Pwm where REMAP: Remap, PINS: Pins, @@ -187,7 +187,7 @@ impl Timer { _pins: PINS, mapr: &mut MAPR, freq: T, - ) -> PINS::Channels + ) -> Pwm where REMAP: Remap, PINS: Pins, @@ -200,6 +200,12 @@ impl Timer { } } +pub struct Pwm { + clk: Hertz, + _channels: PhantomData, + _tim: PhantomData, +} + #[derive(Copy, Clone)] pub struct PwmChannel { _channel: PhantomData, @@ -219,7 +225,7 @@ macro_rules! hal { _pins: PINS, freq: Hertz, clk: Hertz, - ) -> PINS::Channels + ) -> Pwm<$TIMX, PINS::Channels> where REMAP: Remap, PINS: Pins, @@ -260,6 +266,13 @@ macro_rules! hal { .set_bit() ); + Pwm { + clk: clk, + _tim: PhantomData, + _channels: PhantomData + } + } + impl Copy for PwmChannel<$TIMX, C1> {} impl Clone for PwmChannel<$TIMX, C1> { fn clone(&self) -> Self { From a275dc16dce699c56b2f2c07547c1c0f6ba8de5f Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 05:51:02 -0500 Subject: [PATCH 08/30] Make Pwm Deref and DerefMut for backwards compatability --- src/pwm.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/pwm.rs b/src/pwm.rs index a73e7fda..f44b351a 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -206,6 +206,20 @@ pub struct Pwm { _tim: PhantomData, } +impl Deref for Pwm { + type Target = PWMCHANNELS; + + fn deref(&self) -> &Self::Target { + unsafe { mem::MaybeUninit::uninit().assume_init() } + } +} + +impl DerefMut for Pwm { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { mem::MaybeUninit::uninit().assume_init() } + } +} + #[derive(Copy, Clone)] pub struct PwmChannel { _channel: PhantomData, From 69235c70d0d4d3c0243ba9c41c1c69445ff6546c Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 05:52:04 -0500 Subject: [PATCH 09/30] Add the core::ops Deref and DerefMut modules --- src/pwm.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pwm.rs b/src/pwm.rs index f44b351a..c3dce3cb 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -56,6 +56,7 @@ use core::marker::PhantomData; use core::marker::{Copy}; use core::mem; +use core::ops::{Deref, DerefMut}; use cast::{u16, u32}; use crate::hal; From 8d260861c73385c8ad98754c83b6504d75f5ada4 Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 05:53:17 -0500 Subject: [PATCH 10/30] Implement the new Pwm class to be compliant with embedded_hal::Pwm --- src/pwm.rs | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 2 deletions(-) diff --git a/src/pwm.rs b/src/pwm.rs index c3dce3cb..14c06bb4 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -57,6 +57,7 @@ use core::marker::PhantomData; use core::marker::{Copy}; use core::mem; use core::ops::{Deref, DerefMut}; +use embedded_hal::PwmPin; use cast::{u16, u32}; use crate::hal; @@ -74,6 +75,7 @@ use crate::afio::MAPR; use crate::bb; use crate::gpio::{self, Alternate, PushPull}; use crate::time::Hertz; +use crate::time::U32Ext; use crate::timer::Timer; pub trait Pins { @@ -232,6 +234,93 @@ pub struct C2; pub struct C3; pub struct C4; +/* + The following implemention of the embedded_hal::Pwm uses Hertz as a time type. This was choosen + because of the timescales of operationsbeing on the order of nanoseconds and not being able to + efficently represent a float on the hardware. It might be possible to change the time type to + a different time based using such as the nanosecond. The issue with doing so is that the max + delay would then be at just a little over 2 seconds because of the 32 bit depth of the number. + Using milliseconds is also an option, however, using this as a base unit means that only there + could be resolution issues when trying to get a specific value, because of the integer nature. + + To find a middle ground, the Hertz type is used as a base here and the Into trait has been + defined for several base time units. This will allow for calling the set_period method with + something that is natural to both the MCU and the end user. +*/ +macro_rules! pwm_impl { + ( $( $TIMX:ident, $timX:ident, ( $($CHNUM:pat),+ ), ( $($ENUMNUM:tt),+ ), ( $($ENCHX:ident),+ ); )+ ) => { + $( + #[allow(unused_parens)] + impl hal::Pwm for Pwm<$TIMX, ($(PwmChannel<$TIMX, $ENCHX>),+,)> { + type Channel = u8; + type Duty = u16; + type Time = Hertz; + + fn enable(&mut self, channel: Self::Channel) { + match channel { + $( $CHNUM => self.$ENUMNUM.enable(),)+ + _ => {} + } + } + + fn disable(&mut self, channel: Self::Channel) { + match channel { + $( $CHNUM => self.$ENUMNUM.disable(),)+ + _ => {} + } + } + + fn get_duty(&self, channel: Self::Channel) -> Self::Duty { + match channel { + $( $CHNUM => self.$ENUMNUM.get_duty(),)+ + _ => 0 + } + } + + fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { + match channel { + $( $CHNUM => self.$ENUMNUM.set_duty(duty),)+ + _ => {} + } + } + + fn get_max_duty(&self) -> Self::Duty { + unsafe { (*$TIMX::ptr()).arr.read().arr().bits() } + } + + fn get_period(&self) -> Self::Time { + let clk = self.clk; + let mut psc: u16 = 0; + let mut arr: u16 = 0; + unsafe { + psc = (*$TIMX::ptr()).psc.read().psc().bits(); + arr = (*$TIMX::ptr()).arr.read().arr().bits(); + } + + // Length in ms of an internal clock pulse + (clk.0 / u32(psc * arr)).hz() +// (((psc as u32) / clk.0) * (1_000_000 as u32) * (arr as u32)).ms() + } + + fn set_period

(&mut self, period: P) where + P: Into { + let clk = self.clk; + +// let freq = u16(1 / period.into()); + + let ticks = clk.0 / period.into().0; + let psc = u16(ticks / (1 << 16)).unwrap(); + let arr = u16(ticks / u32(psc + 1)).unwrap(); + unsafe { + (*$TIMX::ptr()).psc.write(|w| w.psc().bits(psc)); + (*$TIMX::ptr()).arr.write(|w| w.arr().bits(arr)); + } + } + } + )+ + }; +} + macro_rules! hal { ($($TIMX:ident: ($timX:ident),)+) => { $( @@ -288,6 +377,23 @@ macro_rules! hal { } } + pwm_impl!( + $TIMX, $timX, (0, 1, 2, 3), (0, 1, 2, 3), (C1, C2, C3, C4); + $TIMX, $timX, (0, 1, 2), (0, 1, 2), (C1, C2, C3); + $TIMX, $timX, (0, 1, 2), (0, 1, 2), (C1, C2, C4); + $TIMX, $timX, (0, 1, 2), (0, 1, 2), (C2, C3, C4); + $TIMX, $timX, (0, 1), (0, 1), (C1, C2); + $TIMX, $timX, (0, 1), (0, 1), (C1, C3); + $TIMX, $timX, (0, 1), (0, 1), (C1, C4); + $TIMX, $timX, (0, 1), (0, 1), (C2, C3); + $TIMX, $timX, (0, 1), (0, 1), (C2, C4); + $TIMX, $timX, (0, 1), (0, 1), (C3, C4); + $TIMX, $timX, (0), (0), (C1); + $TIMX, $timX, (0), (0), (C2); + $TIMX, $timX, (0), (0), (C3); + $TIMX, $timX, (0), (0), (C4); + ); + impl Copy for PwmChannel<$TIMX, C1> {} impl Clone for PwmChannel<$TIMX, C1> { fn clone(&self) -> Self { @@ -301,8 +407,6 @@ macro_rules! hal { unsafe { mem::MaybeUninit::uninit().assume_init() } } } - } - } impl Copy for PwmChannel<$TIMX, C3> {} impl Clone for PwmChannel<$TIMX, C3> { From 4a0a15f70865226b4ba86466750f3497fd904f27 Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 06:18:02 -0500 Subject: [PATCH 11/30] Update example for the Pwm --- examples/pwm.rs | 51 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/examples/pwm.rs b/examples/pwm.rs index 6638964c..c08a2b27 100644 --- a/examples/pwm.rs +++ b/examples/pwm.rs @@ -11,6 +11,7 @@ use stm32f1xx_hal::{ prelude::*, pac, timer::{Tim2NoRemap, Timer}, + time::U32Ext }; use cortex_m_rt::entry; @@ -49,25 +50,57 @@ fn main() -> ! { // let c4 = gpiob.pb9.into_alternate_push_pull(&mut gpiob.crh); let mut pwm = Timer::tim2(p.TIM2, &clocks, &mut rcc.apb1) - .pwm::(pins, &mut afio.mapr, 1.khz()) - .2; + .pwm::(pins, &mut afio.mapr, 1.khz()); + + //// Operations affecting all defined channels on the Timer + + // Adjust period to 0.5 seconds + pwm.set_period(500.us()); + + asm::bkpt(); + + // Return to the original frequency + pwm.set_period(1.khz()); + + asm::bkpt(); let max = pwm.get_max_duty(); - pwm.enable(); + //// Operations affecting single channels can be accessed through + //// the Pwm object or via dereferencing to the pin. Pin indexing + //// starts at 0. + + // Use the Pwm object to set C3 to full strength + pwm.set_duty(2, max); + + asm::bkpt(); + + // Use the Pwm object to set C3 to be dim + pwm.set_duty(2, max / 4); + + asm::bkpt(); + + // Use the Pwm object to set C3 to be zero + pwm.set_duty(2, 0); + + asm::bkpt(); + + + // Extract the PwmChannel for C3 + let mut pwm_channel = pwm.2; - // full - pwm.set_duty(max); + // Use the PwmChannel object to set C3 to be full strength + pwm_channel.set_duty(max); asm::bkpt(); - // dim - pwm.set_duty(max / 4); + // Use the PwmChannel object to set C3 to be dim + pwm_channel.set_duty(max / 4); asm::bkpt(); - // zero - pwm.set_duty(0); + // Use the PwmChannel object to set C3 to be zero + pwm_channel.set_duty(0); asm::bkpt(); From 7175ebedb5ff33f23558cdc245c6d32429115ed4 Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 06:24:52 -0500 Subject: [PATCH 12/30] Reduce complexity of macro call --- src/pwm.rs | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/pwm.rs b/src/pwm.rs index 14c06bb4..ec2cd891 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -248,7 +248,7 @@ pub struct C4; something that is natural to both the MCU and the end user. */ macro_rules! pwm_impl { - ( $( $TIMX:ident, $timX:ident, ( $($CHNUM:pat),+ ), ( $($ENUMNUM:tt),+ ), ( $($ENCHX:ident),+ ); )+ ) => { + ( $( $TIMX:ident, $timX:ident, ( $($CHNUM:tt),+ ), ( $($ENCHX:ident),+ ); )+ ) => { $( #[allow(unused_parens)] impl hal::Pwm for Pwm<$TIMX, ($(PwmChannel<$TIMX, $ENCHX>),+,)> { @@ -258,28 +258,28 @@ macro_rules! pwm_impl { fn enable(&mut self, channel: Self::Channel) { match channel { - $( $CHNUM => self.$ENUMNUM.enable(),)+ + $( $CHNUM => self.$CHNUM.enable(),)+ _ => {} } } fn disable(&mut self, channel: Self::Channel) { match channel { - $( $CHNUM => self.$ENUMNUM.disable(),)+ + $( $CHNUM => self.$CHNUM.disable(),)+ _ => {} } } fn get_duty(&self, channel: Self::Channel) -> Self::Duty { match channel { - $( $CHNUM => self.$ENUMNUM.get_duty(),)+ + $( $CHNUM => self.$CHNUM.get_duty(),)+ _ => 0 } } fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { match channel { - $( $CHNUM => self.$ENUMNUM.set_duty(duty),)+ + $( $CHNUM => self.$CHNUM.set_duty(duty),)+ _ => {} } } @@ -378,20 +378,20 @@ macro_rules! hal { } pwm_impl!( - $TIMX, $timX, (0, 1, 2, 3), (0, 1, 2, 3), (C1, C2, C3, C4); - $TIMX, $timX, (0, 1, 2), (0, 1, 2), (C1, C2, C3); - $TIMX, $timX, (0, 1, 2), (0, 1, 2), (C1, C2, C4); - $TIMX, $timX, (0, 1, 2), (0, 1, 2), (C2, C3, C4); - $TIMX, $timX, (0, 1), (0, 1), (C1, C2); - $TIMX, $timX, (0, 1), (0, 1), (C1, C3); - $TIMX, $timX, (0, 1), (0, 1), (C1, C4); - $TIMX, $timX, (0, 1), (0, 1), (C2, C3); - $TIMX, $timX, (0, 1), (0, 1), (C2, C4); - $TIMX, $timX, (0, 1), (0, 1), (C3, C4); - $TIMX, $timX, (0), (0), (C1); - $TIMX, $timX, (0), (0), (C2); - $TIMX, $timX, (0), (0), (C3); - $TIMX, $timX, (0), (0), (C4); + $TIMX, $timX, (0, 1, 2, 3), (C1, C2, C3, C4); + $TIMX, $timX, (0, 1, 2), (C1, C2, C3); + $TIMX, $timX, (0, 1, 2), (C1, C2, C4); + $TIMX, $timX, (0, 1, 2), (C2, C3, C4); + $TIMX, $timX, (0, 1), (C1, C2); + $TIMX, $timX, (0, 1), (C1, C3); + $TIMX, $timX, (0, 1), (C1, C4); + $TIMX, $timX, (0, 1), (C2, C3); + $TIMX, $timX, (0, 1), (C2, C4); + $TIMX, $timX, (0, 1), (C3, C4); + $TIMX, $timX, (0), (C1); + $TIMX, $timX, (0), (C2); + $TIMX, $timX, (0), (C3); + $TIMX, $timX, (0), (C4); ); impl Copy for PwmChannel<$TIMX, C1> {} From a6bbac1ef8d4e1a9932d06734b1d987636fe30d4 Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 06:42:38 -0500 Subject: [PATCH 13/30] Remove accedental merge conflict messages --- src/time.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/time.rs b/src/time.rs index a008ccc4..366086a9 100644 --- a/src/time.rs +++ b/src/time.rs @@ -92,7 +92,6 @@ impl Into for MegaHertz { } } -<<<<<<< HEAD impl Into for MilliSeconds { fn into(self) -> Hertz { Hertz(1_000_000 / self.0) @@ -105,10 +104,7 @@ impl Into for MicroSeconds { } } -/// A monotonic nondecreasing timer -======= /// A monotonic non-decreasing timer ->>>>>>> master #[derive(Clone, Copy)] pub struct MonoTimer { frequency: Hertz, From 06f5a471837d3cd38b5f61f394b31bf4b609cb55 Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 22:08:54 -0500 Subject: [PATCH 14/30] Correct typo in code comment --- src/pwm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pwm.rs b/src/pwm.rs index ec2cd891..ffa1b150 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -236,7 +236,7 @@ pub struct C4; /* The following implemention of the embedded_hal::Pwm uses Hertz as a time type. This was choosen - because of the timescales of operationsbeing on the order of nanoseconds and not being able to + because of the timescales of operations being on the order of nanoseconds and not being able to efficently represent a float on the hardware. It might be possible to change the time type to a different time based using such as the nanosecond. The issue with doing so is that the max delay would then be at just a little over 2 seconds because of the 32 bit depth of the number. From 6a6b08a384905a379a2b2f04f7cfe02e8b17605c Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 22:09:57 -0500 Subject: [PATCH 15/30] Simplify the get_period function --- src/pwm.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/pwm.rs b/src/pwm.rs index ffa1b150..0648ae65 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -290,12 +290,8 @@ macro_rules! pwm_impl { fn get_period(&self) -> Self::Time { let clk = self.clk; - let mut psc: u16 = 0; - let mut arr: u16 = 0; - unsafe { - psc = (*$TIMX::ptr()).psc.read().psc().bits(); - arr = (*$TIMX::ptr()).arr.read().arr().bits(); - } + let psc = unsafe{ (*$TIMX::ptr()).psc.read().psc().bits() }; + let arr = unsafe{ (*$TIMX::ptr()).arr.read().arr().bits() }; // Length in ms of an internal clock pulse (clk.0 / u32(psc * arr)).hz() From 0cbc67fd23afe379932d35f1f83fd0c35edc3e18 Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 22:10:52 -0500 Subject: [PATCH 16/30] Temporarally remove the Clone and Copy instances --- src/pwm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pwm.rs b/src/pwm.rs index 0648ae65..ce1c90fe 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -389,7 +389,7 @@ macro_rules! hal { $TIMX, $timX, (0), (C3); $TIMX, $timX, (0), (C4); ); - +/* impl Copy for PwmChannel<$TIMX, C1> {} impl Clone for PwmChannel<$TIMX, C1> { fn clone(&self) -> Self { @@ -417,7 +417,7 @@ macro_rules! hal { unsafe { mem::MaybeUninit::uninit().assume_init() } } } - +*/ impl hal::PwmPin for PwmChannel<$TIMX, C1> { type Duty = u16; From a77eea3163c055788e86344cdb46038da046e66c Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 22:11:45 -0500 Subject: [PATCH 17/30] Remove PhantomData from the _channels field of the Pwm struct --- src/pwm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pwm.rs b/src/pwm.rs index ce1c90fe..d913544b 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -205,7 +205,7 @@ impl Timer { pub struct Pwm { clk: Hertz, - _channels: PhantomData, + _channels: PWMCHANNELS, _tim: PhantomData, } From b22ff3b7bc188d58e05521ec01a31fb5024460a3 Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 22:12:51 -0500 Subject: [PATCH 18/30] Add an `into_channels(&self)` method to split out the channels --- src/pwm.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/pwm.rs b/src/pwm.rs index d913544b..28ff3335 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -209,6 +209,12 @@ pub struct Pwm { _tim: PhantomData, } +impl Pwm { + fn into_channels(&self) -> PWMCHANNELS { + self._channels + } +} + impl Deref for Pwm { type Target = PWMCHANNELS; From a6f21b407bb087de6c63f3b973e00f53c27eff1d Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 22:13:34 -0500 Subject: [PATCH 19/30] Update the Deref and DerefMut impl --- src/pwm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pwm.rs b/src/pwm.rs index 28ff3335..97e2a35c 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -219,13 +219,13 @@ impl Deref for Pwm { type Target = PWMCHANNELS; fn deref(&self) -> &Self::Target { - unsafe { mem::MaybeUninit::uninit().assume_init() } + &self._channels } } impl DerefMut for Pwm { fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { mem::MaybeUninit::uninit().assume_init() } + &mut self._channels } } From ca3b1a9990601d38c4948a18f05180b5955941f7 Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 22:14:51 -0500 Subject: [PATCH 20/30] Remove unecessary [#derive] and [#allow] directives --- src/pwm.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pwm.rs b/src/pwm.rs index 97e2a35c..6b5c9687 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -229,7 +229,6 @@ impl DerefMut for Pwm { } } -#[derive(Copy, Clone)] pub struct PwmChannel { _channel: PhantomData, _tim: PhantomData, @@ -256,7 +255,6 @@ pub struct C4; macro_rules! pwm_impl { ( $( $TIMX:ident, $timX:ident, ( $($CHNUM:tt),+ ), ( $($ENCHX:ident),+ ); )+ ) => { $( - #[allow(unused_parens)] impl hal::Pwm for Pwm<$TIMX, ($(PwmChannel<$TIMX, $ENCHX>),+,)> { type Channel = u8; type Duty = u16; From 87179b1ea036d4daff10280b92149a91f41c6e86 Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Tue, 21 Jan 2020 22:26:48 -0500 Subject: [PATCH 21/30] Corrected the order for milli and micro (cant beleive I did that) --- src/time.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/time.rs b/src/time.rs index 366086a9..f7318650 100644 --- a/src/time.rs +++ b/src/time.rs @@ -94,13 +94,13 @@ impl Into for MegaHertz { impl Into for MilliSeconds { fn into(self) -> Hertz { - Hertz(1_000_000 / self.0) + Hertz(1_000 / self.0) } } impl Into for MicroSeconds { fn into(self) -> Hertz { - Hertz(1_000 / self.0) + Hertz(1_000_000 / self.0) } } From cf5a1521bf9abd6a4e8741e75b083116d07f7b78 Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Sat, 25 Jan 2020 14:11:27 -0500 Subject: [PATCH 22/30] Update to @burrbull suggested techniques --- src/pwm.rs | 220 +++++++++++++++++++++++++++++------------------------ 1 file changed, 121 insertions(+), 99 deletions(-) diff --git a/src/pwm.rs b/src/pwm.rs index 6b5c9687..f31e1dcf 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -56,8 +56,6 @@ use core::marker::PhantomData; use core::marker::{Copy}; use core::mem; -use core::ops::{Deref, DerefMut}; -use embedded_hal::PwmPin; use cast::{u16, u32}; use crate::hal; @@ -84,6 +82,28 @@ pub trait Pins { const C3: bool = false; const C4: bool = false; type Channels; + + fn check_enabled(c: Channel) -> Option { + if c == Channel::C1 && Self::C1 { + Some(c) + } else if c == Channel::C2 && Self::C2 { + Some(c) + } else if c == Channel::C3 && Self::C3 { + Some(c) + } else if c == Channel::C4 && Self::C4 { + Some(c) + } else { + None + } + } +} + +#[derive(Clone, Copy, PartialEq)] +pub enum Channel { + C1, + C2, + C3, + C4, } use crate::timer::sealed::{Remap, Ch1, Ch2, Ch3, Ch4}; @@ -132,7 +152,7 @@ impl Timer { _pins: PINS, mapr: &mut MAPR, freq: T, - ) -> Pwm + ) -> Pwm where REMAP: Remap, PINS: Pins, @@ -151,7 +171,7 @@ impl Timer { _pins: PINS, mapr: &mut MAPR, freq: T, - ) -> Pwm + ) -> Pwm where REMAP: Remap, PINS: Pins, @@ -170,7 +190,7 @@ impl Timer { _pins: PINS, mapr: &mut MAPR, freq: T, - ) -> Pwm + ) -> Pwm where REMAP: Remap, PINS: Pins, @@ -190,7 +210,7 @@ impl Timer { _pins: PINS, mapr: &mut MAPR, freq: T, - ) -> Pwm + ) -> Pwm where REMAP: Remap, PINS: Pins, @@ -203,29 +223,22 @@ impl Timer { } } -pub struct Pwm { +pub struct Pwm +where + REMAP: Remap, + PINS: Pins +{ clk: Hertz, - _channels: PWMCHANNELS, - _tim: PhantomData, -} - -impl Pwm { - fn into_channels(&self) -> PWMCHANNELS { - self._channels - } -} - -impl Deref for Pwm { - type Target = PWMCHANNELS; - - fn deref(&self) -> &Self::Target { - &self._channels - } + _pins: PhantomData<(TIM, REMAP, P, PINS)>, } -impl DerefMut for Pwm { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self._channels +impl Pwm +where + REMAP: Remap, + PINS: Pins +{ + pub fn split(self) -> PINS::Channels { + unsafe { mem::MaybeUninit::uninit().assume_init() } } } @@ -252,74 +265,6 @@ pub struct C4; defined for several base time units. This will allow for calling the set_period method with something that is natural to both the MCU and the end user. */ -macro_rules! pwm_impl { - ( $( $TIMX:ident, $timX:ident, ( $($CHNUM:tt),+ ), ( $($ENCHX:ident),+ ); )+ ) => { - $( - impl hal::Pwm for Pwm<$TIMX, ($(PwmChannel<$TIMX, $ENCHX>),+,)> { - type Channel = u8; - type Duty = u16; - type Time = Hertz; - - fn enable(&mut self, channel: Self::Channel) { - match channel { - $( $CHNUM => self.$CHNUM.enable(),)+ - _ => {} - } - } - - fn disable(&mut self, channel: Self::Channel) { - match channel { - $( $CHNUM => self.$CHNUM.disable(),)+ - _ => {} - } - } - - fn get_duty(&self, channel: Self::Channel) -> Self::Duty { - match channel { - $( $CHNUM => self.$CHNUM.get_duty(),)+ - _ => 0 - } - } - - fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { - match channel { - $( $CHNUM => self.$CHNUM.set_duty(duty),)+ - _ => {} - } - } - - fn get_max_duty(&self) -> Self::Duty { - unsafe { (*$TIMX::ptr()).arr.read().arr().bits() } - } - - fn get_period(&self) -> Self::Time { - let clk = self.clk; - let psc = unsafe{ (*$TIMX::ptr()).psc.read().psc().bits() }; - let arr = unsafe{ (*$TIMX::ptr()).arr.read().arr().bits() }; - - // Length in ms of an internal clock pulse - (clk.0 / u32(psc * arr)).hz() -// (((psc as u32) / clk.0) * (1_000_000 as u32) * (arr as u32)).ms() - } - - fn set_period

(&mut self, period: P) where - P: Into { - let clk = self.clk; - -// let freq = u16(1 / period.into()); - - let ticks = clk.0 / period.into().0; - let psc = u16(ticks / (1 << 16)).unwrap(); - let arr = u16(ticks / u32(psc + 1)).unwrap(); - unsafe { - (*$TIMX::ptr()).psc.write(|w| w.psc().bits(psc)); - (*$TIMX::ptr()).arr.write(|w| w.arr().bits(arr)); - } - } - } - )+ - }; -} macro_rules! hal { ($($TIMX:ident: ($timX:ident),)+) => { @@ -329,7 +274,7 @@ macro_rules! hal { _pins: PINS, freq: Hertz, clk: Hertz, - ) -> Pwm<$TIMX, PINS::Channels> + ) -> Pwm<$TIMX, REMAP, P, PINS> where REMAP: Remap, PINS: Pins, @@ -372,12 +317,89 @@ macro_rules! hal { Pwm { clk: clk, - _tim: PhantomData, - _channels: PhantomData + _pins: PhantomData } } - pwm_impl!( + impl hal::Pwm for Pwm<$TIMX, REMAP, P, PINS> where + REMAP: Remap, + PINS: Pins, + { + type Channel = Channel; + type Duty = u16; + type Time = Hertz; + + fn enable(&mut self, channel: Self::Channel) { + match PINS::check_enabled(channel) { + Some(Channel::C1) => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 0) }, + Some(Channel::C2) => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 4) }, + Some(Channel::C3) => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 8) }, + Some(Channel::C4) => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 12) }, + None => {} + } + } + + fn disable(&mut self, channel: Self::Channel) { + match PINS::check_enabled(channel) { + Some(Channel::C1) => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 0) }, + Some(Channel::C2) => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 4) }, + Some(Channel::C3) => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 8) }, + Some(Channel::C4) => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 12) }, + None => {} + } + } + + fn get_duty(&self, channel: Self::Channel) -> Self::Duty { + match PINS::check_enabled(channel) { + Some(Channel::C1) => unsafe { (*$TIMX::ptr()).ccr1.read().ccr().bits() }, + Some(Channel::C2) => unsafe { (*$TIMX::ptr()).ccr2.read().ccr().bits() }, + Some(Channel::C3) => unsafe { (*$TIMX::ptr()).ccr3.read().ccr().bits() }, + Some(Channel::C4) => unsafe { (*$TIMX::ptr()).ccr4.read().ccr().bits() }, + None => 0, + } + } + + fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { + match PINS::check_enabled(channel) { + Some(Channel::C1) => unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr().bits(duty)) }, + Some(Channel::C2) => unsafe { (*$TIMX::ptr()).ccr2.write(|w| w.ccr().bits(duty)) }, + Some(Channel::C3) => unsafe { (*$TIMX::ptr()).ccr3.write(|w| w.ccr().bits(duty)) }, + Some(Channel::C4) => unsafe { (*$TIMX::ptr()).ccr4.write(|w| w.ccr().bits(duty)) }, + None => {}, + } + } + + fn get_max_duty(&self) -> Self::Duty { + unsafe { (*$TIMX::ptr()).arr.read().arr().bits() } + } + + fn get_period(&self) -> Self::Time { + let clk = self.clk; + let psc: u16 = unsafe{(*$TIMX::ptr()).psc.read().psc().bits()}; + let arr: u16 = unsafe{(*$TIMX::ptr()).psc.read().psc().bits()}; + + // Length in ms of an internal clock pulse + (clk.0 / u32(psc * arr)).hz() +// (((psc as u32) / clk.0) * (1_000_000 as u32) * (arr as u32)).ms() + } + + fn set_period(&mut self, period: T) where + T: Into { + let clk = self.clk; + +// let freq = u16(1 / period.into()); + + let ticks = clk.0 / period.into().0; + let psc = u16(ticks / (1 << 16)).unwrap(); + let arr = u16(ticks / u32(psc + 1)).unwrap(); + unsafe { + (*$TIMX::ptr()).psc.write(|w| w.psc().bits(psc)); + (*$TIMX::ptr()).arr.write(|w| w.arr().bits(arr)); + } + } + } +/* + pwm_impl!( $TIMX, $timX, (0, 1, 2, 3), (C1, C2, C3, C4); $TIMX, $timX, (0, 1, 2), (C1, C2, C3); $TIMX, $timX, (0, 1, 2), (C1, C2, C4); @@ -393,7 +415,7 @@ macro_rules! hal { $TIMX, $timX, (0), (C3); $TIMX, $timX, (0), (C4); ); -/* + impl Copy for PwmChannel<$TIMX, C1> {} impl Clone for PwmChannel<$TIMX, C1> { fn clone(&self) -> Self { From 62ec7bd4c8493be8c71ca7c9994c7a22f8aef5b7 Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Sat, 25 Jan 2020 14:26:43 -0500 Subject: [PATCH 23/30] Shift comments to correct spot and update indent --- src/pwm.rs | 192 ++++++++++++++++++++--------------------------------- 1 file changed, 73 insertions(+), 119 deletions(-) diff --git a/src/pwm.rs b/src/pwm.rs index f31e1dcf..36762fda 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -252,20 +252,6 @@ pub struct C2; pub struct C3; pub struct C4; -/* - The following implemention of the embedded_hal::Pwm uses Hertz as a time type. This was choosen - because of the timescales of operations being on the order of nanoseconds and not being able to - efficently represent a float on the hardware. It might be possible to change the time type to - a different time based using such as the nanosecond. The issue with doing so is that the max - delay would then be at just a little over 2 seconds because of the 32 bit depth of the number. - Using milliseconds is also an option, however, using this as a base unit means that only there - could be resolution issues when trying to get a specific value, because of the integer nature. - - To find a middle ground, the Hertz type is used as a base here and the Into trait has been - defined for several base time units. This will allow for calling the set_period method with - something that is natural to both the MCU and the end user. -*/ - macro_rules! hal { ($($TIMX:ident: ($timX:ident),)+) => { $( @@ -321,129 +307,97 @@ macro_rules! hal { } } - impl hal::Pwm for Pwm<$TIMX, REMAP, P, PINS> where + /* + The following implemention of the embedded_hal::Pwm uses Hertz as a time type. This was choosen + because of the timescales of operations being on the order of nanoseconds and not being able to + efficently represent a float on the hardware. It might be possible to change the time type to + a different time based using such as the nanosecond. The issue with doing so is that the max + delay would then be at just a little over 2 seconds because of the 32 bit depth of the number. + Using milliseconds is also an option, however, using this as a base unit means that only there + could be resolution issues when trying to get a specific value, because of the integer nature. + + To find a middle ground, the Hertz type is used as a base here and the Into trait has been + defined for several base time units. This will allow for calling the set_period method with + something that is natural to both the MCU and the end user. + */ + impl hal::Pwm for Pwm<$TIMX, REMAP, P, PINS> where REMAP: Remap, PINS: Pins, - { - type Channel = Channel; - type Duty = u16; - type Time = Hertz; - - fn enable(&mut self, channel: Self::Channel) { - match PINS::check_enabled(channel) { - Some(Channel::C1) => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 0) }, - Some(Channel::C2) => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 4) }, - Some(Channel::C3) => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 8) }, - Some(Channel::C4) => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 12) }, - None => {} + { + type Channel = Channel; + type Duty = u16; + type Time = Hertz; + + fn enable(&mut self, channel: Self::Channel) { + match PINS::check_enabled(channel) { + Some(Channel::C1) => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 0) }, + Some(Channel::C2) => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 4) }, + Some(Channel::C3) => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 8) }, + Some(Channel::C4) => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 12) }, + None => {} + } } - } - fn disable(&mut self, channel: Self::Channel) { - match PINS::check_enabled(channel) { - Some(Channel::C1) => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 0) }, - Some(Channel::C2) => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 4) }, - Some(Channel::C3) => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 8) }, - Some(Channel::C4) => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 12) }, - None => {} + fn disable(&mut self, channel: Self::Channel) { + match PINS::check_enabled(channel) { + Some(Channel::C1) => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 0) }, + Some(Channel::C2) => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 4) }, + Some(Channel::C3) => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 8) }, + Some(Channel::C4) => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 12) }, + None => {} + } } - } - fn get_duty(&self, channel: Self::Channel) -> Self::Duty { - match PINS::check_enabled(channel) { - Some(Channel::C1) => unsafe { (*$TIMX::ptr()).ccr1.read().ccr().bits() }, - Some(Channel::C2) => unsafe { (*$TIMX::ptr()).ccr2.read().ccr().bits() }, - Some(Channel::C3) => unsafe { (*$TIMX::ptr()).ccr3.read().ccr().bits() }, - Some(Channel::C4) => unsafe { (*$TIMX::ptr()).ccr4.read().ccr().bits() }, - None => 0, + fn get_duty(&self, channel: Self::Channel) -> Self::Duty { + match PINS::check_enabled(channel) { + Some(Channel::C1) => unsafe { (*$TIMX::ptr()).ccr1.read().ccr().bits() }, + Some(Channel::C2) => unsafe { (*$TIMX::ptr()).ccr2.read().ccr().bits() }, + Some(Channel::C3) => unsafe { (*$TIMX::ptr()).ccr3.read().ccr().bits() }, + Some(Channel::C4) => unsafe { (*$TIMX::ptr()).ccr4.read().ccr().bits() }, + None => 0, + } } - } - fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { - match PINS::check_enabled(channel) { - Some(Channel::C1) => unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr().bits(duty)) }, - Some(Channel::C2) => unsafe { (*$TIMX::ptr()).ccr2.write(|w| w.ccr().bits(duty)) }, - Some(Channel::C3) => unsafe { (*$TIMX::ptr()).ccr3.write(|w| w.ccr().bits(duty)) }, - Some(Channel::C4) => unsafe { (*$TIMX::ptr()).ccr4.write(|w| w.ccr().bits(duty)) }, - None => {}, + fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { + match PINS::check_enabled(channel) { + Some(Channel::C1) => unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr().bits(duty)) }, + Some(Channel::C2) => unsafe { (*$TIMX::ptr()).ccr2.write(|w| w.ccr().bits(duty)) }, + Some(Channel::C3) => unsafe { (*$TIMX::ptr()).ccr3.write(|w| w.ccr().bits(duty)) }, + Some(Channel::C4) => unsafe { (*$TIMX::ptr()).ccr4.write(|w| w.ccr().bits(duty)) }, + None => {}, + } } - } - - fn get_max_duty(&self) -> Self::Duty { - unsafe { (*$TIMX::ptr()).arr.read().arr().bits() } - } - fn get_period(&self) -> Self::Time { - let clk = self.clk; - let psc: u16 = unsafe{(*$TIMX::ptr()).psc.read().psc().bits()}; - let arr: u16 = unsafe{(*$TIMX::ptr()).psc.read().psc().bits()}; - - // Length in ms of an internal clock pulse - (clk.0 / u32(psc * arr)).hz() -// (((psc as u32) / clk.0) * (1_000_000 as u32) * (arr as u32)).ms() - } + fn get_max_duty(&self) -> Self::Duty { + unsafe { (*$TIMX::ptr()).arr.read().arr().bits() } + } - fn set_period(&mut self, period: T) where - T: Into { + fn get_period(&self) -> Self::Time { let clk = self.clk; + let psc: u16 = unsafe{(*$TIMX::ptr()).psc.read().psc().bits()}; + let arr: u16 = unsafe{(*$TIMX::ptr()).psc.read().psc().bits()}; -// let freq = u16(1 / period.into()); + // Length in ms of an internal clock pulse + (clk.0 / u32(psc * arr)).hz() + // (((psc as u32) / clk.0) * (1_000_000 as u32) * (arr as u32)).ms() + } - let ticks = clk.0 / period.into().0; - let psc = u16(ticks / (1 << 16)).unwrap(); - let arr = u16(ticks / u32(psc + 1)).unwrap(); - unsafe { - (*$TIMX::ptr()).psc.write(|w| w.psc().bits(psc)); - (*$TIMX::ptr()).arr.write(|w| w.arr().bits(arr)); - } - } - } -/* - pwm_impl!( - $TIMX, $timX, (0, 1, 2, 3), (C1, C2, C3, C4); - $TIMX, $timX, (0, 1, 2), (C1, C2, C3); - $TIMX, $timX, (0, 1, 2), (C1, C2, C4); - $TIMX, $timX, (0, 1, 2), (C2, C3, C4); - $TIMX, $timX, (0, 1), (C1, C2); - $TIMX, $timX, (0, 1), (C1, C3); - $TIMX, $timX, (0, 1), (C1, C4); - $TIMX, $timX, (0, 1), (C2, C3); - $TIMX, $timX, (0, 1), (C2, C4); - $TIMX, $timX, (0, 1), (C3, C4); - $TIMX, $timX, (0), (C1); - $TIMX, $timX, (0), (C2); - $TIMX, $timX, (0), (C3); - $TIMX, $timX, (0), (C4); - ); - - impl Copy for PwmChannel<$TIMX, C1> {} - impl Clone for PwmChannel<$TIMX, C1> { - fn clone(&self) -> Self { - unsafe { mem::MaybeUninit::uninit().assume_init() } - } - } + fn set_period(&mut self, period: T) where + T: Into { + let clk = self.clk; - impl Copy for PwmChannel<$TIMX, C2> {} - impl Clone for PwmChannel<$TIMX, C2> { - fn clone(&self) -> Self { - unsafe { mem::MaybeUninit::uninit().assume_init() } - } - } + // let freq = u16(1 / period.into()); - impl Copy for PwmChannel<$TIMX, C3> {} - impl Clone for PwmChannel<$TIMX, C3> { - fn clone(&self) -> Self { - unsafe { mem::MaybeUninit::uninit().assume_init() } - } + let ticks = clk.0 / period.into().0; + let psc = u16(ticks / (1 << 16)).unwrap(); + let arr = u16(ticks / u32(psc + 1)).unwrap(); + unsafe { + (*$TIMX::ptr()).psc.write(|w| w.psc().bits(psc)); + (*$TIMX::ptr()).arr.write(|w| w.arr().bits(arr)); + } + } } - impl Copy for PwmChannel<$TIMX, C4> {} - impl Clone for PwmChannel<$TIMX, C4> { - fn clone(&self) -> Self { - unsafe { mem::MaybeUninit::uninit().assume_init() } - } - } -*/ impl hal::PwmPin for PwmChannel<$TIMX, C1> { type Duty = u16; From b2b3a074b63a0b4cca0fab151d07c5f6b9925f3b Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Sat, 25 Jan 2020 14:27:31 -0500 Subject: [PATCH 24/30] Update Pwm examples to use new format --- examples/pwm.rs | 16 ++++++++-------- examples/pwm_custom.rs | 21 ++++++++++++--------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/examples/pwm.rs b/examples/pwm.rs index c08a2b27..58eb4695 100644 --- a/examples/pwm.rs +++ b/examples/pwm.rs @@ -11,7 +11,8 @@ use stm32f1xx_hal::{ prelude::*, pac, timer::{Tim2NoRemap, Timer}, - time::U32Ext + time::U32Ext, + pwm::Channel }; use cortex_m_rt::entry; @@ -55,7 +56,7 @@ fn main() -> ! { //// Operations affecting all defined channels on the Timer // Adjust period to 0.5 seconds - pwm.set_period(500.us()); + pwm.set_period(500.ms()); asm::bkpt(); @@ -67,27 +68,26 @@ fn main() -> ! { let max = pwm.get_max_duty(); //// Operations affecting single channels can be accessed through - //// the Pwm object or via dereferencing to the pin. Pin indexing - //// starts at 0. + //// the Pwm object or via dereferencing to the pin. // Use the Pwm object to set C3 to full strength - pwm.set_duty(2, max); + pwm.set_duty(Channel::C2, max); asm::bkpt(); // Use the Pwm object to set C3 to be dim - pwm.set_duty(2, max / 4); + pwm.set_duty(Channel::C2, max / 4); asm::bkpt(); // Use the Pwm object to set C3 to be zero - pwm.set_duty(2, 0); + pwm.set_duty(Channel::C2, 0); asm::bkpt(); // Extract the PwmChannel for C3 - let mut pwm_channel = pwm.2; + let mut pwm_channel = pwm.split().1; // Use the PwmChannel object to set C3 to be full strength pwm_channel.set_duty(max); diff --git a/examples/pwm_custom.rs b/examples/pwm_custom.rs index e11abf1a..46b13a54 100644 --- a/examples/pwm_custom.rs +++ b/examples/pwm_custom.rs @@ -33,28 +33,31 @@ fn main() -> ! { let p0 = pb4.into_alternate_push_pull(&mut gpiob.crl); let p1 = gpiob.pb5.into_alternate_push_pull(&mut gpiob.crl); - let mut pwm = Timer::tim3(p.TIM3, &clocks, &mut rcc.apb1) + let pwm = Timer::tim3(p.TIM3, &clocks, &mut rcc.apb1) .pwm((p0, p1), &mut afio.mapr, 1.khz()); - let max = pwm.0.get_max_duty(); + let max = pwm.get_max_duty(); - pwm.0.enable(); - pwm.1.enable(); + let mut pwm_channels = pwm.split(); + + // Enable the individual channels + pwm_channels.0.enable(); + pwm_channels.1.enable(); // full - pwm.0.set_duty(max); - pwm.1.set_duty(max); + pwm_channels.0.set_duty(max); + pwm_channels.1.set_duty(max); asm::bkpt(); // dim - pwm.1.set_duty(max / 4); + pwm_channels.1.set_duty(max / 4); asm::bkpt(); // zero - pwm.0.set_duty(0); - pwm.1.set_duty(0); + pwm_channels.0.set_duty(0); + pwm_channels.1.set_duty(0); asm::bkpt(); From aa3c331a6309dd34b31a28adb0d68f63c943d608 Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Sat, 25 Jan 2020 14:42:57 -0500 Subject: [PATCH 25/30] Removed old commented code --- src/pwm.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/pwm.rs b/src/pwm.rs index 36762fda..fda5268e 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -379,15 +379,12 @@ macro_rules! hal { // Length in ms of an internal clock pulse (clk.0 / u32(psc * arr)).hz() - // (((psc as u32) / clk.0) * (1_000_000 as u32) * (arr as u32)).ms() } fn set_period(&mut self, period: T) where T: Into { let clk = self.clk; - // let freq = u16(1 / period.into()); - let ticks = clk.0 / period.into().0; let psc = u16(ticks / (1 << 16)).unwrap(); let arr = u16(ticks / u32(psc + 1)).unwrap(); From 4c4c2d146bc02b4b70dfcf3d694d4f48ebd49771 Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Sat, 25 Jan 2020 14:53:39 -0500 Subject: [PATCH 26/30] Change check_enabled to check_used and return Channel vice Option --- src/pwm.rs | 62 ++++++++++++++++++++++++------------------------------ 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/src/pwm.rs b/src/pwm.rs index fda5268e..bbebc84a 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -83,17 +83,15 @@ pub trait Pins { const C4: bool = false; type Channels; - fn check_enabled(c: Channel) -> Option { - if c == Channel::C1 && Self::C1 { - Some(c) - } else if c == Channel::C2 && Self::C2 { - Some(c) - } else if c == Channel::C3 && Self::C3 { - Some(c) - } else if c == Channel::C4 && Self::C4 { - Some(c) + fn check_used(c: Channel) -> Channel { + if (c == Channel::C1 && Self::C1) + || (c == Channel::C2 && Self::C2) + || (c == Channel::C3 && Self::C3) + || (c == Channel::C4 && Self::C4) + { + c } else { - None + panic!("Unused channel") } } } @@ -329,42 +327,38 @@ macro_rules! hal { type Time = Hertz; fn enable(&mut self, channel: Self::Channel) { - match PINS::check_enabled(channel) { - Some(Channel::C1) => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 0) }, - Some(Channel::C2) => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 4) }, - Some(Channel::C3) => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 8) }, - Some(Channel::C4) => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 12) }, - None => {} + match PINS::check_used(channel) { + Channel::C1 => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 0) }, + Channel::C2 => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 4) }, + Channel::C3 => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 8) }, + Channel::C4 => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 12) } } } fn disable(&mut self, channel: Self::Channel) { - match PINS::check_enabled(channel) { - Some(Channel::C1) => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 0) }, - Some(Channel::C2) => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 4) }, - Some(Channel::C3) => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 8) }, - Some(Channel::C4) => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 12) }, - None => {} + match PINS::check_used(channel) { + Channel::C1 => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 0) }, + Channel::C2 => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 4) }, + Channel::C3 => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 8) }, + Channel::C4 => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 12) }, } } fn get_duty(&self, channel: Self::Channel) -> Self::Duty { - match PINS::check_enabled(channel) { - Some(Channel::C1) => unsafe { (*$TIMX::ptr()).ccr1.read().ccr().bits() }, - Some(Channel::C2) => unsafe { (*$TIMX::ptr()).ccr2.read().ccr().bits() }, - Some(Channel::C3) => unsafe { (*$TIMX::ptr()).ccr3.read().ccr().bits() }, - Some(Channel::C4) => unsafe { (*$TIMX::ptr()).ccr4.read().ccr().bits() }, - None => 0, + match PINS::check_used(channel) { + Channel::C1 => unsafe { (*$TIMX::ptr()).ccr1.read().ccr().bits() }, + Channel::C2 => unsafe { (*$TIMX::ptr()).ccr2.read().ccr().bits() }, + Channel::C3 => unsafe { (*$TIMX::ptr()).ccr3.read().ccr().bits() }, + Channel::C4 => unsafe { (*$TIMX::ptr()).ccr4.read().ccr().bits() }, } } fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { - match PINS::check_enabled(channel) { - Some(Channel::C1) => unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr().bits(duty)) }, - Some(Channel::C2) => unsafe { (*$TIMX::ptr()).ccr2.write(|w| w.ccr().bits(duty)) }, - Some(Channel::C3) => unsafe { (*$TIMX::ptr()).ccr3.write(|w| w.ccr().bits(duty)) }, - Some(Channel::C4) => unsafe { (*$TIMX::ptr()).ccr4.write(|w| w.ccr().bits(duty)) }, - None => {}, + match PINS::check_used(channel) { + Channel::C1 => unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr().bits(duty)) }, + Channel::C2 => unsafe { (*$TIMX::ptr()).ccr2.write(|w| w.ccr().bits(duty)) }, + Channel::C3 => unsafe { (*$TIMX::ptr()).ccr3.write(|w| w.ccr().bits(duty)) }, + Channel::C4 => unsafe { (*$TIMX::ptr()).ccr4.write(|w| w.ccr().bits(duty)) }, } } From 1098ab2340bbca82fa88bf1dbb1f988505778bd7 Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Sat, 25 Jan 2020 14:56:31 -0500 Subject: [PATCH 27/30] Use channel C3 in the code to match the comments --- examples/pwm.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/pwm.rs b/examples/pwm.rs index 58eb4695..f224033e 100644 --- a/examples/pwm.rs +++ b/examples/pwm.rs @@ -71,23 +71,23 @@ fn main() -> ! { //// the Pwm object or via dereferencing to the pin. // Use the Pwm object to set C3 to full strength - pwm.set_duty(Channel::C2, max); + pwm.set_duty(Channel::C3, max); asm::bkpt(); // Use the Pwm object to set C3 to be dim - pwm.set_duty(Channel::C2, max / 4); + pwm.set_duty(Channel::C3, max / 4); asm::bkpt(); // Use the Pwm object to set C3 to be zero - pwm.set_duty(Channel::C2, 0); + pwm.set_duty(Channel::C3, 0); asm::bkpt(); // Extract the PwmChannel for C3 - let mut pwm_channel = pwm.split().1; + let mut pwm_channel = pwm.split().2; // Use the PwmChannel object to set C3 to be full strength pwm_channel.set_duty(max); From bca666de7ac26b4bb4032a46c5c47e3b65b1e3ee Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Sun, 15 Mar 2020 06:12:14 -0400 Subject: [PATCH 28/30] Did not actually commit the merge fixes.. --- src/pwm.rs | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/src/pwm.rs b/src/pwm.rs index fbfb2b66..e40769fc 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -137,16 +137,7 @@ pins_impl!( #[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "stm32f105",))] impl Timer { -<<<<<<< HEAD - pub fn pwm( - self, - _pins: PINS, - mapr: &mut MAPR, - freq: T, - ) -> Pwm -======= pub fn pwm(self, _pins: PINS, mapr: &mut MAPR, freq: T) -> PINS::Channels ->>>>>>> master where REMAP: Remap, PINS: Pins, @@ -164,16 +155,7 @@ impl Timer { } impl Timer { -<<<<<<< HEAD - pub fn pwm( - self, - _pins: PINS, - mapr: &mut MAPR, - freq: T, - ) -> Pwm -======= pub fn pwm(self, _pins: PINS, mapr: &mut MAPR, freq: T) -> PINS::Channels ->>>>>>> master where REMAP: Remap, PINS: Pins, @@ -187,16 +169,7 @@ impl Timer { } impl Timer { -<<<<<<< HEAD - pub fn pwm( - self, - _pins: PINS, - mapr: &mut MAPR, - freq: T, - ) -> Pwm -======= pub fn pwm(self, _pins: PINS, mapr: &mut MAPR, freq: T) -> PINS::Channels ->>>>>>> master where REMAP: Remap, PINS: Pins, @@ -211,16 +184,7 @@ impl Timer { #[cfg(feature = "medium")] impl Timer { -<<<<<<< HEAD - pub fn pwm( - self, - _pins: PINS, - mapr: &mut MAPR, - freq: T, - ) -> Pwm -======= pub fn pwm(self, _pins: PINS, mapr: &mut MAPR, freq: T) -> PINS::Channels ->>>>>>> master where REMAP: Remap, PINS: Pins, From 16431d32c70674f595afa0af4a45a11a53eeb9c2 Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Sun, 15 Mar 2020 07:07:10 -0400 Subject: [PATCH 29/30] Re-adjust the return types of the pwm methods --- src/pwm.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pwm.rs b/src/pwm.rs index e40769fc..a3c93f13 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -137,7 +137,7 @@ pins_impl!( #[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "stm32f105",))] impl Timer { - pub fn pwm(self, _pins: PINS, mapr: &mut MAPR, freq: T) -> PINS::Channels + pub fn pwm(self, _pins: PINS, mapr: &mut MAPR, freq: T) -> Pwm where REMAP: Remap, PINS: Pins, @@ -155,7 +155,7 @@ impl Timer { } impl Timer { - pub fn pwm(self, _pins: PINS, mapr: &mut MAPR, freq: T) -> PINS::Channels + pub fn pwm(self, _pins: PINS, mapr: &mut MAPR, freq: T) -> Pwm where REMAP: Remap, PINS: Pins, @@ -169,7 +169,7 @@ impl Timer { } impl Timer { - pub fn pwm(self, _pins: PINS, mapr: &mut MAPR, freq: T) -> PINS::Channels + pub fn pwm(self, _pins: PINS, mapr: &mut MAPR, freq: T) -> Pwm where REMAP: Remap, PINS: Pins, @@ -184,7 +184,7 @@ impl Timer { #[cfg(feature = "medium")] impl Timer { - pub fn pwm(self, _pins: PINS, mapr: &mut MAPR, freq: T) -> PINS::Channels + pub fn pwm(self, _pins: PINS, mapr: &mut MAPR, freq: T) -> Pwm where REMAP: Remap, PINS: Pins, From 013478ab9834c967f1ce883ac8ab2abe35bf085a Mon Sep 17 00:00:00 2001 From: Justace Clutter Date: Mon, 30 Mar 2020 08:00:55 -0400 Subject: [PATCH 30/30] Added changelog message for Pwm implementation --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cf6bbd7..fb8df6f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- Extend the Pwm implementation to cover the full embedded_hal::Pwm API - Replace default blocking spi Write implementation with an optimized one - Use `Deref` for SPI generic implementations instead of macros - Make traits `rcc::Enable` and `rcc::Reset` public, but `RccBus` sealed