From b726ef1886c65ab76b01f2c54ad559573e19083d Mon Sep 17 00:00:00 2001 From: Jacob Rosenthal Date: Wed, 3 Nov 2021 18:37:54 -0700 Subject: [PATCH] make SequenceConfig struct is consistent with other Config structs, that are always non_exhaustive and have a Default --- embassy-nrf/src/pwm.rs | 143 ++++++++++++++----------- examples/nrf/src/bin/pwm_sequence.rs | 25 +++-- examples/nrf/src/bin/pwm_simple_sin.rs | 24 ++--- 3 files changed, 101 insertions(+), 91 deletions(-) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 0d06f845..9f88633c 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -12,43 +12,6 @@ use crate::interrupt::Interrupt; use crate::pac; use crate::util::slice_in_ram_or; -/// PWM Base clock is system clock (16MHz) divided by prescaler -#[derive(Debug, Eq, PartialEq, Clone, Copy)] -pub enum Prescaler { - Div1, - Div2, - Div4, - Div8, - Div16, - Div32, - Div64, - Div128, -} - -/// How the sequence values are distributed across the channels -#[derive(Debug, Eq, PartialEq, Clone, Copy)] -pub enum SequenceLoad { - /// Provided sequence will be used across all channels - Common, - /// Provided sequence contains grouped values for each channel ex: - /// [ch0_0_and_ch1_0, ch2_0_and_ch3_0, ... ch0_n_and_ch1_n, ch2_n_and_ch3_n] - Grouped, - /// Provided sequence contains individual values for each channel ex: - /// [ch0_0, ch1_0, ch2_0, ch3_0... ch0_n, ch1_n, ch2_n, ch3_n] - Individual, - /// Similar to Individual mode, but only three channels are used. The fourth - /// value is loaded into the pulse generator counter as its top value. - Waveform, -} - -#[derive(Debug, Eq, PartialEq, Clone, Copy)] -pub enum CounterMode { - /// Up counter (edge-aligned PWM duty cycle) - Up, - /// Up and down counter (center-aligned PWM duty cycle) - UpAndDown, -} - /// Interface to the PWM peripheral pub struct SimplePwm<'d, T: Instance> { phantom: PhantomData<&'d mut T>, @@ -58,6 +21,18 @@ pub struct SequencePwm<'d, T: Instance> { phantom: PhantomData<&'d mut T>, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub enum Error { + /// Max Sequence size is 32767 + SequenceTooLong, + /// Min Sequence count is 1 + SequenceTimesAtLeastOne, + /// EasyDMA can only read from data memory, read only buffers in flash will fail. + DMABufferNotInDataMemory, +} + impl<'d, T: Instance> SequencePwm<'d, T> { /// Creates the interface to a PWM Sequence interface. /// @@ -69,17 +44,18 @@ impl<'d, T: Instance> SequencePwm<'d, T> { /// mechanisms) on stack allocated buffers which which have been passed to /// [`new()`](SequencePwm::new). #[allow(unused_unsafe)] - pub fn new( + pub fn new<'a>( _pwm: impl Unborrow + 'd, ch0: impl Unborrow + 'd, ch1: impl Unborrow + 'd, ch2: impl Unborrow + 'd, ch3: impl Unborrow + 'd, config: SequenceConfig, + sequence: &'a [u16], ) -> Result { - slice_in_ram_or(config.sequence, Error::DMABufferNotInDataMemory)?; + slice_in_ram_or(sequence, Error::DMABufferNotInDataMemory)?; - if config.sequence.len() > 32767 { + if sequence.len() > 32767 { return Err(Error::SequenceTooLong); } @@ -120,10 +96,10 @@ impl<'d, T: Instance> SequencePwm<'d, T> { r.seq0 .ptr - .write(|w| unsafe { w.bits(config.sequence.as_ptr() as u32) }); + .write(|w| unsafe { w.bits(sequence.as_ptr() as u32) }); r.seq0 .cnt - .write(|w| unsafe { w.bits(config.sequence.len() as u32) }); + .write(|w| unsafe { w.bits(sequence.len() as u32) }); r.seq0.refresh.write(|w| unsafe { w.bits(config.refresh) }); r.seq0 .enddelay @@ -131,10 +107,10 @@ impl<'d, T: Instance> SequencePwm<'d, T> { r.seq1 .ptr - .write(|w| unsafe { w.bits(config.sequence.as_ptr() as u32) }); + .write(|w| unsafe { w.bits(sequence.as_ptr() as u32) }); r.seq1 .cnt - .write(|w| unsafe { w.bits(config.sequence.len() as u32) }); + .write(|w| unsafe { w.bits(sequence.len() as u32) }); r.seq1.refresh.write(|w| unsafe { w.bits(config.refresh) }); r.seq1 .enddelay @@ -237,24 +213,15 @@ impl<'a, T: Instance> Drop for SequencePwm<'a, T> { } } -#[derive(Debug, Eq, PartialEq, Clone, Copy)] -pub enum SequenceMode { - /// Run sequence n Times total - Times(u16), - /// Repeat until `stop` is called. - Infinite, -} - /// Configure an infinite looping sequence for `simple_playback` -pub struct SequenceConfig<'a> { +#[non_exhaustive] +pub struct SequenceConfig { /// Selects up mode or up-and-down mode for the counter pub counter_mode: CounterMode, /// Top value to be compared against buffer values pub top: u16, /// Configuration for PWM_CLK pub prescaler: Prescaler, - /// In ram buffer to be played back - pub sequence: &'a [u16], /// How a sequence is read from RAM and is spread to the compare register pub sequence_load: SequenceLoad, /// Number of Times PWM periods to delay between each sequence sample @@ -263,16 +230,62 @@ pub struct SequenceConfig<'a> { pub end_delay: u32, } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[non_exhaustive] -pub enum Error { - /// Max Sequence size is 32767 - SequenceTooLong, - /// Min Sequence size is 1 - SequenceTimesAtLeastOne, - /// EasyDMA can only read from data memory, read only buffers in flash will fail. - DMABufferNotInDataMemory, +impl Default for SequenceConfig { + fn default() -> SequenceConfig { + SequenceConfig { + counter_mode: CounterMode::Up, + top: 1000, + prescaler: Prescaler::Div16, + sequence_load: SequenceLoad::Common, + refresh: 0, + end_delay: 0, + } + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Copy)] +pub enum SequenceMode { + /// Run sequence n Times total + Times(u16), + /// Repeat until `stop` is called. + Infinite, +} + +/// PWM Base clock is system clock (16MHz) divided by prescaler +#[derive(Debug, Eq, PartialEq, Clone, Copy)] +pub enum Prescaler { + Div1, + Div2, + Div4, + Div8, + Div16, + Div32, + Div64, + Div128, +} + +/// How the sequence values are distributed across the channels +#[derive(Debug, Eq, PartialEq, Clone, Copy)] +pub enum SequenceLoad { + /// Provided sequence will be used across all channels + Common, + /// Provided sequence contains grouped values for each channel ex: + /// [ch0_0_and_ch1_0, ch2_0_and_ch3_0, ... ch0_n_and_ch1_n, ch2_n_and_ch3_n] + Grouped, + /// Provided sequence contains individual values for each channel ex: + /// [ch0_0, ch1_0, ch2_0, ch3_0... ch0_n, ch1_n, ch2_n, ch3_n] + Individual, + /// Similar to Individual mode, but only three channels are used. The fourth + /// value is loaded into the pulse generator counter as its top value. + Waveform, +} + +#[derive(Debug, Eq, PartialEq, Clone, Copy)] +pub enum CounterMode { + /// Up counter (edge-aligned PWM duty cycle) + Up, + /// Up and down counter (center-aligned PWM duty cycle) + UpAndDown, } impl<'d, T: Instance> SimplePwm<'d, T> { diff --git a/examples/nrf/src/bin/pwm_sequence.rs b/examples/nrf/src/bin/pwm_sequence.rs index 82575d70..3f8b051d 100644 --- a/examples/nrf/src/bin/pwm_sequence.rs +++ b/examples/nrf/src/bin/pwm_sequence.rs @@ -7,9 +7,7 @@ mod example_common; use defmt::*; use embassy::executor::Spawner; use embassy::time::{Duration, Timer}; -use embassy_nrf::pwm::{ - CounterMode, Prescaler, SequenceConfig, SequenceLoad, SequenceMode, SequencePwm, -}; +use embassy_nrf::pwm::{Prescaler, SequenceConfig, SequenceLoad, SequenceMode, SequencePwm}; use embassy_nrf::Peripherals; #[embassy::main] @@ -18,18 +16,19 @@ async fn main(_spawner: Spawner, p: Peripherals) { 0x8000, 0, 0, 0, 0, 0x8000, 0, 0, 0, 0, 0x8000, 0, 0, 0, 0, 0x8000, ]; - let config = SequenceConfig { - counter_mode: CounterMode::Up, - top: 15625, - prescaler: Prescaler::Div128, - sequence: &seq_values, - sequence_load: SequenceLoad::Individual, - refresh: 0, - end_delay: 0, - }; + let mut config = SequenceConfig::default(); + config.top = 15625; + config.prescaler = Prescaler::Div128; + config.sequence_load = SequenceLoad::Individual; let pwm = unwrap!(SequencePwm::new( - p.PWM0, p.P0_13, p.P0_15, p.P0_16, p.P0_14, config + p.PWM0, + p.P0_13, + p.P0_15, + p.P0_16, + p.P0_14, + config, + &seq_values, )); let _ = pwm.start(SequenceMode::Times(5)); info!("pwm started!"); diff --git a/examples/nrf/src/bin/pwm_simple_sin.rs b/examples/nrf/src/bin/pwm_simple_sin.rs index afafb5d9..33fa6dcf 100644 --- a/examples/nrf/src/bin/pwm_simple_sin.rs +++ b/examples/nrf/src/bin/pwm_simple_sin.rs @@ -9,9 +9,7 @@ use defmt::*; use embassy::executor::Spawner; use embassy::time::{Duration, Timer}; use embassy_nrf::gpio::NoPin; -use embassy_nrf::pwm::{ - CounterMode, Prescaler, SequenceConfig, SequenceLoad, SequenceMode, SequencePwm, -}; +use embassy_nrf::pwm::{CounterMode, SequenceConfig, SequenceMode, SequencePwm}; use embassy_nrf::Peripherals; use micromath::F32Ext; @@ -22,18 +20,18 @@ async fn main(_spawner: Spawner, p: Peripherals) { // probably not best use of resources to create the table at runtime, but makes testing fast let seq_values: [u16; 220] = core::array::from_fn(|n| ((W1 * n as f32).sin() * 10000.0) as u16); - let config = SequenceConfig { - counter_mode: CounterMode::UpAndDown, - top: 12000, - prescaler: Prescaler::Div16, - sequence: &seq_values, - sequence_load: SequenceLoad::Common, - refresh: 0, - end_delay: 0, - }; + let mut config = SequenceConfig::default(); + config.counter_mode = CounterMode::UpAndDown; + config.top = 12000; let pwm = unwrap!(SequencePwm::new( - p.PWM0, p.P0_13, NoPin, NoPin, NoPin, config + p.PWM0, + p.P0_13, + NoPin, + NoPin, + NoPin, + config, + &seq_values )); let _ = pwm.start(SequenceMode::Infinite); info!("pwm started!");