aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhuntc <[email protected]>2022-02-04 13:04:55 +1100
committerhuntc <[email protected]>2022-02-04 13:04:55 +1100
commit1af6b23f970d80d881bbc83fe69846e14c512e1c (patch)
treedabe8b1b01350098387ff349ca66a2d6be12ffe1
parentbc7266394ddba3d6128cc9de131109c2454f3d05 (diff)
Introduces a Sequences struct
-rw-r--r--embassy-nrf/src/pwm.rs274
-rw-r--r--examples/nrf/src/bin/pwm_sequence_ws2812b.rs39
2 files changed, 161 insertions, 152 deletions
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs
index e561f0383..b696cbe63 100644
--- a/embassy-nrf/src/pwm.rs
+++ b/embassy-nrf/src/pwm.rs
@@ -31,8 +31,6 @@ pub struct SequencePwm<'d, T: Instance> {
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<'d>>,
35 sequence1: Option<Sequence<'d>>,
36} 34}
37 35
38#[derive(Debug, Clone, Copy, PartialEq, Eq)] 36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -127,111 +125,9 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
127 ch1: ch1.degrade_optional(), 125 ch1: ch1.degrade_optional(),
128 ch2: ch2.degrade_optional(), 126 ch2: ch2.degrade_optional(),
129 ch3: ch3.degrade_optional(), 127 ch3: ch3.degrade_optional(),
130 sequence0: None,
131 sequence1: None,
132 }) 128 })
133 } 129 }
134 130
135 /// Start or restart playback. Takes at least one sequence along with its
136 /// configuration. Optionally takes a second sequence and its configuration.
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.
139 #[inline(always)]
140 pub fn start(
141 &mut self,
142 sequence0: Sequence<'d>,
143 sequence1: Option<Sequence<'d>>,
144 times: SequenceMode,
145 ) -> Result<(), Error> {
146 let alt_sequence = sequence1.as_ref().unwrap_or(&sequence0);
147
148 slice_in_ram_or(sequence0.words, Error::DMABufferNotInDataMemory)?;
149 slice_in_ram_or(alt_sequence.words, Error::DMABufferNotInDataMemory)?;
150
151 if sequence0.words.len() > MAX_SEQUENCE_LEN || alt_sequence.words.len() > MAX_SEQUENCE_LEN {
152 return Err(Error::SequenceTooLong);
153 }
154
155 if let SequenceMode::Times(0) = times {
156 return Err(Error::SequenceTimesAtLeastOne);
157 }
158
159 let _ = self.stop();
160
161 let r = T::regs();
162
163 r.seq0
164 .refresh
165 .write(|w| unsafe { w.bits(sequence0.config.refresh) });
166 r.seq0
167 .enddelay
168 .write(|w| unsafe { w.bits(sequence0.config.end_delay) });
169 r.seq0
170 .ptr
171 .write(|w| unsafe { w.bits(sequence0.words.as_ptr() as u32) });
172 r.seq0
173 .cnt
174 .write(|w| unsafe { w.bits(sequence0.words.len() as u32) });
175
176 r.seq1
177 .refresh
178 .write(|w| unsafe { w.bits(alt_sequence.config.refresh) });
179 r.seq1
180 .enddelay
181 .write(|w| unsafe { w.bits(alt_sequence.config.end_delay) });
182 r.seq1
183 .ptr
184 .write(|w| unsafe { w.bits(alt_sequence.words.as_ptr() as u32) });
185 r.seq1
186 .cnt
187 .write(|w| unsafe { w.bits(alt_sequence.words.len() as u32) });
188
189 r.enable.write(|w| w.enable().enabled());
190
191 // defensive before seqstart
192 compiler_fence(Ordering::SeqCst);
193
194 match times {
195 // just the one time, no loop count
196 SequenceMode::Times(1) => {
197 r.loop_.write(|w| w.cnt().disabled());
198 // tasks_seqstart() doesn't exist in all svds so write its bit instead
199 r.tasks_seqstart[0].write(|w| unsafe { w.bits(0x01) });
200 }
201 // loop count is how many times to play BOTH sequences
202 // 2 total (1 x 2)
203 // 3 total, (2 x 2) - 1
204 SequenceMode::Times(n) => {
205 let odd = n & 1 == 1;
206 let times = if odd { (n / 2) + 1 } else { n / 2 };
207
208 r.loop_.write(|w| unsafe { w.cnt().bits(times) });
209
210 // we can subtract 1 by starting at seq1 instead of seq0
211 if odd {
212 // tasks_seqstart() doesn't exist in all svds so write its bit instead
213 r.tasks_seqstart[1].write(|w| unsafe { w.bits(0x01) });
214 } else {
215 // tasks_seqstart() doesn't exist in all svds so write its bit instead
216 r.tasks_seqstart[0].write(|w| unsafe { w.bits(0x01) });
217 }
218 }
219 // to play infinitely, repeat the sequence one time, then have loops done self trigger seq0 again
220 SequenceMode::Infinite => {
221 r.loop_.write(|w| unsafe { w.cnt().bits(0x1) });
222 r.shorts.write(|w| w.loopsdone_seqstart0().enabled());
223
224 // tasks_seqstart() doesn't exist in all svds so write its bit instead
225 r.tasks_seqstart[0].write(|w| unsafe { w.bits(0x01) });
226 }
227 }
228
229 self.sequence0 = Some(sequence0);
230 self.sequence1 = sequence1;
231
232 Ok(())
233 }
234
235 /// Returns reference to `Stopped` event endpoint for PPI. 131 /// Returns reference to `Stopped` event endpoint for PPI.
236 #[inline(always)] 132 #[inline(always)]
237 pub fn event_stopped(&self) -> Event { 133 pub fn event_stopped(&self) -> Event {
@@ -331,33 +227,12 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
331 227
332 Task::from_reg(&r.tasks_stop) 228 Task::from_reg(&r.tasks_stop)
333 } 229 }
334
335 /// Stop playback. Disables the peripheral. Does NOT clear the last duty
336 /// cycle from the pin. Returns any sequences previously provided to
337 /// `start` so that they may be further mutated.
338 #[inline(always)]
339 pub fn stop(&mut self) -> (Option<Sequence<'d>>, Option<Sequence<'d>>) {
340 let r = T::regs();
341
342 r.shorts.reset();
343
344 compiler_fence(Ordering::SeqCst);
345
346 // tasks_stop() doesn't exist in all svds so write its bit instead
347 r.tasks_stop.write(|w| unsafe { w.bits(0x01) });
348
349 r.enable.write(|w| w.enable().disabled());
350
351 (self.sequence0.take(), self.sequence1.take())
352 }
353} 230}
354 231
355impl<'a, T: Instance> Drop for SequencePwm<'a, T> { 232impl<'a, T: Instance> Drop for SequencePwm<'a, T> {
356 fn drop(&mut self) { 233 fn drop(&mut self) {
357 let r = T::regs(); 234 let r = T::regs();
358 235
359 let _ = self.stop();
360
361 if let Some(pin) = &self.ch0 { 236 if let Some(pin) = &self.ch0 {
362 pin.set_low(); 237 pin.set_low();
363 pin.conf().reset(); 238 pin.conf().reset();
@@ -426,21 +301,158 @@ impl Default for SequenceConfig {
426 301
427/// A composition of a sequence buffer and its configuration. 302/// A composition of a sequence buffer and its configuration.
428#[non_exhaustive] 303#[non_exhaustive]
429pub struct Sequence<'d> { 304pub struct Sequence<'s> {
430 /// The words comprising the sequence. Must not exceed 32767 words. 305 /// The words comprising the sequence. Must not exceed 32767 words.
431 /// The reason for this buffer to be mutable is so that stopping 306 pub words: &'s [u16],
432 /// the PWM can relinquish the sequence for subsequent modification.
433 pub words: &'d mut [u16],
434 /// Configuration associated with the sequence. 307 /// Configuration associated with the sequence.
435 pub config: SequenceConfig, 308 pub config: SequenceConfig,
436} 309}
437 310
438impl<'d> Sequence<'d> { 311impl<'s> Sequence<'s> {
439 pub fn new(words: &'d mut [u16], config: SequenceConfig) -> Self { 312 pub fn new(words: &'s [u16], config: SequenceConfig) -> Self {
440 Self { words, config } 313 Self { words, config }
441 } 314 }
442} 315}
443 316
317/// A composition of sequences that can be started and stopped.
318/// Takes at least one sequence along with its configuration.
319/// Optionally takes a second sequence and its configuration.
320/// In the case where no second sequence is provided then the first sequence
321/// is used.
322#[non_exhaustive]
323pub struct Sequences<'d, 's, T: Instance> {
324 _pwm: &'s mut SequencePwm<'d, T>,
325 sequence0: Sequence<'s>,
326 sequence1: Option<Sequence<'s>>,
327}
328
329impl<'d, 's, T: Instance> Sequences<'d, 's, T> {
330 pub fn new(
331 pwm: &'s mut SequencePwm<'d, T>,
332 sequence0: Sequence<'s>,
333 sequence1: Option<Sequence<'s>>,
334 ) -> Self {
335 Sequences {
336 _pwm: pwm,
337 sequence0,
338 sequence1,
339 }
340 }
341
342 /// Start or restart playback. The sequence mode applies to both sequences combined as one.
343 #[inline(always)]
344 pub fn start(&self, times: SequenceMode) -> Result<(), Error> {
345 let sequence0 = &self.sequence0;
346 let alt_sequence = self.sequence1.as_ref().unwrap_or(&self.sequence0);
347
348 slice_in_ram_or(sequence0.words, Error::DMABufferNotInDataMemory)?;
349 slice_in_ram_or(alt_sequence.words, Error::DMABufferNotInDataMemory)?;
350
351 if sequence0.words.len() > MAX_SEQUENCE_LEN || alt_sequence.words.len() > MAX_SEQUENCE_LEN {
352 return Err(Error::SequenceTooLong);
353 }
354
355 if let SequenceMode::Times(0) = times {
356 return Err(Error::SequenceTimesAtLeastOne);
357 }
358
359 let _ = self.stop();
360
361 let r = T::regs();
362
363 r.seq0
364 .refresh
365 .write(|w| unsafe { w.bits(sequence0.config.refresh) });
366 r.seq0
367 .enddelay
368 .write(|w| unsafe { w.bits(sequence0.config.end_delay) });
369 r.seq0
370 .ptr
371 .write(|w| unsafe { w.bits(sequence0.words.as_ptr() as u32) });
372 r.seq0
373 .cnt
374 .write(|w| unsafe { w.bits(sequence0.words.len() as u32) });
375
376 r.seq1
377 .refresh
378 .write(|w| unsafe { w.bits(alt_sequence.config.refresh) });
379 r.seq1
380 .enddelay
381 .write(|w| unsafe { w.bits(alt_sequence.config.end_delay) });
382 r.seq1
383 .ptr
384 .write(|w| unsafe { w.bits(alt_sequence.words.as_ptr() as u32) });
385 r.seq1
386 .cnt
387 .write(|w| unsafe { w.bits(alt_sequence.words.len() as u32) });
388
389 r.enable.write(|w| w.enable().enabled());
390
391 // defensive before seqstart
392 compiler_fence(Ordering::SeqCst);
393
394 match times {
395 // just the one time, no loop count
396 SequenceMode::Times(1) => {
397 r.loop_.write(|w| w.cnt().disabled());
398 // tasks_seqstart() doesn't exist in all svds so write its bit instead
399 r.tasks_seqstart[0].write(|w| unsafe { w.bits(0x01) });
400 }
401 // loop count is how many times to play BOTH sequences
402 // 2 total (1 x 2)
403 // 3 total, (2 x 2) - 1
404 SequenceMode::Times(n) => {
405 let odd = n & 1 == 1;
406 let times = if odd { (n / 2) + 1 } else { n / 2 };
407
408 r.loop_.write(|w| unsafe { w.cnt().bits(times) });
409
410 // we can subtract 1 by starting at seq1 instead of seq0
411 if odd {
412 // tasks_seqstart() doesn't exist in all svds so write its bit instead
413 r.tasks_seqstart[1].write(|w| unsafe { w.bits(0x01) });
414 } else {
415 // tasks_seqstart() doesn't exist in all svds so write its bit instead
416 r.tasks_seqstart[0].write(|w| unsafe { w.bits(0x01) });
417 }
418 }
419 // to play infinitely, repeat the sequence one time, then have loops done self trigger seq0 again
420 SequenceMode::Infinite => {
421 r.loop_.write(|w| unsafe { w.cnt().bits(0x1) });
422 r.shorts.write(|w| w.loopsdone_seqstart0().enabled());
423
424 // tasks_seqstart() doesn't exist in all svds so write its bit instead
425 r.tasks_seqstart[0].write(|w| unsafe { w.bits(0x01) });
426 }
427 }
428
429 Ok(())
430 }
431
432 /// Stop playback. Disables the peripheral. Does NOT clear the last duty
433 /// cycle from the pin. Returns any sequences previously provided to
434 /// `start` so that they may be further mutated.
435 #[inline(always)]
436 pub fn stop(&self) {
437 let r = T::regs();
438
439 r.shorts.reset();
440
441 compiler_fence(Ordering::SeqCst);
442
443 // tasks_stop() doesn't exist in all svds so write its bit instead
444 r.tasks_stop.write(|w| unsafe { w.bits(0x01) });
445
446 r.enable.write(|w| w.enable().disabled());
447 }
448}
449
450impl<'d, 's, T: Instance> Drop for Sequences<'d, 's, T> {
451 fn drop(&mut self) {
452 let _ = self.stop();
453 }
454}
455
444/// How many times to run the sequence 456/// How many times to run the sequence
445#[derive(Debug, Eq, PartialEq, Clone, Copy)] 457#[derive(Debug, Eq, PartialEq, Clone, Copy)]
446pub enum SequenceMode { 458pub enum SequenceMode {
diff --git a/examples/nrf/src/bin/pwm_sequence_ws2812b.rs b/examples/nrf/src/bin/pwm_sequence_ws2812b.rs
index 0ce79cbe0..310842d8d 100644
--- a/examples/nrf/src/bin/pwm_sequence_ws2812b.rs
+++ b/examples/nrf/src/bin/pwm_sequence_ws2812b.rs
@@ -9,7 +9,7 @@ use 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::{
12 Config, Prescaler, Sequence, SequenceConfig, SequenceLoad, SequenceMode, SequencePwm, 12 Config, Prescaler, Sequence, SequenceConfig, SequenceLoad, SequenceMode, SequencePwm, Sequences,
13}; 13};
14use embassy_nrf::Peripherals; 14use embassy_nrf::Peripherals;
15 15
@@ -30,19 +30,6 @@ 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
46 let mut config = Config::default(); 33 let mut config = Config::default();
47 config.sequence_load = SequenceLoad::Common; 34 config.sequence_load = SequenceLoad::Common;
48 config.prescaler = Prescaler::Div1; 35 config.prescaler = Prescaler::Div1;
@@ -51,18 +38,24 @@ async fn main(_spawner: Spawner, p: Peripherals) {
51 p.PWM0, p.P1_05, NoPin, NoPin, NoPin, config, 38 p.PWM0, p.P1_05, NoPin, NoPin, NoPin, config,
52 )); 39 ));
53 40
54 unwrap!(pwm.start(color_seq, Some(reset_seq), SequenceMode::Times(2))); 41 // Declare the bits of 24 bits in a buffer we'll be
55 42 // mutating later.
56 Timer::after(Duration::from_millis(1000)).await; 43 let mut seq_words = [
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 RES,
48 ];
49 let mut seq_config = SequenceConfig::default();
50 seq_config.end_delay = 799; // 50us (20 ticks * 40) - 1 tick because we've already got one RES;
57 51
58 let mut color_bit = 16; 52 let mut color_bit = 16;
59 let mut bit_value = T0H; 53 let mut bit_value = T0H;
60 54
61 loop { 55 loop {
62 if let (Some(color_seq), Some(reset_seq)) = pwm.stop() { 56 let sequence0 = Sequence::new(&seq_words, seq_config.clone());
63 color_seq.words[color_bit] = bit_value; 57 let sequences = Sequences::new(&mut pwm, sequence0, None);
64 unwrap!(pwm.start(color_seq, Some(reset_seq), SequenceMode::Times(2))); 58 unwrap!(sequences.start(SequenceMode::Times(2)));
65 }
66 59
67 Timer::after(Duration::from_millis(50)).await; 60 Timer::after(Duration::from_millis(50)).await;
68 61
@@ -79,5 +72,9 @@ async fn main(_spawner: Spawner, p: Peripherals) {
79 color_bit -= 1; 72 color_bit -= 1;
80 } 73 }
81 } 74 }
75
76 drop(sequences);
77
78 seq_words[color_bit] = bit_value;
82 } 79 }
83} 80}