From 1fed8ac5dbb239e53cdc51b10c27a0c58ea92aeb Mon Sep 17 00:00:00 2001 From: Vincenzo Marturano Date: Thu, 24 Oct 2024 15:12:04 +0200 Subject: [PATCH 1/9] Allow separate control of duty cycle for each channel in a pwm slice by splitting the Pwm driver. --- embassy-rp/src/pwm.rs | 52 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index cfb99c569..4f11eb8f7 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -344,6 +344,58 @@ impl<'d> Pwm<'d> { fn bit(&self) -> u32 { 1 << self.slice as usize } + + #[inline] + /// Split Pwm driver to allow separate duty cycle control of each channel + pub fn split(&self) -> (PwmOutput,PwmOutput){ + (PwmOutput::new(PwmChannel::A,self.slice.clone()),PwmOutput::new(PwmChannel::B,self.slice.clone())) + } +} + +enum PwmChannel{ + A, + B +} + +/// Single channel of Pwm driver. +pub struct PwmOutput { + channel: PwmChannel, + slice: usize +} + +impl PwmOutput { + fn new(channel: PwmChannel,slice: usize) -> Self{ + Self { channel, slice } + } +} + +impl SetDutyCycle for PwmOutput { + fn max_duty_cycle(&self) -> u16 { + pac::PWM.ch(self.slice).top().read().top() + } + + fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { + let max_duty = self.max_duty_cycle(); + if duty > max_duty { + return Err(PwmError::InvalidDutyCycle); + } + + let p = pac::PWM.ch(self.slice); + match self.channel { + PwmChannel::A => { + p.cc().modify(|w| { + w.set_a(duty); + }); + }, + PwmChannel::B => { + p.cc().modify(|w| { + w.set_b(duty); + }); + }, + } + + Ok(()) + } } /// Batch representation of PWM slices. From 2596de52bba32b0d1e755ab18909c10a9e663aad Mon Sep 17 00:00:00 2001 From: Vincenzo Marturano Date: Thu, 24 Oct 2024 15:39:22 +0200 Subject: [PATCH 2/9] Fixed missing trait implementation for PwmOutput. --- embassy-rp/src/pwm.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 4f11eb8f7..66f0dc7f2 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -369,6 +369,10 @@ impl PwmOutput { } } +impl ErrorType for PwmOutput { + type Error = PwmError; +} + impl SetDutyCycle for PwmOutput { fn max_duty_cycle(&self) -> u16 { pac::PWM.ch(self.slice).top().read().top() From 31662eaeef0762a7c7b9c95aee61a9066d7e447a Mon Sep 17 00:00:00 2001 From: Vincenzo Marturano Date: Thu, 24 Oct 2024 16:04:32 +0200 Subject: [PATCH 3/9] Add new() method to PwmBatch so it can be istantiated. --- embassy-rp/src/pwm.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 66f0dc7f2..4da5e5e28 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -406,6 +406,10 @@ impl SetDutyCycle for PwmOutput { pub struct PwmBatch(u32); impl PwmBatch { + #[inline] + pub fn new() -> Self{ + Self(0) + } #[inline] /// Enable a PWM slice in this batch. pub fn enable(&mut self, pwm: &Pwm<'_>) { From 052463212b6b6c1647f517ce38272dd4dd3d4353 Mon Sep 17 00:00:00 2001 From: Vincenzo Marturano Date: Thu, 24 Oct 2024 16:20:28 +0200 Subject: [PATCH 4/9] Revert "Add new() method to PwmBatch so it can be istantiated." This reverts commit 31662eaeef0762a7c7b9c95aee61a9066d7e447a. --- embassy-rp/src/pwm.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 4da5e5e28..66f0dc7f2 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -406,10 +406,6 @@ impl SetDutyCycle for PwmOutput { pub struct PwmBatch(u32); impl PwmBatch { - #[inline] - pub fn new() -> Self{ - Self(0) - } #[inline] /// Enable a PWM slice in this batch. pub fn enable(&mut self, pwm: &Pwm<'_>) { From 336ef01b05e87e6b2b3c9b98e9bdca0c7d78a6af Mon Sep 17 00:00:00 2001 From: Vincenzo Marturano Date: Thu, 24 Oct 2024 19:36:54 +0200 Subject: [PATCH 5/9] Implemented owned split. --- embassy-rp/src/pwm.rs | 47 ++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 66f0dc7f2..5fea0901a 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -347,25 +347,36 @@ impl<'d> Pwm<'d> { #[inline] /// Split Pwm driver to allow separate duty cycle control of each channel - pub fn split(&self) -> (PwmOutput,PwmOutput){ - (PwmOutput::new(PwmChannel::A,self.slice.clone()),PwmOutput::new(PwmChannel::B,self.slice.clone())) + pub fn split(self) -> (Option, Option) { + + let pwm_output_a = if let Some(pin_a) = self.pin_a { + Some(PwmOutput::new(PwmChannelPin::A(pin_a), self.slice.clone())) + }; + + let pwm_output_b = if let Some(pin_b) = self.pin_b { + Some(PwmOutput::new(PwmChannelPin::B(pin_b), self.slice.clone())) + }; + + (pwm_output_a,pwm_output_b) } + } -enum PwmChannel{ - A, - B +enum PwmChannelPin<'d> { + A(PeripheralRef<'d, AnyPin>), + B(PeripheralRef<'d, AnyPin>) } /// Single channel of Pwm driver. -pub struct PwmOutput { - channel: PwmChannel, - slice: usize +pub struct PwmOutput<'d> { + //pin that can be ether ChannelAPin or ChannelBPin + channel_pin: PwmChannelPin<'d> , + slice: usize, } -impl PwmOutput { - fn new(channel: PwmChannel,slice: usize) -> Self{ - Self { channel, slice } +impl <'d> PwmOutput<'d> { + fn new(channel_pin: PwmChannelPin<'d>, slice: usize) -> Self { + Self { channel_pin ,slice } } } @@ -373,7 +384,7 @@ impl ErrorType for PwmOutput { type Error = PwmError; } -impl SetDutyCycle for PwmOutput { +impl<'d> SetDutyCycle for PwmOutput<'d> { fn max_duty_cycle(&self) -> u16 { pac::PWM.ch(self.slice).top().read().top() } @@ -385,19 +396,19 @@ impl SetDutyCycle for PwmOutput { } let p = pac::PWM.ch(self.slice); - match self.channel { - PwmChannel::A => { + match self.channel_pin { + PwmChannelPin::A => { p.cc().modify(|w| { w.set_a(duty); }); - }, - PwmChannel::B => { + } + PwmChannelPin::B => { p.cc().modify(|w| { w.set_b(duty); }); - }, + } } - + Ok(()) } } From 354ff3bac31a910598a6e350499262b3163d50ef Mon Sep 17 00:00:00 2001 From: Vincenzo Marturano Date: Thu, 24 Oct 2024 19:46:23 +0200 Subject: [PATCH 6/9] Fix missing lifetime --- embassy-rp/src/pwm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 5fea0901a..2df2cfad3 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -347,7 +347,7 @@ impl<'d> Pwm<'d> { #[inline] /// Split Pwm driver to allow separate duty cycle control of each channel - pub fn split(self) -> (Option, Option) { + pub fn split(self) -> (Option>, Option>) { let pwm_output_a = if let Some(pin_a) = self.pin_a { Some(PwmOutput::new(PwmChannelPin::A(pin_a), self.slice.clone())) @@ -380,7 +380,7 @@ impl <'d> PwmOutput<'d> { } } -impl ErrorType for PwmOutput { +impl<'d> ErrorType for PwmOutput<'d> { type Error = PwmError; } From 874dbec5a4d11c57c3683a27ac09584e728694c2 Mon Sep 17 00:00:00 2001 From: Vincenzo Marturano Date: Thu, 24 Oct 2024 19:52:09 +0200 Subject: [PATCH 7/9] Fixed mistakes. --- embassy-rp/src/pwm.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 2df2cfad3..443308158 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -351,10 +351,14 @@ impl<'d> Pwm<'d> { let pwm_output_a = if let Some(pin_a) = self.pin_a { Some(PwmOutput::new(PwmChannelPin::A(pin_a), self.slice.clone())) + }else{ + None }; let pwm_output_b = if let Some(pin_b) = self.pin_b { Some(PwmOutput::new(PwmChannelPin::B(pin_b), self.slice.clone())) + }else { + None }; (pwm_output_a,pwm_output_b) @@ -397,12 +401,12 @@ impl<'d> SetDutyCycle for PwmOutput<'d> { let p = pac::PWM.ch(self.slice); match self.channel_pin { - PwmChannelPin::A => { + PwmChannelPin::A(_) => { p.cc().modify(|w| { w.set_a(duty); }); } - PwmChannelPin::B => { + PwmChannelPin::B(_) => { p.cc().modify(|w| { w.set_b(duty); }); From 71fe8a7b90abc7b625d0f5b822508b350f3444d2 Mon Sep 17 00:00:00 2001 From: Vincenzo Marturano Date: Fri, 25 Oct 2024 12:54:06 +0200 Subject: [PATCH 8/9] Fixed owned split and implemented split_by_ref. --- embassy-rp/src/pwm.rs | 80 ++++++++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 20 deletions(-) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 443308158..18d476ed4 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -347,40 +347,80 @@ impl<'d> Pwm<'d> { #[inline] /// Split Pwm driver to allow separate duty cycle control of each channel - pub fn split(self) -> (Option>, Option>) { - - let pwm_output_a = if let Some(pin_a) = self.pin_a { - Some(PwmOutput::new(PwmChannelPin::A(pin_a), self.slice.clone())) - }else{ - None - }; - - let pwm_output_b = if let Some(pin_b) = self.pin_b { - Some(PwmOutput::new(PwmChannelPin::B(pin_b), self.slice.clone())) - }else { - None - }; - - (pwm_output_a,pwm_output_b) + pub fn split(mut self) -> (Option>, Option>) { + ( + self.pin_a + .take() + .map(|pin| PwmOutput::new(PwmChannelPin::A(pin), self.slice.clone(), true)), + self.pin_b + .take() + .map(|pin| PwmOutput::new(PwmChannelPin::B(pin), self.slice.clone(), true)), + ) } + pub fn split_by_ref(&mut self) -> (Option>, Option>) { + ( + self.pin_a + .as_mut() + .map(|pin| PwmOutput::new(PwmChannelPin::A(pin.reborrow()), self.slice.clone(), false)), + self.pin_b + .as_mut() + .map(|pin| PwmOutput::new(PwmChannelPin::B(pin.reborrow()), self.slice.clone(), false)), + ) + } } enum PwmChannelPin<'d> { A(PeripheralRef<'d, AnyPin>), - B(PeripheralRef<'d, AnyPin>) + B(PeripheralRef<'d, AnyPin>), } /// Single channel of Pwm driver. pub struct PwmOutput<'d> { //pin that can be ether ChannelAPin or ChannelBPin - channel_pin: PwmChannelPin<'d> , + channel_pin: PwmChannelPin<'d>, slice: usize, + is_owned: bool, } -impl <'d> PwmOutput<'d> { - fn new(channel_pin: PwmChannelPin<'d>, slice: usize) -> Self { - Self { channel_pin ,slice } +impl<'d> PwmOutput<'d> { + fn new(channel_pin: PwmChannelPin<'d>, slice: usize, is_owned: bool) -> Self { + Self { + channel_pin, + slice, + is_owned, + } + } +} + +impl<'d> Drop for PwmOutput<'d> { + fn drop(&mut self) { + if self.is_owned { + let p = pac::PWM.ch(self.slice); + match &self.channel_pin { + PwmChannelPin::A(pin) => { + p.cc().modify(|w| { + w.set_a(0); + }); + + pin.gpio().ctrl().write(|w| w.set_funcsel(31)); + ///Enable pin PULL-DOWN + pin.pad_ctrl().modify(|w| { + w.set_pde(true); + }); + } + PwmChannelPin::B(pin) => { + p.cc().modify(|w| { + w.set_b(0); + }); + pin.gpio().ctrl().write(|w| w.set_funcsel(31)); + ///Enable pin PULL-DOWN + pin.pad_ctrl().modify(|w| { + w.set_pde(true); + }); + } + } + } } } From 9690bed5a6f9a37bc926c1e86585bc28eb667ebf Mon Sep 17 00:00:00 2001 From: Vincenzo Marturano Date: Fri, 25 Oct 2024 13:12:24 +0200 Subject: [PATCH 9/9] Fix documentation. --- embassy-rp/src/pwm.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 18d476ed4..4fb8ade12 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -345,8 +345,8 @@ impl<'d> Pwm<'d> { 1 << self.slice as usize } + /// Splits the PWM driver into separate `PwmOutput` instances for channels A and B. #[inline] - /// Split Pwm driver to allow separate duty cycle control of each channel pub fn split(mut self) -> (Option>, Option>) { ( self.pin_a @@ -357,7 +357,9 @@ impl<'d> Pwm<'d> { .map(|pin| PwmOutput::new(PwmChannelPin::B(pin), self.slice.clone(), true)), ) } - + /// Splits the PWM driver by reference to allow for separate duty cycle control + /// of each channel (A and B) without taking ownership of the PWM instance. + #[inline] pub fn split_by_ref(&mut self) -> (Option>, Option>) { ( self.pin_a @@ -404,7 +406,7 @@ impl<'d> Drop for PwmOutput<'d> { }); pin.gpio().ctrl().write(|w| w.set_funcsel(31)); - ///Enable pin PULL-DOWN + //Enable pin PULL-DOWN pin.pad_ctrl().modify(|w| { w.set_pde(true); }); @@ -414,7 +416,7 @@ impl<'d> Drop for PwmOutput<'d> { w.set_b(0); }); pin.gpio().ctrl().write(|w| w.set_funcsel(31)); - ///Enable pin PULL-DOWN + //Enable pin PULL-DOWN pin.pad_ctrl().modify(|w| { w.set_pde(true); });