From 7598b8a40fba7e7035d67da5867f27d16818ea62 Mon Sep 17 00:00:00 2001 From: huntc Date: Sun, 23 Jan 2022 16:21:34 +1100 Subject: [PATCH 1/2] Permit many sequences to be passed Sequences are now passed in via the start method to avoid having to stop the PWM and restart it. Sequences continue to be constrained with the same lifetime of the Pwm object itself. The pwm_sequence example has been extended to illustrate multiple sequences being passed around. --- embassy-nrf/src/pwm.rs | 62 ++++++++++++------------ examples/nrf/src/bin/pwm_sequence.rs | 18 +++---- examples/nrf/src/bin/pwm_sequence_ppi.rs | 10 +--- 3 files changed, 43 insertions(+), 47 deletions(-) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 3fdc37ec..cffe5a3b 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -63,14 +63,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { ch2: impl Unborrow + 'd, ch3: impl Unborrow + 'd, config: SequenceConfig, - sequence: &'d [u16], ) -> Result { - slice_in_ram_or(sequence, Error::DMABufferNotInDataMemory)?; - - if sequence.len() > 32767 { - return Err(Error::SequenceTooLong); - } - unborrow!(ch0, ch1, ch2, ch3); let r = T::regs(); @@ -110,28 +103,6 @@ impl<'d, T: Instance> SequencePwm<'d, T> { r.events_seqstarted[0].reset(); r.events_seqstarted[1].reset(); - r.seq0 - .ptr - .write(|w| unsafe { w.bits(sequence.as_ptr() as u32) }); - r.seq0 - .cnt - .write(|w| unsafe { w.bits(sequence.len() as u32) }); - r.seq0.refresh.write(|w| unsafe { w.bits(config.refresh) }); - r.seq0 - .enddelay - .write(|w| unsafe { w.bits(config.end_delay) }); - - r.seq1 - .ptr - .write(|w| unsafe { w.bits(sequence.as_ptr() as u32) }); - r.seq1 - .cnt - .write(|w| unsafe { w.bits(sequence.len() as u32) }); - r.seq1.refresh.write(|w| unsafe { w.bits(config.refresh) }); - r.seq1 - .enddelay - .write(|w| unsafe { w.bits(config.end_delay) }); - r.decoder.write(|w| { w.load().bits(config.sequence_load as u8); w.mode().refresh_count() @@ -146,6 +117,16 @@ impl<'d, T: Instance> SequencePwm<'d, T> { r.countertop .write(|w| unsafe { w.countertop().bits(config.max_duty) }); + r.seq0.refresh.write(|w| unsafe { w.bits(config.refresh) }); + r.seq0 + .enddelay + .write(|w| unsafe { w.bits(config.end_delay) }); + + r.seq1.refresh.write(|w| unsafe { w.bits(config.refresh) }); + r.seq1 + .enddelay + .write(|w| unsafe { w.bits(config.end_delay) }); + Ok(Self { phantom: PhantomData, ch0: ch0.degrade_optional(), @@ -157,12 +138,33 @@ impl<'d, T: Instance> SequencePwm<'d, T> { /// Start or restart playback #[inline(always)] - pub fn start(&self, times: SequenceMode) -> Result<(), Error> { + pub fn start(&self, sequence: &'d [u16], times: SequenceMode) -> Result<(), Error> { + slice_in_ram_or(sequence, Error::DMABufferNotInDataMemory)?; + + if sequence.len() > 32767 { + return Err(Error::SequenceTooLong); + } + if let SequenceMode::Times(0) = times { return Err(Error::SequenceTimesAtLeastOne); } + let r = T::regs(); + r.seq0 + .ptr + .write(|w| unsafe { w.bits(sequence.as_ptr() as u32) }); + r.seq0 + .cnt + .write(|w| unsafe { w.bits(sequence.len() as u32) }); + + r.seq1 + .ptr + .write(|w| unsafe { w.bits(sequence.as_ptr() as u32) }); + r.seq1 + .cnt + .write(|w| unsafe { w.bits(sequence.len() as u32) }); + self.stop(); r.enable.write(|w| w.enable().enabled()); diff --git a/examples/nrf/src/bin/pwm_sequence.rs b/examples/nrf/src/bin/pwm_sequence.rs index 8f57b524..9877b54a 100644 --- a/examples/nrf/src/bin/pwm_sequence.rs +++ b/examples/nrf/src/bin/pwm_sequence.rs @@ -13,7 +13,8 @@ use embassy_nrf::Peripherals; #[embassy::main] async fn main(_spawner: Spawner, p: Peripherals) { - let seq_values: [u16; 5] = [1000, 250, 100, 50, 0]; + let seq_values_1: [u16; 5] = [1000, 250, 100, 50, 0]; + let seq_values_2: [u16; 5] = [0, 50, 100, 250, 1000]; let mut config = SequenceConfig::default(); config.prescaler = Prescaler::Div128; @@ -25,18 +26,17 @@ async fn main(_spawner: Spawner, p: Peripherals) { // thus our sequence takes 5 * 5000ms or 25 seconds let pwm = unwrap!(SequencePwm::new( - p.PWM0, - p.P0_13, - NoPin, - NoPin, - NoPin, - config, - &seq_values + p.PWM0, p.P0_13, NoPin, NoPin, NoPin, config, )); - let _ = pwm.start(SequenceMode::Infinite); + let _ = pwm.start(&seq_values_1, SequenceMode::Infinite); info!("pwm started!"); + Timer::after(Duration::from_millis(20000)).await; + info!("pwm starting with another sequence!"); + + let _ = pwm.start(&seq_values_2, SequenceMode::Infinite); + // we can abort a sequence if we need to before its complete with pwm.stop() // or stop is also implicitly called when the pwm peripheral is dropped // when it goes out of scope diff --git a/examples/nrf/src/bin/pwm_sequence_ppi.rs b/examples/nrf/src/bin/pwm_sequence_ppi.rs index aaea9ff0..f72ccc11 100644 --- a/examples/nrf/src/bin/pwm_sequence_ppi.rs +++ b/examples/nrf/src/bin/pwm_sequence_ppi.rs @@ -27,16 +27,10 @@ async fn main(_spawner: Spawner, p: Peripherals) { config.refresh = 30; let pwm = unwrap!(SequencePwm::new( - p.PWM0, - p.P0_13, - NoPin, - NoPin, - NoPin, - config, - &seq_values + p.PWM0, p.P0_13, NoPin, NoPin, NoPin, config, )); - let _ = pwm.start(SequenceMode::Times(1)); + let _ = pwm.start(&seq_values, SequenceMode::Times(1)); // pwm.stop() deconfigures pins, and then the task_start_seq0 task cant work // so its going to have to start running in order load the configuration From 48afef28a0c85d8296b0b984217350dad75daf46 Mon Sep 17 00:00:00 2001 From: huntc Date: Mon, 24 Jan 2022 17:08:24 +1100 Subject: [PATCH 2/2] Strengthen the borrow The start method is now safe. Because it has the potential of borrowing the sequence and mutating itself, the sequence must outlive the Pwm struct. --- embassy-nrf/src/pwm.rs | 2 +- examples/nrf/src/bin/pwm_sequence.rs | 2 +- examples/nrf/src/bin/pwm_sequence_ppi.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index cffe5a3b..61a28283 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -138,7 +138,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { /// Start or restart playback #[inline(always)] - pub fn start(&self, sequence: &'d [u16], times: SequenceMode) -> Result<(), Error> { + pub fn start(&mut self, sequence: &'d [u16], times: SequenceMode) -> Result<(), Error> { slice_in_ram_or(sequence, Error::DMABufferNotInDataMemory)?; if sequence.len() > 32767 { diff --git a/examples/nrf/src/bin/pwm_sequence.rs b/examples/nrf/src/bin/pwm_sequence.rs index 9877b54a..561bc1dd 100644 --- a/examples/nrf/src/bin/pwm_sequence.rs +++ b/examples/nrf/src/bin/pwm_sequence.rs @@ -25,7 +25,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { config.refresh = 624; // thus our sequence takes 5 * 5000ms or 25 seconds - let pwm = unwrap!(SequencePwm::new( + let mut pwm = unwrap!(SequencePwm::new( p.PWM0, p.P0_13, NoPin, NoPin, NoPin, config, )); let _ = pwm.start(&seq_values_1, SequenceMode::Infinite); diff --git a/examples/nrf/src/bin/pwm_sequence_ppi.rs b/examples/nrf/src/bin/pwm_sequence_ppi.rs index f72ccc11..213ef5ed 100644 --- a/examples/nrf/src/bin/pwm_sequence_ppi.rs +++ b/examples/nrf/src/bin/pwm_sequence_ppi.rs @@ -26,7 +26,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { // thus our sequence takes 5 * 250ms or 1.25 seconds config.refresh = 30; - let pwm = unwrap!(SequencePwm::new( + let mut pwm = unwrap!(SequencePwm::new( p.PWM0, p.P0_13, NoPin, NoPin, NoPin, config, ));