aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-10-25 17:37:15 +0000
committerGitHub <[email protected]>2024-10-25 17:37:15 +0000
commit6bcd05ac830bbeaaa09776a397477ee4022c3499 (patch)
tree2f8c1ca6c0daecebdf041e7fa0c5334384ac0c06
parenta18ca16437db18c857902703274bc18aab960063 (diff)
parent9690bed5a6f9a37bc926c1e86585bc28eb667ebf (diff)
Merge pull request #3454 from vivi202/embassy-rpSplitPwm
Embassy-rp Split Pwm driver to allow separate duty cycle control of each channel.
-rw-r--r--embassy-rp/src/pwm.rs113
1 files changed, 113 insertions, 0 deletions
diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs
index cfb99c569..4fb8ade12 100644
--- a/embassy-rp/src/pwm.rs
+++ b/embassy-rp/src/pwm.rs
@@ -344,6 +344,119 @@ impl<'d> Pwm<'d> {
344 fn bit(&self) -> u32 { 344 fn bit(&self) -> u32 {
345 1 << self.slice as usize 345 1 << self.slice as usize
346 } 346 }
347
348 /// Splits the PWM driver into separate `PwmOutput` instances for channels A and B.
349 #[inline]
350 pub fn split(mut self) -> (Option<PwmOutput<'d>>, Option<PwmOutput<'d>>) {
351 (
352 self.pin_a
353 .take()
354 .map(|pin| PwmOutput::new(PwmChannelPin::A(pin), self.slice.clone(), true)),
355 self.pin_b
356 .take()
357 .map(|pin| PwmOutput::new(PwmChannelPin::B(pin), self.slice.clone(), true)),
358 )
359 }
360 /// Splits the PWM driver by reference to allow for separate duty cycle control
361 /// of each channel (A and B) without taking ownership of the PWM instance.
362 #[inline]
363 pub fn split_by_ref(&mut self) -> (Option<PwmOutput<'_>>, Option<PwmOutput<'_>>) {
364 (
365 self.pin_a
366 .as_mut()
367 .map(|pin| PwmOutput::new(PwmChannelPin::A(pin.reborrow()), self.slice.clone(), false)),
368 self.pin_b
369 .as_mut()
370 .map(|pin| PwmOutput::new(PwmChannelPin::B(pin.reborrow()), self.slice.clone(), false)),
371 )
372 }
373}
374
375enum PwmChannelPin<'d> {
376 A(PeripheralRef<'d, AnyPin>),
377 B(PeripheralRef<'d, AnyPin>),
378}
379
380/// Single channel of Pwm driver.
381pub struct PwmOutput<'d> {
382 //pin that can be ether ChannelAPin or ChannelBPin
383 channel_pin: PwmChannelPin<'d>,
384 slice: usize,
385 is_owned: bool,
386}
387
388impl<'d> PwmOutput<'d> {
389 fn new(channel_pin: PwmChannelPin<'d>, slice: usize, is_owned: bool) -> Self {
390 Self {
391 channel_pin,
392 slice,
393 is_owned,
394 }
395 }
396}
397
398impl<'d> Drop for PwmOutput<'d> {
399 fn drop(&mut self) {
400 if self.is_owned {
401 let p = pac::PWM.ch(self.slice);
402 match &self.channel_pin {
403 PwmChannelPin::A(pin) => {
404 p.cc().modify(|w| {
405 w.set_a(0);
406 });
407
408 pin.gpio().ctrl().write(|w| w.set_funcsel(31));
409 //Enable pin PULL-DOWN
410 pin.pad_ctrl().modify(|w| {
411 w.set_pde(true);
412 });
413 }
414 PwmChannelPin::B(pin) => {
415 p.cc().modify(|w| {
416 w.set_b(0);
417 });
418 pin.gpio().ctrl().write(|w| w.set_funcsel(31));
419 //Enable pin PULL-DOWN
420 pin.pad_ctrl().modify(|w| {
421 w.set_pde(true);
422 });
423 }
424 }
425 }
426 }
427}
428
429impl<'d> ErrorType for PwmOutput<'d> {
430 type Error = PwmError;
431}
432
433impl<'d> SetDutyCycle for PwmOutput<'d> {
434 fn max_duty_cycle(&self) -> u16 {
435 pac::PWM.ch(self.slice).top().read().top()
436 }
437
438 fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
439 let max_duty = self.max_duty_cycle();
440 if duty > max_duty {
441 return Err(PwmError::InvalidDutyCycle);
442 }
443
444 let p = pac::PWM.ch(self.slice);
445 match self.channel_pin {
446 PwmChannelPin::A(_) => {
447 p.cc().modify(|w| {
448 w.set_a(duty);
449 });
450 }
451 PwmChannelPin::B(_) => {
452 p.cc().modify(|w| {
453 w.set_b(duty);
454 });
455 }
456 }
457
458 Ok(())
459 }
347} 460}
348 461
349/// Batch representation of PWM slices. 462/// Batch representation of PWM slices.