diff options
| author | Maarten de Vries <[email protected]> | 2025-10-15 11:58:46 +0200 |
|---|---|---|
| committer | Maarten de Vries <[email protected]> | 2025-10-15 14:42:06 +0200 |
| commit | 5be0e0e7f9d453fc695c1a3c5b8b8148d7a4852a (patch) | |
| tree | ea36650b5923f3c1809e1b24b4b8d43c38c7a207 /embassy-nrf/src | |
| parent | ec97698085e79239b51429f59249a7f42bf04368 (diff) | |
embassy_nrf::pwm: expose duty cycle polarity for SimplePwm
Diffstat (limited to 'embassy-nrf/src')
| -rw-r--r-- | embassy-nrf/src/pwm.rs | 92 |
1 files changed, 85 insertions, 7 deletions
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 1fa8f183b..e47922e5a 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs | |||
| @@ -17,7 +17,7 @@ use crate::{interrupt, pac}; | |||
| 17 | /// to simply set a duty cycle across up to four channels. | 17 | /// to simply set a duty cycle across up to four channels. |
| 18 | pub struct SimplePwm<'d> { | 18 | pub struct SimplePwm<'d> { |
| 19 | r: pac::pwm::Pwm, | 19 | r: pac::pwm::Pwm, |
| 20 | duty: [u16; 4], | 20 | duty: [DutyCycle; 4], |
| 21 | ch0: Option<Peri<'d, AnyPin>>, | 21 | ch0: Option<Peri<'d, AnyPin>>, |
| 22 | ch1: Option<Peri<'d, AnyPin>>, | 22 | ch1: Option<Peri<'d, AnyPin>>, |
| 23 | ch2: Option<Peri<'d, AnyPin>>, | 23 | ch2: Option<Peri<'d, AnyPin>>, |
| @@ -578,6 +578,84 @@ pub enum CounterMode { | |||
| 578 | UpAndDown, | 578 | UpAndDown, |
| 579 | } | 579 | } |
| 580 | 580 | ||
| 581 | /// Duty value and polarity for a single channel. | ||
| 582 | /// | ||
| 583 | /// If the channel has inverted polarity, the output is set high as long as the counter is below the duty value. | ||
| 584 | #[repr(transparent)] | ||
| 585 | #[derive(Eq, PartialEq, Clone, Copy)] | ||
| 586 | pub struct DutyCycle { | ||
| 587 | /// The raw duty cycle valuea. | ||
| 588 | /// | ||
| 589 | /// This has the duty cycle in the lower 15 bits. | ||
| 590 | /// The highest bit indicates that the duty cycle has inverted polarity. | ||
| 591 | raw: u16, | ||
| 592 | } | ||
| 593 | |||
| 594 | impl DutyCycle { | ||
| 595 | /// Make a new duty value with normal polarity. | ||
| 596 | /// | ||
| 597 | /// The value is truncated to 15 bits. | ||
| 598 | /// | ||
| 599 | /// The output is set high if the counter is at or above the duty value. | ||
| 600 | pub const fn normal(value: u16) -> Self { | ||
| 601 | let raw = value & 0x7FFF; | ||
| 602 | Self { raw } | ||
| 603 | } | ||
| 604 | |||
| 605 | /// Make a new duty cycle with inverted polarity. | ||
| 606 | /// | ||
| 607 | /// The value is truncated to 15 bits. | ||
| 608 | /// | ||
| 609 | /// The output is set high if the counter is below the duty value. | ||
| 610 | pub const fn inverted(value: u16) -> Self { | ||
| 611 | let raw = value | 0x8000; | ||
| 612 | Self { raw } | ||
| 613 | } | ||
| 614 | |||
| 615 | /// Adjust the polarity of the duty cycle (returns a new object). | ||
| 616 | #[must_use = "this function return a new object, it does not modify self"] | ||
| 617 | pub const fn with_inverted(self, inverted_polarity: bool) -> Self { | ||
| 618 | if inverted_polarity { | ||
| 619 | Self::inverted(self.value()) | ||
| 620 | } else { | ||
| 621 | Self::normal(self.value()) | ||
| 622 | } | ||
| 623 | } | ||
| 624 | |||
| 625 | /// Gets the 15-bit value of the duty cycle. | ||
| 626 | pub const fn value(&self) -> u16 { | ||
| 627 | self.raw & 0x7FFF | ||
| 628 | } | ||
| 629 | |||
| 630 | /// Checks if the duty period has inverted polarity. | ||
| 631 | /// | ||
| 632 | /// If the channel has inverted polarity, the output is set high as long as the counter is below the duty value. | ||
| 633 | pub const fn is_inverted(&self) -> bool { | ||
| 634 | self.raw & 0x8000 != 0 | ||
| 635 | } | ||
| 636 | } | ||
| 637 | |||
| 638 | impl core::fmt::Debug for DutyCycle { | ||
| 639 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { | ||
| 640 | f.debug_struct("DutyCycle") | ||
| 641 | .field("value", &self.value()) | ||
| 642 | .field("inverted", &self.is_inverted()) | ||
| 643 | .finish() | ||
| 644 | } | ||
| 645 | } | ||
| 646 | |||
| 647 | #[cfg(feature = "defmt")] | ||
| 648 | impl defmt::Format for DutyCycle { | ||
| 649 | fn format(&self, f: defmt::Formatter) { | ||
| 650 | defmt::write!( | ||
| 651 | f, | ||
| 652 | "DutyCycle {{ value: {=u16}, inverted: {=bool} }}", | ||
| 653 | self.value(), | ||
| 654 | self.is_inverted(), | ||
| 655 | ); | ||
| 656 | } | ||
| 657 | } | ||
| 658 | |||
| 581 | impl<'d> SimplePwm<'d> { | 659 | impl<'d> SimplePwm<'d> { |
| 582 | /// Create a new 1-channel PWM | 660 | /// Create a new 1-channel PWM |
| 583 | #[allow(unused_unsafe)] | 661 | #[allow(unused_unsafe)] |
| @@ -650,7 +728,7 @@ impl<'d> SimplePwm<'d> { | |||
| 650 | ch1, | 728 | ch1, |
| 651 | ch2, | 729 | ch2, |
| 652 | ch3, | 730 | ch3, |
| 653 | duty: [0; 4], | 731 | duty: [const { DutyCycle::normal(0) }; 4], |
| 654 | }; | 732 | }; |
| 655 | 733 | ||
| 656 | // Disable all interrupts | 734 | // Disable all interrupts |
| @@ -695,14 +773,14 @@ impl<'d> SimplePwm<'d> { | |||
| 695 | self.r.enable().write(|w| w.set_enable(false)); | 773 | self.r.enable().write(|w| w.set_enable(false)); |
| 696 | } | 774 | } |
| 697 | 775 | ||
| 698 | /// Returns the current duty of the channel | 776 | /// Returns the current duty of the channel. |
| 699 | pub fn duty(&self, channel: usize) -> u16 { | 777 | pub fn duty(&self, channel: usize) -> DutyCycle { |
| 700 | self.duty[channel] | 778 | self.duty[channel] |
| 701 | } | 779 | } |
| 702 | 780 | ||
| 703 | /// Sets duty cycle (15 bit) for a PWM channel. | 781 | /// Sets duty cycle (15 bit) and polarity for a PWM channel. |
| 704 | pub fn set_duty(&mut self, channel: usize, duty: u16) { | 782 | pub fn set_duty(&mut self, channel: usize, duty: DutyCycle) { |
| 705 | self.duty[channel] = duty & 0x7FFF; | 783 | self.duty[channel] = duty; |
| 706 | 784 | ||
| 707 | // reload ptr in case self was moved | 785 | // reload ptr in case self was moved |
| 708 | self.r.seq(0).ptr().write_value((self.duty).as_ptr() as u32); | 786 | self.r.seq(0).ptr().write_value((self.duty).as_ptr() as u32); |
