make SequenceConfig struct is consistent with other Config structs, that are always non_exhaustive and have a Default

This commit is contained in:
Jacob Rosenthal 2021-11-03 18:37:54 -07:00
parent d961fd1015
commit b726ef1886
3 changed files with 101 additions and 91 deletions

View File

@ -12,43 +12,6 @@ use crate::interrupt::Interrupt;
use crate::pac; use crate::pac;
use crate::util::slice_in_ram_or; 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 /// Interface to the PWM peripheral
pub struct SimplePwm<'d, T: Instance> { pub struct SimplePwm<'d, T: Instance> {
phantom: PhantomData<&'d mut T>, phantom: PhantomData<&'d mut T>,
@ -58,6 +21,18 @@ pub struct SequencePwm<'d, T: Instance> {
phantom: PhantomData<&'d mut T>, 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> { impl<'d, T: Instance> SequencePwm<'d, T> {
/// Creates the interface to a PWM Sequence interface. /// 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 /// mechanisms) on stack allocated buffers which which have been passed to
/// [`new()`](SequencePwm::new). /// [`new()`](SequencePwm::new).
#[allow(unused_unsafe)] #[allow(unused_unsafe)]
pub fn new( pub fn new<'a>(
_pwm: impl Unborrow<Target = T> + 'd, _pwm: impl Unborrow<Target = T> + 'd,
ch0: impl Unborrow<Target = impl GpioOptionalPin> + 'd, ch0: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
ch1: impl Unborrow<Target = impl GpioOptionalPin> + 'd, ch1: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
ch2: impl Unborrow<Target = impl GpioOptionalPin> + 'd, ch2: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
ch3: impl Unborrow<Target = impl GpioOptionalPin> + 'd, ch3: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
config: SequenceConfig, config: SequenceConfig,
sequence: &'a [u16],
) -> Result<Self, Error> { ) -> Result<Self, Error> {
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); return Err(Error::SequenceTooLong);
} }
@ -120,10 +96,10 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
r.seq0 r.seq0
.ptr .ptr
.write(|w| unsafe { w.bits(config.sequence.as_ptr() as u32) }); .write(|w| unsafe { w.bits(sequence.as_ptr() as u32) });
r.seq0 r.seq0
.cnt .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.refresh.write(|w| unsafe { w.bits(config.refresh) });
r.seq0 r.seq0
.enddelay .enddelay
@ -131,10 +107,10 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
r.seq1 r.seq1
.ptr .ptr
.write(|w| unsafe { w.bits(config.sequence.as_ptr() as u32) }); .write(|w| unsafe { w.bits(sequence.as_ptr() as u32) });
r.seq1 r.seq1
.cnt .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.refresh.write(|w| unsafe { w.bits(config.refresh) });
r.seq1 r.seq1
.enddelay .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` /// 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 /// Selects up mode or up-and-down mode for the counter
pub counter_mode: CounterMode, pub counter_mode: CounterMode,
/// Top value to be compared against buffer values /// Top value to be compared against buffer values
pub top: u16, pub top: u16,
/// Configuration for PWM_CLK /// Configuration for PWM_CLK
pub prescaler: Prescaler, 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 /// How a sequence is read from RAM and is spread to the compare register
pub sequence_load: SequenceLoad, pub sequence_load: SequenceLoad,
/// Number of Times PWM periods to delay between each sequence sample /// Number of Times PWM periods to delay between each sequence sample
@ -263,16 +230,62 @@ pub struct SequenceConfig<'a> {
pub end_delay: u32, pub end_delay: u32,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] impl Default for SequenceConfig {
#[cfg_attr(feature = "defmt", derive(defmt::Format))] fn default() -> SequenceConfig {
#[non_exhaustive] SequenceConfig {
pub enum Error { counter_mode: CounterMode::Up,
/// Max Sequence size is 32767 top: 1000,
SequenceTooLong, prescaler: Prescaler::Div16,
/// Min Sequence size is 1 sequence_load: SequenceLoad::Common,
SequenceTimesAtLeastOne, refresh: 0,
/// EasyDMA can only read from data memory, read only buffers in flash will fail. end_delay: 0,
DMABufferNotInDataMemory, }
}
}
#[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> { impl<'d, T: Instance> SimplePwm<'d, T> {

View File

@ -7,9 +7,7 @@ mod example_common;
use defmt::*; use defmt::*;
use embassy::executor::Spawner; use embassy::executor::Spawner;
use embassy::time::{Duration, Timer}; use embassy::time::{Duration, Timer};
use embassy_nrf::pwm::{ use embassy_nrf::pwm::{Prescaler, SequenceConfig, SequenceLoad, SequenceMode, SequencePwm};
CounterMode, Prescaler, SequenceConfig, SequenceLoad, SequenceMode, SequencePwm,
};
use embassy_nrf::Peripherals; use embassy_nrf::Peripherals;
#[embassy::main] #[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, 0x8000, 0, 0, 0, 0, 0x8000, 0, 0, 0, 0, 0x8000, 0, 0, 0, 0, 0x8000,
]; ];
let config = SequenceConfig { let mut config = SequenceConfig::default();
counter_mode: CounterMode::Up, config.top = 15625;
top: 15625, config.prescaler = Prescaler::Div128;
prescaler: Prescaler::Div128, config.sequence_load = SequenceLoad::Individual;
sequence: &seq_values,
sequence_load: SequenceLoad::Individual,
refresh: 0,
end_delay: 0,
};
let pwm = unwrap!(SequencePwm::new( 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)); let _ = pwm.start(SequenceMode::Times(5));
info!("pwm started!"); info!("pwm started!");

View File

@ -9,9 +9,7 @@ use defmt::*;
use embassy::executor::Spawner; use embassy::executor::Spawner;
use embassy::time::{Duration, Timer}; use embassy::time::{Duration, Timer};
use embassy_nrf::gpio::NoPin; use embassy_nrf::gpio::NoPin;
use embassy_nrf::pwm::{ use embassy_nrf::pwm::{CounterMode, SequenceConfig, SequenceMode, SequencePwm};
CounterMode, Prescaler, SequenceConfig, SequenceLoad, SequenceMode, SequencePwm,
};
use embassy_nrf::Peripherals; use embassy_nrf::Peripherals;
use micromath::F32Ext; 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 // 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 seq_values: [u16; 220] = core::array::from_fn(|n| ((W1 * n as f32).sin() * 10000.0) as u16);
let config = SequenceConfig { let mut config = SequenceConfig::default();
counter_mode: CounterMode::UpAndDown, config.counter_mode = CounterMode::UpAndDown;
top: 12000, config.top = 12000;
prescaler: Prescaler::Div16,
sequence: &seq_values,
sequence_load: SequenceLoad::Common,
refresh: 0,
end_delay: 0,
};
let pwm = unwrap!(SequencePwm::new( 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); let _ = pwm.start(SequenceMode::Infinite);
info!("pwm started!"); info!("pwm started!");