aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nrf/src/pwm.rs108
-rw-r--r--examples/nrf/src/bin/pwm_sequence.rs22
-rw-r--r--examples/nrf/src/bin/pwm_sequence_ppi.rs13
-rw-r--r--examples/nrf/src/bin/pwm_sequence_ws2812b.rs33
4 files changed, 68 insertions, 108 deletions
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs
index 9146160cd..94dfdeda6 100644
--- a/embassy-nrf/src/pwm.rs
+++ b/embassy-nrf/src/pwm.rs
@@ -25,14 +25,14 @@ pub struct SimplePwm<'d, T: Instance> {
25 25
26/// SequencePwm allows you to offload the updating of a sequence of duty cycles 26/// SequencePwm allows you to offload the updating of a sequence of duty cycles
27/// to up to four channels, as well as repeat that sequence n times. 27/// to up to four channels, as well as repeat that sequence n times.
28pub struct SequencePwm<'d, T: Instance, const S0: usize, const S1: usize> { 28pub struct SequencePwm<'d, T: Instance> {
29 phantom: PhantomData<&'d mut T>, 29 phantom: PhantomData<&'d mut T>,
30 ch0: Option<AnyPin>, 30 ch0: Option<AnyPin>,
31 ch1: Option<AnyPin>, 31 ch1: Option<AnyPin>,
32 ch2: Option<AnyPin>, 32 ch2: Option<AnyPin>,
33 ch3: Option<AnyPin>, 33 ch3: Option<AnyPin>,
34 sequence0: Option<Sequence<S0>>, 34 sequence0: Option<Sequence<'d>>,
35 sequence1: Option<Sequence<S1>>, 35 sequence1: Option<Sequence<'d>>,
36} 36}
37 37
38#[derive(Debug, Clone, Copy, PartialEq, Eq)] 38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -43,17 +43,13 @@ pub enum Error {
43 SequenceTooLong, 43 SequenceTooLong,
44 /// Min Sequence count is 1 44 /// Min Sequence count is 1
45 SequenceTimesAtLeastOne, 45 SequenceTimesAtLeastOne,
46 /// Sequence 0 is required, Sequence 1 is NOT required
47 SequenceTimesRequireSeq0Only,
48 /// Sequence 0 is required, Sequence 1 is required
49 SequenceTimesRequireBothSeq0AndSeq1,
50 /// EasyDMA can only read from data memory, read only buffers in flash will fail. 46 /// EasyDMA can only read from data memory, read only buffers in flash will fail.
51 DMABufferNotInDataMemory, 47 DMABufferNotInDataMemory,
52} 48}
53 49
54const MAX_SEQUENCE_LEN: usize = 32767; 50const MAX_SEQUENCE_LEN: usize = 32767;
55 51
56impl<'d, T: Instance, const S0: usize, const S1: usize> SequencePwm<'d, T, S0, S1> { 52impl<'d, T: Instance> SequencePwm<'d, T> {
57 /// Creates the interface to a `SequencePwm`. 53 /// Creates the interface to a `SequencePwm`.
58 /// 54 ///
59 /// Must be started by calling `start` 55 /// Must be started by calling `start`
@@ -72,10 +68,6 @@ impl<'d, T: Instance, const S0: usize, const S1: usize> SequencePwm<'d, T, S0, S
72 ch3: impl Unborrow<Target = impl GpioOptionalPin> + 'd, 68 ch3: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
73 config: Config, 69 config: Config,
74 ) -> Result<Self, Error> { 70 ) -> Result<Self, Error> {
75 if S0 > MAX_SEQUENCE_LEN || S1 > MAX_SEQUENCE_LEN {
76 return Err(Error::SequenceTooLong);
77 }
78
79 unborrow!(ch0, ch1, ch2, ch3); 71 unborrow!(ch0, ch1, ch2, ch3);
80 72
81 let r = T::regs(); 73 let r = T::regs();
@@ -141,49 +133,31 @@ impl<'d, T: Instance, const S0: usize, const S1: usize> SequencePwm<'d, T, S0, S
141 } 133 }
142 134
143 /// Start or restart playback. Takes at least one sequence along with its 135 /// Start or restart playback. Takes at least one sequence along with its
144 /// configuration. A second sequence must be provided when looping i.e. 136 /// configuration. Optionally takes a second sequence and its configuration.
145 /// when the sequence mode is anything other than Times(1). 137 /// In the case where no second sequence is provided then the first sequence
138 /// is used. The sequence mode applies to both sequences combined as one.
146 #[inline(always)] 139 #[inline(always)]
147 pub fn start( 140 pub fn start(
148 &mut self, 141 &mut self,
149 sequence0: Sequence<S0>, 142 sequence0: Sequence<'d>,
150 sequence1: Sequence<S1>, 143 sequence1: Option<Sequence<'d>>,
151 times: SequenceMode, 144 times: SequenceMode,
152 ) -> Result<(), Error> { 145 ) -> Result<(), Error> {
153 slice_in_ram_or(&sequence0.words, Error::DMABufferNotInDataMemory)?; 146 let alt_sequence = sequence1.as_ref().unwrap_or(&sequence0);
154 slice_in_ram_or(&sequence1.words, Error::DMABufferNotInDataMemory)?; 147
148 slice_in_ram_or(sequence0.words, Error::DMABufferNotInDataMemory)?;
149 slice_in_ram_or(alt_sequence.words, Error::DMABufferNotInDataMemory)?;
155 150
156 let seq_0_word_count = sequence0.word_count.unwrap_or(S0); 151 if sequence0.words.len() > MAX_SEQUENCE_LEN || alt_sequence.words.len() > MAX_SEQUENCE_LEN {
157 let seq_1_word_count = sequence0.word_count.unwrap_or(S1);
158 if seq_0_word_count > S0 || seq_1_word_count > S1 {
159 return Err(Error::SequenceTooLong); 152 return Err(Error::SequenceTooLong);
160 } 153 }
161 154
162 match times { 155 if let SequenceMode::Times(0) = times {
163 SequenceMode::Times(0) => return Err(Error::SequenceTimesAtLeastOne), 156 return Err(Error::SequenceTimesAtLeastOne);
164 SequenceMode::Times(1) if seq_0_word_count == 0 || seq_1_word_count != 0 => {
165 return Err(Error::SequenceTimesRequireSeq0Only)
166 }
167 SequenceMode::Times(1) => (),
168 SequenceMode::Times(_) | SequenceMode::Infinite
169 if seq_0_word_count == 0 || seq_1_word_count == 0 =>
170 {
171 return Err(Error::SequenceTimesRequireBothSeq0AndSeq1)
172 }
173 SequenceMode::Times(_) | SequenceMode::Infinite => (),
174 } 157 }
175 158
176 let _ = self.stop(); 159 let _ = self.stop();
177 160
178 // We now own these sequences and they will be moved. We want
179 // the peripheral to point at the right bits of memory hence
180 // moving the sequences early.
181 self.sequence0 = Some(sequence0);
182 self.sequence1 = Some(sequence1);
183
184 let sequence0 = self.sequence0.as_ref().unwrap();
185 let sequence1 = self.sequence1.as_ref().unwrap();
186
187 let r = T::regs(); 161 let r = T::regs();
188 162
189 r.seq0 163 r.seq0
@@ -197,20 +171,20 @@ impl<'d, T: Instance, const S0: usize, const S1: usize> SequencePwm<'d, T, S0, S
197 .write(|w| unsafe { w.bits(sequence0.words.as_ptr() as u32) }); 171 .write(|w| unsafe { w.bits(sequence0.words.as_ptr() as u32) });
198 r.seq0 172 r.seq0
199 .cnt 173 .cnt
200 .write(|w| unsafe { w.bits(seq_0_word_count as u32) }); 174 .write(|w| unsafe { w.bits(sequence0.words.len() as u32) });
201 175
202 r.seq1 176 r.seq1
203 .refresh 177 .refresh
204 .write(|w| unsafe { w.bits(sequence1.config.refresh) }); 178 .write(|w| unsafe { w.bits(alt_sequence.config.refresh) });
205 r.seq1 179 r.seq1
206 .enddelay 180 .enddelay
207 .write(|w| unsafe { w.bits(sequence1.config.end_delay) }); 181 .write(|w| unsafe { w.bits(alt_sequence.config.end_delay) });
208 r.seq1 182 r.seq1
209 .ptr 183 .ptr
210 .write(|w| unsafe { w.bits(sequence1.words.as_ptr() as u32) }); 184 .write(|w| unsafe { w.bits(alt_sequence.words.as_ptr() as u32) });
211 r.seq1 185 r.seq1
212 .cnt 186 .cnt
213 .write(|w| unsafe { w.bits(seq_1_word_count as u32) }); 187 .write(|w| unsafe { w.bits(alt_sequence.words.len() as u32) });
214 188
215 r.enable.write(|w| w.enable().enabled()); 189 r.enable.write(|w| w.enable().enabled());
216 190
@@ -252,6 +226,9 @@ impl<'d, T: Instance, const S0: usize, const S1: usize> SequencePwm<'d, T, S0, S
252 } 226 }
253 } 227 }
254 228
229 self.sequence0 = Some(sequence0);
230 self.sequence1 = sequence1;
231
255 Ok(()) 232 Ok(())
256 } 233 }
257 234
@@ -359,7 +336,7 @@ impl<'d, T: Instance, const S0: usize, const S1: usize> SequencePwm<'d, T, S0, S
359 /// cycle from the pin. Returns any sequences previously provided to 336 /// cycle from the pin. Returns any sequences previously provided to
360 /// `start` so that they may be further mutated. 337 /// `start` so that they may be further mutated.
361 #[inline(always)] 338 #[inline(always)]
362 pub fn stop(&mut self) -> (Option<Sequence<S0>>, Option<Sequence<S1>>) { 339 pub fn stop(&mut self) -> (Option<Sequence<'d>>, Option<Sequence<'d>>) {
363 let r = T::regs(); 340 let r = T::regs();
364 341
365 r.shorts.reset(); 342 r.shorts.reset();
@@ -375,7 +352,7 @@ impl<'d, T: Instance, const S0: usize, const S1: usize> SequencePwm<'d, T, S0, S
375 } 352 }
376} 353}
377 354
378impl<'a, T: Instance, const S0: usize, const S1: usize> Drop for SequencePwm<'a, T, S0, S1> { 355impl<'a, T: Instance> Drop for SequencePwm<'a, T> {
379 fn drop(&mut self) { 356 fn drop(&mut self) {
380 let r = T::regs(); 357 let r = T::regs();
381 358
@@ -404,7 +381,6 @@ impl<'a, T: Instance, const S0: usize, const S1: usize> Drop for SequencePwm<'a,
404 } 381 }
405} 382}
406 383
407/// Configuration for the PWM as a whole.
408#[non_exhaustive] 384#[non_exhaustive]
409pub struct Config { 385pub struct Config {
410 /// Selects up mode or up-and-down mode for the counter 386 /// Selects up mode or up-and-down mode for the counter
@@ -428,7 +404,6 @@ impl Default for Config {
428 } 404 }
429} 405}
430 406
431/// Configuration per sequence
432#[non_exhaustive] 407#[non_exhaustive]
433#[derive(Clone)] 408#[derive(Clone)]
434pub struct SequenceConfig { 409pub struct SequenceConfig {
@@ -447,39 +422,20 @@ impl Default for SequenceConfig {
447 } 422 }
448} 423}
449 424
450/// A composition of a sequence buffer and its configuration.
451#[non_exhaustive] 425#[non_exhaustive]
452#[derive(Clone)] 426pub struct Sequence<'d> {
453pub struct Sequence<const S: usize> {
454 /// The words comprising the sequence. Must not exceed 32767 words. 427 /// The words comprising the sequence. Must not exceed 32767 words.
455 pub words: [u16; S], 428 pub words: &'d mut [u16],
456 /// The count of words to use. If None the S will be used.
457 pub word_count: Option<usize>,
458 /// Configuration associated with the sequence. 429 /// Configuration associated with the sequence.
459 pub config: SequenceConfig, 430 pub config: SequenceConfig,
460} 431}
461 432
462impl<const S: usize> Sequence<S> { 433impl<'d> Sequence<'d> {
463 pub const fn new(words: [u16; S], config: SequenceConfig) -> Self { 434 pub fn new(words: &'d mut [u16], config: SequenceConfig) -> Self {
464 Self { 435 Self { words, config }
465 words,
466 word_count: None,
467 config,
468 }
469 } 436 }
470} 437}
471 438
472/// Declares an empty sequence which will cause it to be disabled.
473/// Note that any looping i.e. !Times(1), will require a second
474/// sequence given the way the PWM peripheral works.
475pub const EMPTY_SEQ: Sequence<0> = Sequence::new(
476 [],
477 SequenceConfig {
478 refresh: 0,
479 end_delay: 0,
480 },
481);
482
483/// How many times to run the sequence 439/// How many times to run the sequence
484#[derive(Debug, Eq, PartialEq, Clone, Copy)] 440#[derive(Debug, Eq, PartialEq, Clone, Copy)]
485pub enum SequenceMode { 441pub enum SequenceMode {
@@ -490,7 +446,7 @@ pub enum SequenceMode {
490 /// 5 to 6 = Run sequence 0, sequence 1, sequence 0, sequence 1, sequence 0 and then sequence 1 446 /// 5 to 6 = Run sequence 0, sequence 1, sequence 0, sequence 1, sequence 0 and then sequence 1
491 /// i.e the when >= 2 the loop count is determined by dividing by 2 and rounding up 447 /// i.e the when >= 2 the loop count is determined by dividing by 2 and rounding up
492 Times(u16), 448 Times(u16),
493 /// Repeat until `stop` is called. Both sequences must be provided. 449 /// Repeat until `stop` is called.
494 Infinite, 450 Infinite,
495} 451}
496 452
diff --git a/examples/nrf/src/bin/pwm_sequence.rs b/examples/nrf/src/bin/pwm_sequence.rs
index 6fe957d24..6fb861e8f 100644
--- a/examples/nrf/src/bin/pwm_sequence.rs
+++ b/examples/nrf/src/bin/pwm_sequence.rs
@@ -8,13 +8,14 @@ use defmt::*;
8use embassy::executor::Spawner; 8use embassy::executor::Spawner;
9use embassy::time::{Duration, Timer}; 9use embassy::time::{Duration, Timer};
10use embassy_nrf::gpio::NoPin; 10use embassy_nrf::gpio::NoPin;
11use embassy_nrf::pwm::{ 11use embassy_nrf::pwm::{Config, Prescaler, Sequence, SequenceConfig, SequenceMode, SequencePwm};
12 Config, Prescaler, Sequence, SequenceConfig, SequenceMode, SequencePwm, EMPTY_SEQ,
13};
14use embassy_nrf::Peripherals; 12use embassy_nrf::Peripherals;
15 13
16#[embassy::main] 14#[embassy::main]
17async fn main(_spawner: Spawner, p: Peripherals) { 15async fn main(_spawner: Spawner, p: Peripherals) {
16 let mut seq_words_1: [u16; 5] = [1000, 250, 100, 50, 0];
17 let mut seq_words_2: [u16; 5] = [0, 50, 100, 250, 1000];
18
18 let mut config = Config::default(); 19 let mut config = Config::default();
19 config.prescaler = Prescaler::Div128; 20 config.prescaler = Prescaler::Div128;
20 // 1 period is 1000 * (128/16mhz = 0.000008s = 0.008ms) = 8us 21 // 1 period is 1000 * (128/16mhz = 0.000008s = 0.008ms) = 8us
@@ -25,20 +26,25 @@ async fn main(_spawner: Spawner, p: Peripherals) {
25 seq_config.refresh = 624; 26 seq_config.refresh = 624;
26 // thus our sequence takes 5 * 5000ms or 25 seconds 27 // thus our sequence takes 5 * 5000ms or 25 seconds
27 28
28 let seq_1 = Sequence::new([1000, 250, 100, 50, 0], seq_config.clone());
29 let seq_2 = Sequence::new([0, 50, 100, 250, 1000], seq_config);
30
31 let mut pwm = unwrap!(SequencePwm::new( 29 let mut pwm = unwrap!(SequencePwm::new(
32 p.PWM0, p.P0_13, NoPin, NoPin, NoPin, config, 30 p.PWM0, p.P0_13, NoPin, NoPin, NoPin, config,
33 )); 31 ));
34 unwrap!(pwm.start(seq_1, EMPTY_SEQ, SequenceMode::Times(1))); 32 let _ = pwm.start(
33 Sequence::new(&mut seq_words_1, seq_config.clone()),
34 None,
35 SequenceMode::Infinite,
36 );
35 37
36 info!("pwm started!"); 38 info!("pwm started!");
37 39
38 Timer::after(Duration::from_millis(20000)).await; 40 Timer::after(Duration::from_millis(20000)).await;
39 info!("pwm starting with another sequence!"); 41 info!("pwm starting with another sequence!");
40 42
41 unwrap!(pwm.start(seq_2, EMPTY_SEQ, SequenceMode::Times(1))); 43 let _ = pwm.start(
44 Sequence::new(&mut seq_words_2, seq_config),
45 None,
46 SequenceMode::Infinite,
47 );
42 48
43 // we can abort a sequence if we need to before its complete with pwm.stop() 49 // we can abort a sequence if we need to before its complete with pwm.stop()
44 // or stop is also implicitly called when the pwm peripheral is dropped 50 // or stop is also implicitly called when the pwm peripheral is dropped
diff --git a/examples/nrf/src/bin/pwm_sequence_ppi.rs b/examples/nrf/src/bin/pwm_sequence_ppi.rs
index 4883222a8..f5d734bb1 100644
--- a/examples/nrf/src/bin/pwm_sequence_ppi.rs
+++ b/examples/nrf/src/bin/pwm_sequence_ppi.rs
@@ -16,7 +16,7 @@ use embassy_nrf::Peripherals;
16 16
17#[embassy::main] 17#[embassy::main]
18async fn main(_spawner: Spawner, p: Peripherals) { 18async fn main(_spawner: Spawner, p: Peripherals) {
19 let seq_words: [u16; 5] = [1000, 250, 100, 50, 0]; 19 let mut seq_words: [u16; 5] = [1000, 250, 100, 50, 0];
20 20
21 let mut config = Config::default(); 21 let mut config = Config::default();
22 config.prescaler = Prescaler::Div128; 22 config.prescaler = Prescaler::Div128;
@@ -31,12 +31,11 @@ async fn main(_spawner: Spawner, p: Peripherals) {
31 p.PWM0, p.P0_13, NoPin, NoPin, NoPin, config, 31 p.PWM0, p.P0_13, NoPin, NoPin, NoPin, config,
32 )); 32 ));
33 33
34 // If we loop in any way i.e. not Times(1), then we must provide 34 let _ = pwm.start(
35 // the PWM peripheral with two sequences. 35 Sequence::new(&mut seq_words, seq_config),
36 let seq_0 = Sequence::new(seq_words, seq_config); 36 None,
37 let seq_1 = seq_0.clone(); 37 SequenceMode::Infinite,
38 38 );
39 unwrap!(pwm.start(seq_0, seq_1, SequenceMode::Infinite));
40 // pwm.stop() deconfigures pins, and then the task_start_seq0 task cant work 39 // pwm.stop() deconfigures pins, and then the task_start_seq0 task cant work
41 // so its going to have to start running in order load the configuration 40 // so its going to have to start running in order load the configuration
42 41
diff --git a/examples/nrf/src/bin/pwm_sequence_ws2812b.rs b/examples/nrf/src/bin/pwm_sequence_ws2812b.rs
index 8acb209cc..0ce79cbe0 100644
--- a/examples/nrf/src/bin/pwm_sequence_ws2812b.rs
+++ b/examples/nrf/src/bin/pwm_sequence_ws2812b.rs
@@ -30,6 +30,19 @@ const RES: u16 = 0x8000;
30// line is assumed to be P1_05. 30// line is assumed to be P1_05.
31#[embassy::main] 31#[embassy::main]
32async fn main(_spawner: Spawner, p: Peripherals) { 32async fn main(_spawner: Spawner, p: Peripherals) {
33 // Declare the bits of 24 bits
34 let mut color_seq_words = [
35 T0H, T0H, T0H, T0H, T0H, T0H, T0H, T0H, // G
36 T0H, T0H, T0H, T0H, T0H, T0H, T0H, T0H, // R
37 T1H, T1H, T1H, T1H, T1H, T1H, T1H, T1H, // B
38 ];
39 let color_seq = Sequence::new(&mut color_seq_words, SequenceConfig::default());
40
41 let mut reset_seq_words = [RES; 1];
42 let mut reset_seq_config = SequenceConfig::default();
43 reset_seq_config.end_delay = 799; // 50us (20 ticks * 40) - 1 tick because we've already got one RES;
44 let reset_seq = Sequence::new(&mut reset_seq_words, reset_seq_config);
45
33 let mut config = Config::default(); 46 let mut config = Config::default();
34 config.sequence_load = SequenceLoad::Common; 47 config.sequence_load = SequenceLoad::Common;
35 config.prescaler = Prescaler::Div1; 48 config.prescaler = Prescaler::Div1;
@@ -38,21 +51,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
38 p.PWM0, p.P1_05, NoPin, NoPin, NoPin, config, 51 p.PWM0, p.P1_05, NoPin, NoPin, NoPin, config,
39 )); 52 ));
40 53
41 // Declare the bits of 24 bits 54 unwrap!(pwm.start(color_seq, Some(reset_seq), SequenceMode::Times(2)));
42 let color_seq = Sequence::new(
43 [
44 T0H, T0H, T0H, T0H, T0H, T0H, T0H, T0H, // G
45 T0H, T0H, T0H, T0H, T0H, T0H, T0H, T0H, // R
46 T1H, T1H, T1H, T1H, T1H, T1H, T1H, T1H, // B
47 ],
48 SequenceConfig::default(),
49 );
50
51 let mut reset_seq_config = SequenceConfig::default();
52 reset_seq_config.end_delay = 799; // 50us (20 ticks * 40) - 1 tick because we've already got one RES;
53 let reset_seq = Sequence::new([RES], reset_seq_config);
54
55 unwrap!(pwm.start(color_seq, reset_seq, SequenceMode::Times(2)));
56 55
57 Timer::after(Duration::from_millis(1000)).await; 56 Timer::after(Duration::from_millis(1000)).await;
58 57
@@ -60,9 +59,9 @@ async fn main(_spawner: Spawner, p: Peripherals) {
60 let mut bit_value = T0H; 59 let mut bit_value = T0H;
61 60
62 loop { 61 loop {
63 if let (Some(mut color_seq), Some(reset_seq)) = pwm.stop() { 62 if let (Some(color_seq), Some(reset_seq)) = pwm.stop() {
64 color_seq.words[color_bit] = bit_value; 63 color_seq.words[color_bit] = bit_value;
65 unwrap!(pwm.start(color_seq, reset_seq, SequenceMode::Times(2))); 64 unwrap!(pwm.start(color_seq, Some(reset_seq), SequenceMode::Times(2)));
66 } 65 }
67 66
68 Timer::after(Duration::from_millis(50)).await; 67 Timer::after(Duration::from_millis(50)).await;