aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Rosenthal <[email protected]>2021-11-03 18:37:54 -0700
committerJacob Rosenthal <[email protected]>2021-11-03 18:37:54 -0700
commitb726ef1886c65ab76b01f2c54ad559573e19083d (patch)
tree1be0d14f92e3b60c4088fe63853abfce6defb83b
parentd961fd1015f7911dc1085035c37b0554b0184982 (diff)
make SequenceConfig struct is consistent with other Config structs, that are always non_exhaustive and have a Default
-rw-r--r--embassy-nrf/src/pwm.rs143
-rw-r--r--examples/nrf/src/bin/pwm_sequence.rs25
-rw-r--r--examples/nrf/src/bin/pwm_simple_sin.rs24
3 files changed, 101 insertions, 91 deletions
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs
index 0d06f845c..9f88633c4 100644
--- a/embassy-nrf/src/pwm.rs
+++ b/embassy-nrf/src/pwm.rs
@@ -12,43 +12,6 @@ use crate::interrupt::Interrupt;
12use crate::pac; 12use crate::pac;
13use crate::util::slice_in_ram_or; 13use crate::util::slice_in_ram_or;
14 14
15/// PWM Base clock is system clock (16MHz) divided by prescaler
16#[derive(Debug, Eq, PartialEq, Clone, Copy)]
17pub enum Prescaler {
18 Div1,
19 Div2,
20 Div4,
21 Div8,
22 Div16,
23 Div32,
24 Div64,
25 Div128,
26}
27
28/// How the sequence values are distributed across the channels
29#[derive(Debug, Eq, PartialEq, Clone, Copy)]
30pub enum SequenceLoad {
31 /// Provided sequence will be used across all channels
32 Common,
33 /// Provided sequence contains grouped values for each channel ex:
34 /// [ch0_0_and_ch1_0, ch2_0_and_ch3_0, ... ch0_n_and_ch1_n, ch2_n_and_ch3_n]
35 Grouped,
36 /// Provided sequence contains individual values for each channel ex:
37 /// [ch0_0, ch1_0, ch2_0, ch3_0... ch0_n, ch1_n, ch2_n, ch3_n]
38 Individual,
39 /// Similar to Individual mode, but only three channels are used. The fourth
40 /// value is loaded into the pulse generator counter as its top value.
41 Waveform,
42}
43
44#[derive(Debug, Eq, PartialEq, Clone, Copy)]
45pub enum CounterMode {
46 /// Up counter (edge-aligned PWM duty cycle)
47 Up,
48 /// Up and down counter (center-aligned PWM duty cycle)
49 UpAndDown,
50}
51
52/// Interface to the PWM peripheral 15/// Interface to the PWM peripheral
53pub struct SimplePwm<'d, T: Instance> { 16pub struct SimplePwm<'d, T: Instance> {
54 phantom: PhantomData<&'d mut T>, 17 phantom: PhantomData<&'d mut T>,
@@ -58,6 +21,18 @@ pub struct SequencePwm<'d, T: Instance> {
58 phantom: PhantomData<&'d mut T>, 21 phantom: PhantomData<&'d mut T>,
59} 22}
60 23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26#[non_exhaustive]
27pub enum Error {
28 /// Max Sequence size is 32767
29 SequenceTooLong,
30 /// Min Sequence count is 1
31 SequenceTimesAtLeastOne,
32 /// EasyDMA can only read from data memory, read only buffers in flash will fail.
33 DMABufferNotInDataMemory,
34}
35
61impl<'d, T: Instance> SequencePwm<'d, T> { 36impl<'d, T: Instance> SequencePwm<'d, T> {
62 /// Creates the interface to a PWM Sequence interface. 37 /// Creates the interface to a PWM Sequence interface.
63 /// 38 ///
@@ -69,17 +44,18 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
69 /// mechanisms) on stack allocated buffers which which have been passed to 44 /// mechanisms) on stack allocated buffers which which have been passed to
70 /// [`new()`](SequencePwm::new). 45 /// [`new()`](SequencePwm::new).
71 #[allow(unused_unsafe)] 46 #[allow(unused_unsafe)]
72 pub fn new( 47 pub fn new<'a>(
73 _pwm: impl Unborrow<Target = T> + 'd, 48 _pwm: impl Unborrow<Target = T> + 'd,
74 ch0: impl Unborrow<Target = impl GpioOptionalPin> + 'd, 49 ch0: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
75 ch1: impl Unborrow<Target = impl GpioOptionalPin> + 'd, 50 ch1: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
76 ch2: impl Unborrow<Target = impl GpioOptionalPin> + 'd, 51 ch2: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
77 ch3: impl Unborrow<Target = impl GpioOptionalPin> + 'd, 52 ch3: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
78 config: SequenceConfig, 53 config: SequenceConfig,
54 sequence: &'a [u16],
79 ) -> Result<Self, Error> { 55 ) -> Result<Self, Error> {
80 slice_in_ram_or(config.sequence, Error::DMABufferNotInDataMemory)?; 56 slice_in_ram_or(sequence, Error::DMABufferNotInDataMemory)?;
81 57
82 if config.sequence.len() > 32767 { 58 if sequence.len() > 32767 {
83 return Err(Error::SequenceTooLong); 59 return Err(Error::SequenceTooLong);
84 } 60 }
85 61
@@ -120,10 +96,10 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
120 96
121 r.seq0 97 r.seq0
122 .ptr 98 .ptr
123 .write(|w| unsafe { w.bits(config.sequence.as_ptr() as u32) }); 99 .write(|w| unsafe { w.bits(sequence.as_ptr() as u32) });
124 r.seq0 100 r.seq0
125 .cnt 101 .cnt
126 .write(|w| unsafe { w.bits(config.sequence.len() as u32) }); 102 .write(|w| unsafe { w.bits(sequence.len() as u32) });
127 r.seq0.refresh.write(|w| unsafe { w.bits(config.refresh) }); 103 r.seq0.refresh.write(|w| unsafe { w.bits(config.refresh) });
128 r.seq0 104 r.seq0
129 .enddelay 105 .enddelay
@@ -131,10 +107,10 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
131 107
132 r.seq1 108 r.seq1
133 .ptr 109 .ptr
134 .write(|w| unsafe { w.bits(config.sequence.as_ptr() as u32) }); 110 .write(|w| unsafe { w.bits(sequence.as_ptr() as u32) });
135 r.seq1 111 r.seq1
136 .cnt 112 .cnt
137 .write(|w| unsafe { w.bits(config.sequence.len() as u32) }); 113 .write(|w| unsafe { w.bits(sequence.len() as u32) });
138 r.seq1.refresh.write(|w| unsafe { w.bits(config.refresh) }); 114 r.seq1.refresh.write(|w| unsafe { w.bits(config.refresh) });
139 r.seq1 115 r.seq1
140 .enddelay 116 .enddelay
@@ -237,24 +213,15 @@ impl<'a, T: Instance> Drop for SequencePwm<'a, T> {
237 } 213 }
238} 214}
239 215
240#[derive(Debug, Eq, PartialEq, Clone, Copy)]
241pub enum SequenceMode {
242 /// Run sequence n Times total
243 Times(u16),
244 /// Repeat until `stop` is called.
245 Infinite,
246}
247
248/// Configure an infinite looping sequence for `simple_playback` 216/// Configure an infinite looping sequence for `simple_playback`
249pub struct SequenceConfig<'a> { 217#[non_exhaustive]
218pub struct SequenceConfig {
250 /// Selects up mode or up-and-down mode for the counter 219 /// Selects up mode or up-and-down mode for the counter
251 pub counter_mode: CounterMode, 220 pub counter_mode: CounterMode,
252 /// Top value to be compared against buffer values 221 /// Top value to be compared against buffer values
253 pub top: u16, 222 pub top: u16,
254 /// Configuration for PWM_CLK 223 /// Configuration for PWM_CLK
255 pub prescaler: Prescaler, 224 pub prescaler: Prescaler,
256 /// In ram buffer to be played back
257 pub sequence: &'a [u16],
258 /// How a sequence is read from RAM and is spread to the compare register 225 /// How a sequence is read from RAM and is spread to the compare register
259 pub sequence_load: SequenceLoad, 226 pub sequence_load: SequenceLoad,
260 /// Number of Times PWM periods to delay between each sequence sample 227 /// Number of Times PWM periods to delay between each sequence sample
@@ -263,16 +230,62 @@ pub struct SequenceConfig<'a> {
263 pub end_delay: u32, 230 pub end_delay: u32,
264} 231}
265 232
266#[derive(Debug, Clone, Copy, PartialEq, Eq)] 233impl Default for SequenceConfig {
267#[cfg_attr(feature = "defmt", derive(defmt::Format))] 234 fn default() -> SequenceConfig {
268#[non_exhaustive] 235 SequenceConfig {
269pub enum Error { 236 counter_mode: CounterMode::Up,
270 /// Max Sequence size is 32767 237 top: 1000,
271 SequenceTooLong, 238 prescaler: Prescaler::Div16,
272 /// Min Sequence size is 1 239 sequence_load: SequenceLoad::Common,
273 SequenceTimesAtLeastOne, 240 refresh: 0,
274 /// EasyDMA can only read from data memory, read only buffers in flash will fail. 241 end_delay: 0,
275 DMABufferNotInDataMemory, 242 }
243 }
244}
245
246#[derive(Debug, Eq, PartialEq, Clone, Copy)]
247pub enum SequenceMode {
248 /// Run sequence n Times total
249 Times(u16),
250 /// Repeat until `stop` is called.
251 Infinite,
252}
253
254/// PWM Base clock is system clock (16MHz) divided by prescaler
255#[derive(Debug, Eq, PartialEq, Clone, Copy)]
256pub enum Prescaler {
257 Div1,
258 Div2,
259 Div4,
260 Div8,
261 Div16,
262 Div32,
263 Div64,
264 Div128,
265}
266
267/// How the sequence values are distributed across the channels
268#[derive(Debug, Eq, PartialEq, Clone, Copy)]
269pub enum SequenceLoad {
270 /// Provided sequence will be used across all channels
271 Common,
272 /// Provided sequence contains grouped values for each channel ex:
273 /// [ch0_0_and_ch1_0, ch2_0_and_ch3_0, ... ch0_n_and_ch1_n, ch2_n_and_ch3_n]
274 Grouped,
275 /// Provided sequence contains individual values for each channel ex:
276 /// [ch0_0, ch1_0, ch2_0, ch3_0... ch0_n, ch1_n, ch2_n, ch3_n]
277 Individual,
278 /// Similar to Individual mode, but only three channels are used. The fourth
279 /// value is loaded into the pulse generator counter as its top value.
280 Waveform,
281}
282
283#[derive(Debug, Eq, PartialEq, Clone, Copy)]
284pub enum CounterMode {
285 /// Up counter (edge-aligned PWM duty cycle)
286 Up,
287 /// Up and down counter (center-aligned PWM duty cycle)
288 UpAndDown,
276} 289}
277 290
278impl<'d, T: Instance> SimplePwm<'d, T> { 291impl<'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 82575d703..3f8b051dd 100644
--- a/examples/nrf/src/bin/pwm_sequence.rs
+++ b/examples/nrf/src/bin/pwm_sequence.rs
@@ -7,9 +7,7 @@ mod example_common;
7use defmt::*; 7use defmt::*;
8use embassy::executor::Spawner; 8use embassy::executor::Spawner;
9use embassy::time::{Duration, Timer}; 9use embassy::time::{Duration, Timer};
10use embassy_nrf::pwm::{ 10use embassy_nrf::pwm::{Prescaler, SequenceConfig, SequenceLoad, SequenceMode, SequencePwm};
11 CounterMode, Prescaler, SequenceConfig, SequenceLoad, SequenceMode, SequencePwm,
12};
13use embassy_nrf::Peripherals; 11use embassy_nrf::Peripherals;
14 12
15#[embassy::main] 13#[embassy::main]
@@ -18,18 +16,19 @@ async fn main(_spawner: Spawner, p: Peripherals) {
18 0x8000, 0, 0, 0, 0, 0x8000, 0, 0, 0, 0, 0x8000, 0, 0, 0, 0, 0x8000, 16 0x8000, 0, 0, 0, 0, 0x8000, 0, 0, 0, 0, 0x8000, 0, 0, 0, 0, 0x8000,
19 ]; 17 ];
20 18
21 let config = SequenceConfig { 19 let mut config = SequenceConfig::default();
22 counter_mode: CounterMode::Up, 20 config.top = 15625;
23 top: 15625, 21 config.prescaler = Prescaler::Div128;
24 prescaler: Prescaler::Div128, 22 config.sequence_load = SequenceLoad::Individual;
25 sequence: &seq_values,
26 sequence_load: SequenceLoad::Individual,
27 refresh: 0,
28 end_delay: 0,
29 };
30 23
31 let pwm = unwrap!(SequencePwm::new( 24 let pwm = unwrap!(SequencePwm::new(
32 p.PWM0, p.P0_13, p.P0_15, p.P0_16, p.P0_14, config 25 p.PWM0,
26 p.P0_13,
27 p.P0_15,
28 p.P0_16,
29 p.P0_14,
30 config,
31 &seq_values,
33 )); 32 ));
34 let _ = pwm.start(SequenceMode::Times(5)); 33 let _ = pwm.start(SequenceMode::Times(5));
35 info!("pwm started!"); 34 info!("pwm started!");
diff --git a/examples/nrf/src/bin/pwm_simple_sin.rs b/examples/nrf/src/bin/pwm_simple_sin.rs
index afafb5d96..33fa6dcfe 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::*;
9use embassy::executor::Spawner; 9use embassy::executor::Spawner;
10use embassy::time::{Duration, Timer}; 10use embassy::time::{Duration, Timer};
11use embassy_nrf::gpio::NoPin; 11use embassy_nrf::gpio::NoPin;
12use embassy_nrf::pwm::{ 12use embassy_nrf::pwm::{CounterMode, SequenceConfig, SequenceMode, SequencePwm};
13 CounterMode, Prescaler, SequenceConfig, SequenceLoad, SequenceMode, SequencePwm,
14};
15use embassy_nrf::Peripherals; 13use embassy_nrf::Peripherals;
16use micromath::F32Ext; 14use micromath::F32Ext;
17 15
@@ -22,18 +20,18 @@ async fn main(_spawner: Spawner, p: Peripherals) {
22 // probably not best use of resources to create the table at runtime, but makes testing fast 20 // probably not best use of resources to create the table at runtime, but makes testing fast
23 let seq_values: [u16; 220] = core::array::from_fn(|n| ((W1 * n as f32).sin() * 10000.0) as u16); 21 let seq_values: [u16; 220] = core::array::from_fn(|n| ((W1 * n as f32).sin() * 10000.0) as u16);
24 22
25 let config = SequenceConfig { 23 let mut config = SequenceConfig::default();
26 counter_mode: CounterMode::UpAndDown, 24 config.counter_mode = CounterMode::UpAndDown;
27 top: 12000, 25 config.top = 12000;
28 prescaler: Prescaler::Div16,
29 sequence: &seq_values,
30 sequence_load: SequenceLoad::Common,
31 refresh: 0,
32 end_delay: 0,
33 };
34 26
35 let pwm = unwrap!(SequencePwm::new( 27 let pwm = unwrap!(SequencePwm::new(
36 p.PWM0, p.P0_13, NoPin, NoPin, NoPin, config 28 p.PWM0,
29 p.P0_13,
30 NoPin,
31 NoPin,
32 NoPin,
33 config,
34 &seq_values
37 )); 35 ));
38 let _ = pwm.start(SequenceMode::Infinite); 36 let _ = pwm.start(SequenceMode::Infinite);
39 info!("pwm started!"); 37 info!("pwm started!");