aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nrf/src/pwm.rs118
1 files changed, 90 insertions, 28 deletions
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs
index 6743674e8..00b3278c7 100644
--- a/embassy-nrf/src/pwm.rs
+++ b/embassy-nrf/src/pwm.rs
@@ -311,6 +311,53 @@ impl Default for Config {
311 } 311 }
312} 312}
313 313
314/// Configuration for the simple PWM driver.
315#[derive(Debug, Clone)]
316#[cfg_attr(feature = "defmt", derive(defmt::Format))]
317#[non_exhaustive]
318pub struct SimpleConfig {
319 /// Selects up mode or up-and-down mode for the counter
320 pub counter_mode: CounterMode,
321 /// Top value to be compared against buffer values
322 pub max_duty: u16,
323 /// Configuration for PWM_CLK
324 pub prescaler: Prescaler,
325 /// Drive strength for the channel 0 line.
326 pub ch0_drive: OutputDrive,
327 /// Drive strength for the channel 1 line.
328 pub ch1_drive: OutputDrive,
329 /// Drive strength for the channel 2 line.
330 pub ch2_drive: OutputDrive,
331 /// Drive strength for the channel 3 line.
332 pub ch3_drive: OutputDrive,
333 /// Output level for the channel 0 line when PWM if disabled.
334 pub ch0_idle_level: Level,
335 /// Output level for the channel 1 line when PWM if disabled.
336 pub ch1_idle_level: Level,
337 /// Output level for the channel 2 line when PWM if disabled.
338 pub ch2_idle_level: Level,
339 /// Output level for the channel 3 line when PWM if disabled.
340 pub ch3_idle_level: Level,
341}
342
343impl Default for SimpleConfig {
344 fn default() -> Self {
345 Self {
346 counter_mode: CounterMode::Up,
347 max_duty: 1000,
348 prescaler: Prescaler::Div16,
349 ch0_drive: OutputDrive::Standard,
350 ch1_drive: OutputDrive::Standard,
351 ch2_drive: OutputDrive::Standard,
352 ch3_drive: OutputDrive::Standard,
353 ch0_idle_level: Level::Low,
354 ch1_idle_level: Level::Low,
355 ch2_idle_level: Level::Low,
356 ch3_idle_level: Level::Low,
357 }
358 }
359}
360
314/// Configuration per sequence 361/// Configuration per sequence
315#[non_exhaustive] 362#[non_exhaustive]
316#[derive(Debug, Clone)] 363#[derive(Debug, Clone)]
@@ -643,46 +690,48 @@ impl defmt::Format for DutyCycle {
643 690
644impl<'d> SimplePwm<'d> { 691impl<'d> SimplePwm<'d> {
645 /// Create a new 1-channel PWM 692 /// Create a new 1-channel PWM
646 #[allow(unused_unsafe)] 693 pub fn new_1ch<T: Instance>(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, config: &SimpleConfig) -> Self {
647 pub fn new_1ch<T: Instance>(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>) -> Self { 694 Self::new_inner(pwm, Some(ch0.into()), None, None, None, config)
648 unsafe { Self::new_inner(pwm, Some(ch0.into()), None, None, None) }
649 } 695 }
650 696
651 /// Create a new 2-channel PWM 697 /// Create a new 2-channel PWM
652 #[allow(unused_unsafe)] 698 pub fn new_2ch<T: Instance>(
653 pub fn new_2ch<T: Instance>(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, ch1: Peri<'d, impl GpioPin>) -> Self { 699 pwm: Peri<'d, T>,
654 Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), None, None) 700 ch0: Peri<'d, impl GpioPin>,
701 ch1: Peri<'d, impl GpioPin>,
702 config: &SimpleConfig,
703 ) -> Self {
704 Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), None, None, config)
655 } 705 }
656 706
657 /// Create a new 3-channel PWM 707 /// Create a new 3-channel PWM
658 #[allow(unused_unsafe)]
659 pub fn new_3ch<T: Instance>( 708 pub fn new_3ch<T: Instance>(
660 pwm: Peri<'d, T>, 709 pwm: Peri<'d, T>,
661 ch0: Peri<'d, impl GpioPin>, 710 ch0: Peri<'d, impl GpioPin>,
662 ch1: Peri<'d, impl GpioPin>, 711 ch1: Peri<'d, impl GpioPin>,
663 ch2: Peri<'d, impl GpioPin>, 712 ch2: Peri<'d, impl GpioPin>,
713 config: &SimpleConfig,
664 ) -> Self { 714 ) -> Self {
665 unsafe { Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), Some(ch2.into()), None) } 715 Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), Some(ch2.into()), None, config)
666 } 716 }
667 717
668 /// Create a new 4-channel PWM 718 /// Create a new 4-channel PWM
669 #[allow(unused_unsafe)]
670 pub fn new_4ch<T: Instance>( 719 pub fn new_4ch<T: Instance>(
671 pwm: Peri<'d, T>, 720 pwm: Peri<'d, T>,
672 ch0: Peri<'d, impl GpioPin>, 721 ch0: Peri<'d, impl GpioPin>,
673 ch1: Peri<'d, impl GpioPin>, 722 ch1: Peri<'d, impl GpioPin>,
674 ch2: Peri<'d, impl GpioPin>, 723 ch2: Peri<'d, impl GpioPin>,
675 ch3: Peri<'d, impl GpioPin>, 724 ch3: Peri<'d, impl GpioPin>,
725 config: &SimpleConfig,
676 ) -> Self { 726 ) -> Self {
677 unsafe { 727 Self::new_inner(
678 Self::new_inner( 728 pwm,
679 pwm, 729 Some(ch0.into()),
680 Some(ch0.into()), 730 Some(ch1.into()),
681 Some(ch1.into()), 731 Some(ch2.into()),
682 Some(ch2.into()), 732 Some(ch3.into()),
683 Some(ch3.into()), 733 config,
684 ) 734 )
685 }
686 } 735 }
687 736
688 fn new_inner<T: Instance>( 737 fn new_inner<T: Instance>(
@@ -691,24 +740,33 @@ impl<'d> SimplePwm<'d> {
691 ch1: Option<Peri<'d, AnyPin>>, 740 ch1: Option<Peri<'d, AnyPin>>,
692 ch2: Option<Peri<'d, AnyPin>>, 741 ch2: Option<Peri<'d, AnyPin>>,
693 ch3: Option<Peri<'d, AnyPin>>, 742 ch3: Option<Peri<'d, AnyPin>>,
743 config: &SimpleConfig,
694 ) -> Self { 744 ) -> Self {
695 let r = T::regs(); 745 let r = T::regs();
696 746
697 for (i, ch) in [&ch0, &ch1, &ch2, &ch3].into_iter().enumerate() { 747 let channels = [
698 if let Some(pin) = ch { 748 (&ch0, config.ch0_drive, config.ch0_idle_level),
699 pin.set_low(); 749 (&ch1, config.ch1_drive, config.ch1_idle_level),
700 750 (&ch2, config.ch2_drive, config.ch2_idle_level),
751 (&ch3, config.ch3_drive, config.ch3_idle_level),
752 ];
753 for (i, (pin, drive, idle_level)) in channels.into_iter().enumerate() {
754 if let Some(pin) = pin {
755 match idle_level {
756 Level::Low => pin.set_low(),
757 Level::High => pin.set_high(),
758 }
701 pin.conf().write(|w| { 759 pin.conf().write(|w| {
702 w.set_dir(gpiovals::Dir::OUTPUT); 760 w.set_dir(gpiovals::Dir::OUTPUT);
703 w.set_input(gpiovals::Input::DISCONNECT); 761 w.set_input(gpiovals::Input::DISCONNECT);
704 w.set_drive(gpiovals::Drive::S0S1); 762 convert_drive(w, drive);
705 }); 763 });
706 } 764 }
707 r.psel().out(i).write_value(ch.psel_bits()); 765 r.psel().out(i).write_value(pin.psel_bits());
708 } 766 }
709 767
710 let pwm = Self { 768 let pwm = Self {
711 r: T::regs(), 769 r,
712 ch0, 770 ch0,
713 ch1, 771 ch1,
714 ch2, 772 ch2,
@@ -732,9 +790,13 @@ impl<'d> SimplePwm<'d> {
732 w.set_load(vals::Load::INDIVIDUAL); 790 w.set_load(vals::Load::INDIVIDUAL);
733 w.set_mode(vals::Mode::REFRESH_COUNT); 791 w.set_mode(vals::Mode::REFRESH_COUNT);
734 }); 792 });
735 r.mode().write(|w| w.set_updown(vals::Updown::UP)); 793 r.mode().write(|w| match config.counter_mode {
736 r.prescaler().write(|w| w.set_prescaler(vals::Prescaler::DIV_16)); 794 CounterMode::UpAndDown => w.set_updown(vals::Updown::UP_AND_DOWN),
737 r.countertop().write(|w| w.set_countertop(1000)); 795 CounterMode::Up => w.set_updown(vals::Updown::UP),
796 });
797 r.prescaler()
798 .write(|w| w.set_prescaler(vals::Prescaler::from_bits(config.prescaler as u8)));
799 r.countertop().write(|w| w.set_countertop(config.max_duty));
738 r.loop_().write(|w| w.set_cnt(vals::LoopCnt::DISABLED)); 800 r.loop_().write(|w| w.set_cnt(vals::LoopCnt::DISABLED));
739 801
740 pwm 802 pwm