diff options
Diffstat (limited to 'embassy-nrf/src')
| -rw-r--r-- | embassy-nrf/src/pwm.rs | 118 |
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] | ||
| 318 | pub 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 | |||
| 343 | impl 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 | ||
| 644 | impl<'d> SimplePwm<'d> { | 691 | impl<'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 |
