From ec97698085e79239b51429f59249a7f42bf04368 Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Wed, 15 Oct 2025 11:55:40 +0200 Subject: embassy_nrf::pwm: derive more traits for public structs --- embassy-nrf/src/pwm.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index e038f44b8..1fa8f183b 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -289,6 +289,8 @@ impl<'a> Drop for SequencePwm<'a> { } /// Configuration for the PWM as a whole. +#[derive(Debug, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub struct Config { /// Selects up mode or up-and-down mode for the counter @@ -326,7 +328,8 @@ impl Default for Config { /// Configuration per sequence #[non_exhaustive] -#[derive(Clone)] +#[derive(Debug, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct SequenceConfig { /// Number of PWM periods to delay between each sequence sample pub refresh: u32, @@ -345,6 +348,8 @@ impl Default for SequenceConfig { /// A composition of a sequence buffer and its configuration. #[non_exhaustive] +#[derive(Debug, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Sequence<'s> { /// The words comprising the sequence. Must not exceed 32767 words. pub words: &'s [u16], @@ -496,6 +501,7 @@ impl<'d, 's> Drop for Sequencer<'d, 's> { /// How many times to run a single sequence #[derive(Debug, Eq, PartialEq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum SingleSequenceMode { /// Run a single sequence n Times total. Times(u16), @@ -505,6 +511,7 @@ pub enum SingleSequenceMode { /// Which sequence to start a loop with #[derive(Debug, Eq, PartialEq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum StartSequence { /// Start with Sequence 0 Zero, @@ -514,6 +521,7 @@ pub enum StartSequence { /// How many loops to run two sequences #[derive(Debug, Eq, PartialEq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum SequenceMode { /// Run two sequences n loops i.e. (n * (seq0 + seq1.unwrap_or(seq0))) Loop(u16), @@ -523,6 +531,7 @@ pub enum SequenceMode { /// PWM Base clock is system clock (16MHz) divided by prescaler #[derive(Debug, Eq, PartialEq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Prescaler { /// Divide by 1 Div1, @@ -544,6 +553,7 @@ pub enum Prescaler { /// How the sequence values are distributed across the channels #[derive(Debug, Eq, PartialEq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum SequenceLoad { /// Provided sequence will be used across all channels Common, @@ -560,6 +570,7 @@ pub enum SequenceLoad { /// Selects up mode or up-and-down mode for the counter #[derive(Debug, Eq, PartialEq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum CounterMode { /// Up counter (edge-aligned PWM duty cycle) Up, -- cgit From 5be0e0e7f9d453fc695c1a3c5b8b8148d7a4852a Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Wed, 15 Oct 2025 11:58:46 +0200 Subject: embassy_nrf::pwm: expose duty cycle polarity for SimplePwm --- embassy-nrf/src/pwm.rs | 92 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file 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}; /// to simply set a duty cycle across up to four channels. pub struct SimplePwm<'d> { r: pac::pwm::Pwm, - duty: [u16; 4], + duty: [DutyCycle; 4], ch0: Option>, ch1: Option>, ch2: Option>, @@ -578,6 +578,84 @@ pub enum CounterMode { UpAndDown, } +/// Duty value and polarity for a single channel. +/// +/// If the channel has inverted polarity, the output is set high as long as the counter is below the duty value. +#[repr(transparent)] +#[derive(Eq, PartialEq, Clone, Copy)] +pub struct DutyCycle { + /// The raw duty cycle valuea. + /// + /// This has the duty cycle in the lower 15 bits. + /// The highest bit indicates that the duty cycle has inverted polarity. + raw: u16, +} + +impl DutyCycle { + /// Make a new duty value with normal polarity. + /// + /// The value is truncated to 15 bits. + /// + /// The output is set high if the counter is at or above the duty value. + pub const fn normal(value: u16) -> Self { + let raw = value & 0x7FFF; + Self { raw } + } + + /// Make a new duty cycle with inverted polarity. + /// + /// The value is truncated to 15 bits. + /// + /// The output is set high if the counter is below the duty value. + pub const fn inverted(value: u16) -> Self { + let raw = value | 0x8000; + Self { raw } + } + + /// Adjust the polarity of the duty cycle (returns a new object). + #[must_use = "this function return a new object, it does not modify self"] + pub const fn with_inverted(self, inverted_polarity: bool) -> Self { + if inverted_polarity { + Self::inverted(self.value()) + } else { + Self::normal(self.value()) + } + } + + /// Gets the 15-bit value of the duty cycle. + pub const fn value(&self) -> u16 { + self.raw & 0x7FFF + } + + /// Checks if the duty period has inverted polarity. + /// + /// If the channel has inverted polarity, the output is set high as long as the counter is below the duty value. + pub const fn is_inverted(&self) -> bool { + self.raw & 0x8000 != 0 + } +} + +impl core::fmt::Debug for DutyCycle { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + f.debug_struct("DutyCycle") + .field("value", &self.value()) + .field("inverted", &self.is_inverted()) + .finish() + } +} + +#[cfg(feature = "defmt")] +impl defmt::Format for DutyCycle { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "DutyCycle {{ value: {=u16}, inverted: {=bool} }}", + self.value(), + self.is_inverted(), + ); + } +} + impl<'d> SimplePwm<'d> { /// Create a new 1-channel PWM #[allow(unused_unsafe)] @@ -650,7 +728,7 @@ impl<'d> SimplePwm<'d> { ch1, ch2, ch3, - duty: [0; 4], + duty: [const { DutyCycle::normal(0) }; 4], }; // Disable all interrupts @@ -695,14 +773,14 @@ impl<'d> SimplePwm<'d> { self.r.enable().write(|w| w.set_enable(false)); } - /// Returns the current duty of the channel - pub fn duty(&self, channel: usize) -> u16 { + /// Returns the current duty of the channel. + pub fn duty(&self, channel: usize) -> DutyCycle { self.duty[channel] } - /// Sets duty cycle (15 bit) for a PWM channel. - pub fn set_duty(&mut self, channel: usize, duty: u16) { - self.duty[channel] = duty & 0x7FFF; + /// Sets duty cycle (15 bit) and polarity for a PWM channel. + pub fn set_duty(&mut self, channel: usize, duty: DutyCycle) { + self.duty[channel] = duty; // reload ptr in case self was moved self.r.seq(0).ptr().write_value((self.duty).as_ptr() as u32); -- cgit From b2dce7a67e0dc18c568da5758190e23778d025ef Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Wed, 15 Oct 2025 11:59:42 +0200 Subject: embassy_nrf::pwm: allow setting all duty cycles of SimplePwm at once --- embassy-nrf/src/pwm.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index e47922e5a..7fbe9be9d 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -781,7 +781,23 @@ impl<'d> SimplePwm<'d> { /// Sets duty cycle (15 bit) and polarity for a PWM channel. pub fn set_duty(&mut self, channel: usize, duty: DutyCycle) { self.duty[channel] = duty; + self.sync_duty_cyles_to_peripheral(); + } + + /// Sets the duty cycle (15 bit) and polarity for all PWM channels. + /// + /// You can safely set the duty cycle of disabled PWM channels. + /// + /// When using this function, a single DMA transfer sets all the duty cycles. + /// If you call [`Self::set_duty()`] multiple times, + /// each duty cycle will be set by a separate DMA transfer. + pub fn set_all_duties(&mut self, duty: [DutyCycle; 4]) { + self.duty = duty; + self.sync_duty_cyles_to_peripheral(); + } + /// Transfer the duty cycles from `self` to the peripheral. + fn sync_duty_cyles_to_peripheral(&self) { // reload ptr in case self was moved self.r.seq(0).ptr().write_value((self.duty).as_ptr() as u32); -- cgit From 9c66ec1589ae2e55817e03d9e2bb8666050d054c Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Wed, 15 Oct 2025 12:01:18 +0200 Subject: embassy_nrf::pwm: add channel idle level to config --- embassy-nrf/src/pwm.rs | 85 +++++++++++++++++++++----------------------------- 1 file changed, 35 insertions(+), 50 deletions(-) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 7fbe9be9d..6743674e8 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -6,7 +6,7 @@ use core::sync::atomic::{Ordering, compiler_fence}; use embassy_hal_internal::{Peri, PeripheralType}; -use crate::gpio::{AnyPin, DISCONNECTED, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, convert_drive}; +use crate::gpio::{AnyPin, DISCONNECTED, Level, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, convert_drive}; use crate::pac::gpio::vals as gpiovals; use crate::pac::pwm::vals; use crate::ppi::{Event, Task}; @@ -53,13 +53,11 @@ pub const PWM_CLK_HZ: u32 = 16_000_000; impl<'d> SequencePwm<'d> { /// Create a new 1-channel PWM - #[allow(unused_unsafe)] pub fn new_1ch(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, config: Config) -> Result { Self::new_inner(pwm, Some(ch0.into()), None, None, None, config) } /// Create a new 2-channel PWM - #[allow(unused_unsafe)] pub fn new_2ch( pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, @@ -70,7 +68,6 @@ impl<'d> SequencePwm<'d> { } /// Create a new 3-channel PWM - #[allow(unused_unsafe)] pub fn new_3ch( pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, @@ -82,7 +79,6 @@ impl<'d> SequencePwm<'d> { } /// Create a new 4-channel PWM - #[allow(unused_unsafe)] pub fn new_4ch( pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, @@ -111,44 +107,27 @@ impl<'d> SequencePwm<'d> { ) -> Result { let r = T::regs(); - if let Some(pin) = &ch0 { - pin.set_low(); - pin.conf().write(|w| { - w.set_dir(gpiovals::Dir::OUTPUT); - w.set_input(gpiovals::Input::DISCONNECT); - convert_drive(w, config.ch0_drive); - }); - } - if let Some(pin) = &ch1 { - pin.set_low(); - pin.conf().write(|w| { - w.set_dir(gpiovals::Dir::OUTPUT); - w.set_input(gpiovals::Input::DISCONNECT); - convert_drive(w, config.ch1_drive); - }); - } - if let Some(pin) = &ch2 { - pin.set_low(); - pin.conf().write(|w| { - w.set_dir(gpiovals::Dir::OUTPUT); - w.set_input(gpiovals::Input::DISCONNECT); - convert_drive(w, config.ch2_drive); - }); - } - if let Some(pin) = &ch3 { - pin.set_low(); - pin.conf().write(|w| { - w.set_dir(gpiovals::Dir::OUTPUT); - w.set_input(gpiovals::Input::DISCONNECT); - convert_drive(w, config.ch3_drive); - }); + let channels = [ + (&ch0, config.ch0_drive, config.ch0_idle_level), + (&ch1, config.ch1_drive, config.ch1_idle_level), + (&ch2, config.ch2_drive, config.ch2_idle_level), + (&ch3, config.ch3_drive, config.ch3_idle_level), + ]; + for (i, (pin, drive, idle_level)) in channels.into_iter().enumerate() { + if let Some(pin) = pin { + match idle_level { + Level::Low => pin.set_low(), + Level::High => pin.set_high(), + } + pin.conf().write(|w| { + w.set_dir(gpiovals::Dir::OUTPUT); + w.set_input(gpiovals::Input::DISCONNECT); + convert_drive(w, drive); + }); + } + r.psel().out(i).write_value(pin.psel_bits()); } - r.psel().out(0).write_value(ch0.psel_bits()); - r.psel().out(1).write_value(ch1.psel_bits()); - r.psel().out(2).write_value(ch2.psel_bits()); - r.psel().out(3).write_value(ch3.psel_bits()); - // Disable all interrupts r.intenclr().write(|w| w.0 = 0xFFFF_FFFF); r.shorts().write(|_| ()); @@ -173,13 +152,7 @@ impl<'d> SequencePwm<'d> { .write(|w| w.set_prescaler(vals::Prescaler::from_bits(config.prescaler as u8))); r.countertop().write(|w| w.set_countertop(config.max_duty)); - Ok(Self { - r: T::regs(), - ch0, - ch1, - ch2, - ch3, - }) + Ok(Self { r, ch0, ch1, ch2, ch3 }) } /// Returns reference to `Stopped` event endpoint for PPI. @@ -309,11 +282,19 @@ pub struct Config { pub ch2_drive: OutputDrive, /// Drive strength for the channel 3 line. pub ch3_drive: OutputDrive, + /// Output level for the channel 0 line when PWM if disabled. + pub ch0_idle_level: Level, + /// Output level for the channel 1 line when PWM if disabled. + pub ch1_idle_level: Level, + /// Output level for the channel 2 line when PWM if disabled. + pub ch2_idle_level: Level, + /// Output level for the channel 3 line when PWM if disabled. + pub ch3_idle_level: Level, } impl Default for Config { - fn default() -> Config { - Config { + fn default() -> Self { + Self { counter_mode: CounterMode::Up, max_duty: 1000, prescaler: Prescaler::Div16, @@ -322,6 +303,10 @@ impl Default for Config { ch1_drive: OutputDrive::Standard, ch2_drive: OutputDrive::Standard, ch3_drive: OutputDrive::Standard, + ch0_idle_level: Level::Low, + ch1_idle_level: Level::Low, + ch2_idle_level: Level::Low, + ch3_idle_level: Level::Low, } } } -- cgit From eba322b5108e16de2c57a55d96fcedee154b6303 Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Wed, 15 Oct 2025 12:02:39 +0200 Subject: embassy_nrf::pwm: add config argument to SimplePwm constructors --- embassy-nrf/src/pwm.rs | 118 +++++++++++++++++++++++++++++++++++++------------ 1 file 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 { } } +/// Configuration for the simple PWM driver. +#[derive(Debug, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub struct SimpleConfig { + /// Selects up mode or up-and-down mode for the counter + pub counter_mode: CounterMode, + /// Top value to be compared against buffer values + pub max_duty: u16, + /// Configuration for PWM_CLK + pub prescaler: Prescaler, + /// Drive strength for the channel 0 line. + pub ch0_drive: OutputDrive, + /// Drive strength for the channel 1 line. + pub ch1_drive: OutputDrive, + /// Drive strength for the channel 2 line. + pub ch2_drive: OutputDrive, + /// Drive strength for the channel 3 line. + pub ch3_drive: OutputDrive, + /// Output level for the channel 0 line when PWM if disabled. + pub ch0_idle_level: Level, + /// Output level for the channel 1 line when PWM if disabled. + pub ch1_idle_level: Level, + /// Output level for the channel 2 line when PWM if disabled. + pub ch2_idle_level: Level, + /// Output level for the channel 3 line when PWM if disabled. + pub ch3_idle_level: Level, +} + +impl Default for SimpleConfig { + fn default() -> Self { + Self { + counter_mode: CounterMode::Up, + max_duty: 1000, + prescaler: Prescaler::Div16, + ch0_drive: OutputDrive::Standard, + ch1_drive: OutputDrive::Standard, + ch2_drive: OutputDrive::Standard, + ch3_drive: OutputDrive::Standard, + ch0_idle_level: Level::Low, + ch1_idle_level: Level::Low, + ch2_idle_level: Level::Low, + ch3_idle_level: Level::Low, + } + } +} + /// Configuration per sequence #[non_exhaustive] #[derive(Debug, Clone)] @@ -643,46 +690,48 @@ impl defmt::Format for DutyCycle { impl<'d> SimplePwm<'d> { /// Create a new 1-channel PWM - #[allow(unused_unsafe)] - pub fn new_1ch(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>) -> Self { - unsafe { Self::new_inner(pwm, Some(ch0.into()), None, None, None) } + pub fn new_1ch(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, config: &SimpleConfig) -> Self { + Self::new_inner(pwm, Some(ch0.into()), None, None, None, config) } /// Create a new 2-channel PWM - #[allow(unused_unsafe)] - pub fn new_2ch(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, ch1: Peri<'d, impl GpioPin>) -> Self { - Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), None, None) + pub fn new_2ch( + pwm: Peri<'d, T>, + ch0: Peri<'d, impl GpioPin>, + ch1: Peri<'d, impl GpioPin>, + config: &SimpleConfig, + ) -> Self { + Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), None, None, config) } /// Create a new 3-channel PWM - #[allow(unused_unsafe)] pub fn new_3ch( pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, ch1: Peri<'d, impl GpioPin>, ch2: Peri<'d, impl GpioPin>, + config: &SimpleConfig, ) -> Self { - unsafe { Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), Some(ch2.into()), None) } + Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), Some(ch2.into()), None, config) } /// Create a new 4-channel PWM - #[allow(unused_unsafe)] pub fn new_4ch( pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, ch1: Peri<'d, impl GpioPin>, ch2: Peri<'d, impl GpioPin>, ch3: Peri<'d, impl GpioPin>, + config: &SimpleConfig, ) -> Self { - unsafe { - Self::new_inner( - pwm, - Some(ch0.into()), - Some(ch1.into()), - Some(ch2.into()), - Some(ch3.into()), - ) - } + Self::new_inner( + pwm, + Some(ch0.into()), + Some(ch1.into()), + Some(ch2.into()), + Some(ch3.into()), + config, + ) } fn new_inner( @@ -691,24 +740,33 @@ impl<'d> SimplePwm<'d> { ch1: Option>, ch2: Option>, ch3: Option>, + config: &SimpleConfig, ) -> Self { let r = T::regs(); - for (i, ch) in [&ch0, &ch1, &ch2, &ch3].into_iter().enumerate() { - if let Some(pin) = ch { - pin.set_low(); - + let channels = [ + (&ch0, config.ch0_drive, config.ch0_idle_level), + (&ch1, config.ch1_drive, config.ch1_idle_level), + (&ch2, config.ch2_drive, config.ch2_idle_level), + (&ch3, config.ch3_drive, config.ch3_idle_level), + ]; + for (i, (pin, drive, idle_level)) in channels.into_iter().enumerate() { + if let Some(pin) = pin { + match idle_level { + Level::Low => pin.set_low(), + Level::High => pin.set_high(), + } pin.conf().write(|w| { w.set_dir(gpiovals::Dir::OUTPUT); w.set_input(gpiovals::Input::DISCONNECT); - w.set_drive(gpiovals::Drive::S0S1); + convert_drive(w, drive); }); } - r.psel().out(i).write_value(ch.psel_bits()); + r.psel().out(i).write_value(pin.psel_bits()); } let pwm = Self { - r: T::regs(), + r, ch0, ch1, ch2, @@ -732,9 +790,13 @@ impl<'d> SimplePwm<'d> { w.set_load(vals::Load::INDIVIDUAL); w.set_mode(vals::Mode::REFRESH_COUNT); }); - r.mode().write(|w| w.set_updown(vals::Updown::UP)); - r.prescaler().write(|w| w.set_prescaler(vals::Prescaler::DIV_16)); - r.countertop().write(|w| w.set_countertop(1000)); + r.mode().write(|w| match config.counter_mode { + CounterMode::UpAndDown => w.set_updown(vals::Updown::UP_AND_DOWN), + CounterMode::Up => w.set_updown(vals::Updown::UP), + }); + r.prescaler() + .write(|w| w.set_prescaler(vals::Prescaler::from_bits(config.prescaler as u8))); + r.countertop().write(|w| w.set_countertop(config.max_duty)); r.loop_().write(|w| w.set_cnt(vals::LoopCnt::DISABLED)); pwm -- cgit From 3250345748cd25f209ff3426ae01bad55b2c8e9e Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Wed, 15 Oct 2025 14:41:25 +0200 Subject: embassy_nrf: update CHANGELOG --- embassy-nrf/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index 3df7bfd4c..8ce484646 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - added: Add basic RTC support for nRF54L - changed: apply trimming values from FICR.TRIMCNF on nrf53/54l - changed: do not panic on BufferedUarte overrun +- added: allow configuring the idle state of GPIO pins connected to PWM channels +- changed: allow configuring the PWM peripheral in the constructor of `SimplePwm` +- changed: support setting duty cycles with inverted polarity in `SimplePwm` +- added: support setting the duty cycles of all channels at once in `SimplePwm` ## 0.8.0 - 2025-09-30 -- cgit From 369959e654d095d0e3d95597693bd64fcdb50ec5 Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Wed, 15 Oct 2025 14:53:40 +0200 Subject: embassy_nrf: update examples --- examples/nrf52840/src/bin/i2s_monitor.rs | 9 ++++----- examples/nrf52840/src/bin/pwm.rs | 14 ++++++++------ examples/nrf52840/src/bin/pwm_servo.rs | 14 +++++++------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/examples/nrf52840/src/bin/i2s_monitor.rs b/examples/nrf52840/src/bin/i2s_monitor.rs index 66b429b09..a54659101 100644 --- a/examples/nrf52840/src/bin/i2s_monitor.rs +++ b/examples/nrf52840/src/bin/i2s_monitor.rs @@ -4,7 +4,7 @@ use defmt::{debug, error, info}; use embassy_executor::Spawner; use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, I2S, MasterClock, Sample as _, SampleWidth}; -use embassy_nrf::pwm::{Prescaler, SimplePwm}; +use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm}; use embassy_nrf::{bind_interrupts, peripherals}; use {defmt_rtt as _, panic_probe as _}; @@ -34,7 +34,7 @@ async fn main(_spawner: Spawner) { I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers); // Configure the PWM to use the pins corresponding to the RGB leds - let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24); + let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24, &Default::default()); pwm.set_prescaler(Prescaler::Div1); pwm.set_max_duty(255); @@ -47,9 +47,8 @@ async fn main(_spawner: Spawner) { let rgb = rgb_from_rms(rms); debug!("RMS: {}, RGB: {:?}", rms, rgb); - for i in 0..3 { - pwm.set_duty(i, rgb[i].into()); - } + let duties = rgb.map(|byte| DutyCycle::normal(u16::from(byte))); + pwm.set_all_duties([duties[0], duties[1], duties[2], DutyCycle::normal(0)]); if let Err(err) = input_stream.receive().await { error!("{}", err); diff --git a/examples/nrf52840/src/bin/pwm.rs b/examples/nrf52840/src/bin/pwm.rs index a5bb1347a..02f9b4191 100644 --- a/examples/nrf52840/src/bin/pwm.rs +++ b/examples/nrf52840/src/bin/pwm.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_nrf::pwm::{Prescaler, SimplePwm}; +use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -71,7 +71,7 @@ static DUTY: [u16; 1024] = [ #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); - let mut pwm = SimplePwm::new_4ch(p.PWM0, p.P0_13, p.P0_14, p.P0_16, p.P0_15); + let mut pwm = SimplePwm::new_4ch(p.PWM0, p.P0_13, p.P0_14, p.P0_16, p.P0_15, &Default::default()); pwm.set_prescaler(Prescaler::Div1); pwm.set_max_duty(32767); info!("pwm initialized!"); @@ -79,10 +79,12 @@ async fn main(_spawner: Spawner) { let mut i = 0; loop { i += 1; - pwm.set_duty(0, DUTY[i % 1024]); - pwm.set_duty(1, DUTY[(i + 256) % 1024]); - pwm.set_duty(2, DUTY[(i + 512) % 1024]); - pwm.set_duty(3, DUTY[(i + 768) % 1024]); + pwm.set_all_duties([ + DutyCycle::normal(DUTY[i % 1024]), + DutyCycle::normal(DUTY[(i + 256) % 1024]), + DutyCycle::normal(DUTY[(i + 512) % 1024]), + DutyCycle::normal(DUTY[(i + 768) % 1024]), + ]); Timer::after_millis(3).await; } } diff --git a/examples/nrf52840/src/bin/pwm_servo.rs b/examples/nrf52840/src/bin/pwm_servo.rs index d772d2f5d..93cb984e6 100644 --- a/examples/nrf52840/src/bin/pwm_servo.rs +++ b/examples/nrf52840/src/bin/pwm_servo.rs @@ -3,14 +3,14 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_nrf::pwm::{Prescaler, SimplePwm}; +use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); - let mut pwm = SimplePwm::new_1ch(p.PWM0, p.P0_05); + let mut pwm = SimplePwm::new_1ch(p.PWM0, p.P0_05, &Default::default()); // sg90 microervo requires 50hz or 20ms period // set_period can only set down to 125khz so we cant use it directly // Div128 is 125khz or 0.000008s or 0.008ms, 20/0.008 is 2500 is top @@ -24,23 +24,23 @@ async fn main(_spawner: Spawner) { loop { info!("45 deg"); // poor mans inverting, subtract our value from max_duty - pwm.set_duty(0, 2500 - 156); + pwm.set_duty(0, DutyCycle::normal(2500 - 156)); Timer::after_millis(5000).await; info!("90 deg"); - pwm.set_duty(0, 2500 - 187); + pwm.set_duty(0, DutyCycle::normal(2500 - 187)); Timer::after_millis(5000).await; info!("135 deg"); - pwm.set_duty(0, 2500 - 218); + pwm.set_duty(0, DutyCycle::normal(2500 - 218)); Timer::after_millis(5000).await; info!("180 deg"); - pwm.set_duty(0, 2500 - 250); + pwm.set_duty(0, DutyCycle::normal(2500 - 250)); Timer::after_millis(5000).await; info!("0 deg"); - pwm.set_duty(0, 2500 - 125); + pwm.set_duty(0, DutyCycle::normal(2500 - 125)); Timer::after_millis(5000).await; } } -- cgit