make SequenceConfig struct is consistent with other Config structs, that are always non_exhaustive and have a Default
This commit is contained in:
parent
d961fd1015
commit
b726ef1886
@ -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> {
|
||||||
|
@ -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!");
|
||||||
|
@ -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!");
|
||||||
|
Loading…
Reference in New Issue
Block a user