aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nrf/src/pwm.rs335
-rw-r--r--examples/nrf/src/bin/pwm_double_sequence.rs46
-rw-r--r--examples/nrf/src/bin/pwm_sequence.rs21
-rw-r--r--examples/nrf/src/bin/pwm_sequence_ppi.rs15
-rw-r--r--examples/nrf/src/bin/pwm_sequence_ws2812b.rs80
5 files changed, 368 insertions, 129 deletions
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs
index a77cd6332..01b1f48d9 100644
--- a/embassy-nrf/src/pwm.rs
+++ b/embassy-nrf/src/pwm.rs
@@ -45,6 +45,8 @@ pub enum Error {
45 DMABufferNotInDataMemory, 45 DMABufferNotInDataMemory,
46} 46}
47 47
48const MAX_SEQUENCE_LEN: usize = 32767;
49
48impl<'d, T: Instance> SequencePwm<'d, T> { 50impl<'d, T: Instance> SequencePwm<'d, T> {
49 /// Creates the interface to a `SequencePwm`. 51 /// Creates the interface to a `SequencePwm`.
50 /// 52 ///
@@ -62,7 +64,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
62 ch1: impl Unborrow<Target = impl GpioOptionalPin> + 'd, 64 ch1: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
63 ch2: impl Unborrow<Target = impl GpioOptionalPin> + 'd, 65 ch2: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
64 ch3: impl Unborrow<Target = impl GpioOptionalPin> + 'd, 66 ch3: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
65 config: SequenceConfig, 67 config: Config,
66 ) -> Result<Self, Error> { 68 ) -> Result<Self, Error> {
67 unborrow!(ch0, ch1, ch2, ch3); 69 unborrow!(ch0, ch1, ch2, ch3);
68 70
@@ -117,16 +119,6 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
117 r.countertop 119 r.countertop
118 .write(|w| unsafe { w.countertop().bits(config.max_duty) }); 120 .write(|w| unsafe { w.countertop().bits(config.max_duty) });
119 121
120 r.seq0.refresh.write(|w| unsafe { w.bits(config.refresh) });
121 r.seq0
122 .enddelay
123 .write(|w| unsafe { w.bits(config.end_delay) });
124
125 r.seq1.refresh.write(|w| unsafe { w.bits(config.refresh) });
126 r.seq1
127 .enddelay
128 .write(|w| unsafe { w.bits(config.end_delay) });
129
130 Ok(Self { 122 Ok(Self {
131 phantom: PhantomData, 123 phantom: PhantomData,
132 ch0: ch0.degrade_optional(), 124 ch0: ch0.degrade_optional(),
@@ -136,80 +128,6 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
136 }) 128 })
137 } 129 }
138 130
139 /// Start or restart playback
140 #[inline(always)]
141 pub fn start(&mut self, sequence: &'d [u16], times: SequenceMode) -> Result<(), Error> {
142 slice_in_ram_or(sequence, Error::DMABufferNotInDataMemory)?;
143
144 if sequence.len() > 32767 {
145 return Err(Error::SequenceTooLong);
146 }
147
148 if let SequenceMode::Times(0) = times {
149 return Err(Error::SequenceTimesAtLeastOne);
150 }
151
152 self.stop();
153
154 let r = T::regs();
155
156 r.seq0
157 .ptr
158 .write(|w| unsafe { w.bits(sequence.as_ptr() as u32) });
159 r.seq0
160 .cnt
161 .write(|w| unsafe { w.bits(sequence.len() as u32) });
162
163 r.seq1
164 .ptr
165 .write(|w| unsafe { w.bits(sequence.as_ptr() as u32) });
166 r.seq1
167 .cnt
168 .write(|w| unsafe { w.bits(sequence.len() as u32) });
169
170 r.enable.write(|w| w.enable().enabled());
171
172 // defensive before seqstart
173 compiler_fence(Ordering::SeqCst);
174
175 match times {
176 // just the one time, no loop count
177 SequenceMode::Times(1) => {
178 r.loop_.write(|w| w.cnt().disabled());
179 // tasks_seqstart() doesn't exist in all svds so write its bit instead
180 r.tasks_seqstart[0].write(|w| unsafe { w.bits(0x01) });
181 }
182 // loop count is how many times to play BOTH sequences
183 // 2 total (1 x 2)
184 // 3 total, (2 x 2) - 1
185 SequenceMode::Times(n) => {
186 let odd = n & 1 == 1;
187 let times = if odd { (n / 2) + 1 } else { n / 2 };
188
189 r.loop_.write(|w| unsafe { w.cnt().bits(times) });
190
191 // we can subtract 1 by starting at seq1 instead of seq0
192 if odd {
193 // tasks_seqstart() doesn't exist in all svds so write its bit instead
194 r.tasks_seqstart[1].write(|w| unsafe { w.bits(0x01) });
195 } else {
196 // tasks_seqstart() doesn't exist in all svds so write its bit instead
197 r.tasks_seqstart[0].write(|w| unsafe { w.bits(0x01) });
198 }
199 }
200 // to play infinitely, repeat the sequence one time, then have loops done self trigger seq0 again
201 SequenceMode::Infinite => {
202 r.loop_.write(|w| unsafe { w.cnt().bits(0x1) });
203 r.shorts.write(|w| w.loopsdone_seqstart0().enabled());
204
205 // tasks_seqstart() doesn't exist in all svds so write its bit instead
206 r.tasks_seqstart[0].write(|w| unsafe { w.bits(0x01) });
207 }
208 }
209
210 Ok(())
211 }
212
213 /// Returns reference to `Stopped` event endpoint for PPI. 131 /// Returns reference to `Stopped` event endpoint for PPI.
214 #[inline(always)] 132 #[inline(always)]
215 pub fn event_stopped(&self) -> Event { 133 pub fn event_stopped(&self) -> Event {
@@ -309,30 +227,12 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
309 227
310 Task::from_reg(&r.tasks_stop) 228 Task::from_reg(&r.tasks_stop)
311 } 229 }
312
313 /// Stop playback. Disables the peripheral. Does NOT clear the last duty
314 /// cycle from the pin.
315 #[inline(always)]
316 pub fn stop(&self) {
317 let r = T::regs();
318
319 r.shorts.reset();
320
321 compiler_fence(Ordering::SeqCst);
322
323 // tasks_stop() doesn't exist in all svds so write its bit instead
324 r.tasks_stop.write(|w| unsafe { w.bits(0x01) });
325
326 r.enable.write(|w| w.enable().disabled());
327 }
328} 230}
329 231
330impl<'a, T: Instance> Drop for SequencePwm<'a, T> { 232impl<'a, T: Instance> Drop for SequencePwm<'a, T> {
331 fn drop(&mut self) { 233 fn drop(&mut self) {
332 let r = T::regs(); 234 let r = T::regs();
333 235
334 self.stop();
335
336 if let Some(pin) = &self.ch0 { 236 if let Some(pin) = &self.ch0 {
337 pin.set_low(); 237 pin.set_low();
338 pin.conf().reset(); 238 pin.conf().reset();
@@ -356,9 +256,9 @@ impl<'a, T: Instance> Drop for SequencePwm<'a, T> {
356 } 256 }
357} 257}
358 258
359/// Configure an infinite looping sequence for `SequencePwm` 259/// Configuration for the PWM as a whole.
360#[non_exhaustive] 260#[non_exhaustive]
361pub struct SequenceConfig { 261pub struct Config {
362 /// Selects up mode or up-and-down mode for the counter 262 /// Selects up mode or up-and-down mode for the counter
363 pub counter_mode: CounterMode, 263 pub counter_mode: CounterMode,
364 /// Top value to be compared against buffer values 264 /// Top value to be compared against buffer values
@@ -367,6 +267,23 @@ pub struct SequenceConfig {
367 pub prescaler: Prescaler, 267 pub prescaler: Prescaler,
368 /// How a sequence is read from RAM and is spread to the compare register 268 /// How a sequence is read from RAM and is spread to the compare register
369 pub sequence_load: SequenceLoad, 269 pub sequence_load: SequenceLoad,
270}
271
272impl Default for Config {
273 fn default() -> Config {
274 Config {
275 counter_mode: CounterMode::Up,
276 max_duty: 1000,
277 prescaler: Prescaler::Div16,
278 sequence_load: SequenceLoad::Common,
279 }
280 }
281}
282
283/// Configuration per sequence
284#[non_exhaustive]
285#[derive(Clone)]
286pub struct SequenceConfig {
370 /// Number of PWM periods to delay between each sequence sample 287 /// Number of PWM periods to delay between each sequence sample
371 pub refresh: u32, 288 pub refresh: u32,
372 /// Number of PWM periods after the sequence ends before starting the next sequence 289 /// Number of PWM periods after the sequence ends before starting the next sequence
@@ -376,25 +293,219 @@ pub struct SequenceConfig {
376impl Default for SequenceConfig { 293impl Default for SequenceConfig {
377 fn default() -> SequenceConfig { 294 fn default() -> SequenceConfig {
378 SequenceConfig { 295 SequenceConfig {
379 counter_mode: CounterMode::Up,
380 max_duty: 1000,
381 prescaler: Prescaler::Div16,
382 sequence_load: SequenceLoad::Common,
383 refresh: 0, 296 refresh: 0,
384 end_delay: 0, 297 end_delay: 0,
385 } 298 }
386 } 299 }
387} 300}
388 301
389/// How many times to run the sequence 302/// A composition of a sequence buffer and its configuration.
303#[non_exhaustive]
304pub struct Sequence<'s> {
305 /// The words comprising the sequence. Must not exceed 32767 words.
306 pub words: &'s [u16],
307 /// Configuration associated with the sequence.
308 pub config: SequenceConfig,
309}
310
311impl<'s> Sequence<'s> {
312 pub fn new(words: &'s [u16], config: SequenceConfig) -> Self {
313 Self { words, config }
314 }
315}
316
317/// A single sequence that can be started and stopped.
318/// Takes at one sequence along with its configuration.
319#[non_exhaustive]
320pub struct SingleSequencer<'d, 's, T: Instance> {
321 pub sequencer: Sequencer<'d, 's, T>,
322}
323
324impl<'d, 's, T: Instance> SingleSequencer<'d, 's, T> {
325 /// Create a new sequencer
326 pub fn new(pwm: &'s mut SequencePwm<'d, T>, words: &'s [u16], config: SequenceConfig) -> Self {
327 Self {
328 sequencer: Sequencer::new(pwm, Sequence::new(words, config), None),
329 }
330 }
331
332 /// Start or restart playback.
333 #[inline(always)]
334 pub fn start(&self, times: SingleSequenceMode) -> Result<(), Error> {
335 let (start_seq, times) = match times {
336 SingleSequenceMode::Times(n) if n == 1 => (StartSequence::One, SequenceMode::Loop(1)),
337 SingleSequenceMode::Times(n) if n & 1 == 1 => {
338 (StartSequence::One, SequenceMode::Loop((n / 2) + 1))
339 }
340 SingleSequenceMode::Times(n) => (StartSequence::Zero, SequenceMode::Loop(n / 2)),
341 SingleSequenceMode::Infinite => (StartSequence::Zero, SequenceMode::Infinite),
342 };
343 self.sequencer.start(start_seq, times)
344 }
345
346 /// Stop playback. Disables the peripheral. Does NOT clear the last duty
347 /// cycle from the pin. Returns any sequences previously provided to
348 /// `start` so that they may be further mutated.
349 #[inline(always)]
350 pub fn stop(&self) {
351 self.sequencer.stop();
352 }
353}
354
355/// A composition of sequences that can be started and stopped.
356/// Takes at least one sequence along with its configuration.
357/// Optionally takes a second sequence and its configuration.
358/// In the case where no second sequence is provided then the first sequence
359/// is used.
360#[non_exhaustive]
361pub struct Sequencer<'d, 's, T: Instance> {
362 _pwm: &'s mut SequencePwm<'d, T>,
363 sequence0: Sequence<'s>,
364 sequence1: Option<Sequence<'s>>,
365}
366
367impl<'d, 's, T: Instance> Sequencer<'d, 's, T> {
368 /// Create a new double sequence. In the absence of sequence 1, sequence 0
369 /// will be used twice in the one loop.
370 pub fn new(
371 pwm: &'s mut SequencePwm<'d, T>,
372 sequence0: Sequence<'s>,
373 sequence1: Option<Sequence<'s>>,
374 ) -> Self {
375 Sequencer {
376 _pwm: pwm,
377 sequence0,
378 sequence1,
379 }
380 }
381
382 /// Start or restart playback. The sequence mode applies to both sequences combined as one.
383 #[inline(always)]
384 pub fn start(&self, start_seq: StartSequence, times: SequenceMode) -> Result<(), Error> {
385 let sequence0 = &self.sequence0;
386 let alt_sequence = self.sequence1.as_ref().unwrap_or(&self.sequence0);
387
388 slice_in_ram_or(sequence0.words, Error::DMABufferNotInDataMemory)?;
389 slice_in_ram_or(alt_sequence.words, Error::DMABufferNotInDataMemory)?;
390
391 if sequence0.words.len() > MAX_SEQUENCE_LEN || alt_sequence.words.len() > MAX_SEQUENCE_LEN {
392 return Err(Error::SequenceTooLong);
393 }
394
395 if let SequenceMode::Loop(0) = times {
396 return Err(Error::SequenceTimesAtLeastOne);
397 }
398
399 let _ = self.stop();
400
401 let r = T::regs();
402
403 r.seq0
404 .refresh
405 .write(|w| unsafe { w.bits(sequence0.config.refresh) });
406 r.seq0
407 .enddelay
408 .write(|w| unsafe { w.bits(sequence0.config.end_delay) });
409 r.seq0
410 .ptr
411 .write(|w| unsafe { w.bits(sequence0.words.as_ptr() as u32) });
412 r.seq0
413 .cnt
414 .write(|w| unsafe { w.bits(sequence0.words.len() as u32) });
415
416 r.seq1
417 .refresh
418 .write(|w| unsafe { w.bits(alt_sequence.config.refresh) });
419 r.seq1
420 .enddelay
421 .write(|w| unsafe { w.bits(alt_sequence.config.end_delay) });
422 r.seq1
423 .ptr
424 .write(|w| unsafe { w.bits(alt_sequence.words.as_ptr() as u32) });
425 r.seq1
426 .cnt
427 .write(|w| unsafe { w.bits(alt_sequence.words.len() as u32) });
428
429 r.enable.write(|w| w.enable().enabled());
430
431 // defensive before seqstart
432 compiler_fence(Ordering::SeqCst);
433
434 let seqstart_index = if start_seq == StartSequence::One {
435 1
436 } else {
437 0
438 };
439
440 match times {
441 // just the one time, no loop count
442 SequenceMode::Loop(n) => {
443 r.loop_.write(|w| unsafe { w.cnt().bits(n) });
444 }
445 // to play infinitely, repeat the sequence one time, then have loops done self trigger seq0 again
446 SequenceMode::Infinite => {
447 r.loop_.write(|w| unsafe { w.cnt().bits(0x1) });
448 r.shorts.write(|w| w.loopsdone_seqstart0().enabled());
449 }
450 }
451
452 // tasks_seqstart() doesn't exist in all svds so write its bit instead
453 r.tasks_seqstart[seqstart_index].write(|w| unsafe { w.bits(0x01) });
454
455 Ok(())
456 }
457
458 /// Stop playback. Disables the peripheral. Does NOT clear the last duty
459 /// cycle from the pin. Returns any sequences previously provided to
460 /// `start` so that they may be further mutated.
461 #[inline(always)]
462 pub fn stop(&self) {
463 let r = T::regs();
464
465 r.shorts.reset();
466
467 compiler_fence(Ordering::SeqCst);
468
469 // tasks_stop() doesn't exist in all svds so write its bit instead
470 r.tasks_stop.write(|w| unsafe { w.bits(0x01) });
471
472 r.enable.write(|w| w.enable().disabled());
473 }
474}
475
476impl<'d, 's, T: Instance> Drop for Sequencer<'d, 's, T> {
477 fn drop(&mut self) {
478 let _ = self.stop();
479 }
480}
481
482/// How many times to run a single sequence
390#[derive(Debug, Eq, PartialEq, Clone, Copy)] 483#[derive(Debug, Eq, PartialEq, Clone, Copy)]
391pub enum SequenceMode { 484pub enum SingleSequenceMode {
392 /// Run sequence n Times total 485 /// Run a single sequence n Times total.
393 Times(u16), 486 Times(u16),
394 /// Repeat until `stop` is called. 487 /// Repeat until `stop` is called.
395 Infinite, 488 Infinite,
396} 489}
397 490
491/// Which sequence to start a loop with
492#[derive(Debug, Eq, PartialEq, Clone, Copy)]
493pub enum StartSequence {
494 /// Start with Sequence 0
495 Zero,
496 /// Start with Sequence 1
497 One,
498}
499
500/// How many loops to run two sequences
501#[derive(Debug, Eq, PartialEq, Clone, Copy)]
502pub enum SequenceMode {
503 /// Run two sequences n loops i.e. (n * (seq0 + seq1.unwrap_or(seq0)))
504 Loop(u16),
505 /// Repeat until `stop` is called.
506 Infinite,
507}
508
398/// PWM Base clock is system clock (16MHz) divided by prescaler 509/// PWM Base clock is system clock (16MHz) divided by prescaler
399#[derive(Debug, Eq, PartialEq, Clone, Copy)] 510#[derive(Debug, Eq, PartialEq, Clone, Copy)]
400pub enum Prescaler { 511pub enum Prescaler {
diff --git a/examples/nrf/src/bin/pwm_double_sequence.rs b/examples/nrf/src/bin/pwm_double_sequence.rs
new file mode 100644
index 000000000..269015f4a
--- /dev/null
+++ b/examples/nrf/src/bin/pwm_double_sequence.rs
@@ -0,0 +1,46 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5#[path = "../example_common.rs"]
6mod example_common;
7use defmt::*;
8use embassy::executor::Spawner;
9use embassy::time::{Duration, Timer};
10use embassy_nrf::gpio::NoPin;
11use embassy_nrf::pwm::{
12 Config, Prescaler, Sequence, SequenceConfig, SequenceMode, SequencePwm, Sequencer,
13 StartSequence,
14};
15use embassy_nrf::Peripherals;
16
17#[embassy::main]
18async fn main(_spawner: Spawner, p: Peripherals) {
19 let seq_words_0: [u16; 5] = [1000, 250, 100, 50, 0];
20 let seq_words_1: [u16; 4] = [50, 100, 250, 1000];
21
22 let mut config = Config::default();
23 config.prescaler = Prescaler::Div128;
24 // 1 period is 1000 * (128/16mhz = 0.000008s = 0.008ms) = 8us
25 // but say we want to hold the value for 5000ms
26 // so we want to repeat our value as many times as necessary until 5000ms passes
27 // want 5000/8 = 625 periods total to occur, so 624 (we get the one period for free remember)
28 let mut seq_config = SequenceConfig::default();
29 seq_config.refresh = 624;
30 // thus our sequence takes 5 * 5000ms or 25 seconds
31
32 let mut pwm = unwrap!(SequencePwm::new(
33 p.PWM0, p.P0_13, NoPin, NoPin, NoPin, config,
34 ));
35
36 let sequence_0 = Sequence::new(&seq_words_0, seq_config.clone());
37 let sequence_1 = Sequence::new(&seq_words_1, seq_config);
38 let sequencer = Sequencer::new(&mut pwm, sequence_0, Some(sequence_1));
39 unwrap!(sequencer.start(StartSequence::Zero, SequenceMode::Loop(1)));
40
41 // we can abort a sequence if we need to before its complete with pwm.stop()
42 // or stop is also implicitly called when the pwm peripheral is dropped
43 // when it goes out of scope
44 Timer::after(Duration::from_millis(40000)).await;
45 info!("pwm stopped early!");
46}
diff --git a/examples/nrf/src/bin/pwm_sequence.rs b/examples/nrf/src/bin/pwm_sequence.rs
index 56c865d1c..f06ea0b19 100644
--- a/examples/nrf/src/bin/pwm_sequence.rs
+++ b/examples/nrf/src/bin/pwm_sequence.rs
@@ -8,34 +8,31 @@ 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::{Prescaler, SequenceConfig, SequenceMode, SequencePwm}; 11use embassy_nrf::pwm::{
12 Config, Prescaler, SequenceConfig, SequencePwm, SingleSequenceMode, SingleSequencer,
13};
12use embassy_nrf::Peripherals; 14use embassy_nrf::Peripherals;
13 15
14#[embassy::main] 16#[embassy::main]
15async fn main(_spawner: Spawner, p: Peripherals) { 17async fn main(_spawner: Spawner, p: Peripherals) {
16 let seq_values_1: [u16; 5] = [1000, 250, 100, 50, 0]; 18 let seq_words: [u16; 5] = [1000, 250, 100, 50, 0];
17 let seq_values_2: [u16; 5] = [0, 50, 100, 250, 1000];
18 19
19 let mut config = SequenceConfig::default(); 20 let mut config = Config::default();
20 config.prescaler = Prescaler::Div128; 21 config.prescaler = Prescaler::Div128;
21 // 1 period is 1000 * (128/16mhz = 0.000008s = 0.008ms) = 8us 22 // 1 period is 1000 * (128/16mhz = 0.000008s = 0.008ms) = 8us
22 // but say we want to hold the value for 5000ms 23 // but say we want to hold the value for 5000ms
23 // so we want to repeat our value as many times as necessary until 5000ms passes 24 // so we want to repeat our value as many times as necessary until 5000ms passes
24 // want 5000/8 = 625 periods total to occur, so 624 (we get the one period for free remember) 25 // want 5000/8 = 625 periods total to occur, so 624 (we get the one period for free remember)
25 config.refresh = 624; 26 let mut seq_config = SequenceConfig::default();
27 seq_config.refresh = 624;
26 // thus our sequence takes 5 * 5000ms or 25 seconds 28 // thus our sequence takes 5 * 5000ms or 25 seconds
27 29
28 let mut pwm = unwrap!(SequencePwm::new( 30 let mut pwm = unwrap!(SequencePwm::new(
29 p.PWM0, p.P0_13, NoPin, NoPin, NoPin, config, 31 p.PWM0, p.P0_13, NoPin, NoPin, NoPin, config,
30 )); 32 ));
31 let _ = pwm.start(&seq_values_1, SequenceMode::Infinite);
32 33
33 info!("pwm started!"); 34 let sequencer = SingleSequencer::new(&mut pwm, &seq_words, seq_config);
34 35 unwrap!(sequencer.start(SingleSequenceMode::Times(1)));
35 Timer::after(Duration::from_millis(20000)).await;
36 info!("pwm starting with another sequence!");
37
38 let _ = pwm.start(&seq_values_2, SequenceMode::Infinite);
39 36
40 // we can abort a sequence if we need to before its complete with pwm.stop() 37 // we can abort a sequence if we need to before its complete with pwm.stop()
41 // or stop is also implicitly called when the pwm peripheral is dropped 38 // 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 f03c5716a..c25c5e10d 100644
--- a/examples/nrf/src/bin/pwm_sequence_ppi.rs
+++ b/examples/nrf/src/bin/pwm_sequence_ppi.rs
@@ -11,26 +11,28 @@ use embassy::executor::Spawner;
11use embassy_nrf::gpio::{Input, NoPin, Pull}; 11use embassy_nrf::gpio::{Input, NoPin, Pull};
12use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity}; 12use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity};
13use embassy_nrf::ppi::Ppi; 13use embassy_nrf::ppi::Ppi;
14use embassy_nrf::pwm::{Prescaler, SequenceConfig, SequenceMode, SequencePwm}; 14use embassy_nrf::pwm::{
15 Config, Prescaler, SequenceConfig, SequencePwm, SingleSequenceMode, SingleSequencer,
16};
15use embassy_nrf::Peripherals; 17use embassy_nrf::Peripherals;
16 18
17#[embassy::main] 19#[embassy::main]
18async fn main(_spawner: Spawner, p: Peripherals) { 20async fn main(_spawner: Spawner, p: Peripherals) {
19 let seq_values: [u16; 5] = [1000, 250, 100, 50, 0]; 21 let seq_words: [u16; 5] = [1000, 250, 100, 50, 0];
20 22
21 let mut config = SequenceConfig::default(); 23 let mut config = Config::default();
22 config.prescaler = Prescaler::Div128; 24 config.prescaler = Prescaler::Div128;
23 // 1 period is 1000 * (128/16mhz = 0.000008s = 0.008ms) = 8us 25 // 1 period is 1000 * (128/16mhz = 0.000008s = 0.008ms) = 8us
24 // but say we want to hold the value for 250ms 250ms/8 = 31.25 periods 26 // but say we want to hold the value for 250ms 250ms/8 = 31.25 periods
25 // so round to 31 - 1 (we get the one period for free remember) 27 // so round to 31 - 1 (we get the one period for free remember)
26 // thus our sequence takes 5 * 250ms or 1.25 seconds 28 // thus our sequence takes 5 * 250ms or 1.25 seconds
27 config.refresh = 30; 29 let mut seq_config = SequenceConfig::default();
30 seq_config.refresh = 30;
28 31
29 let mut pwm = unwrap!(SequencePwm::new( 32 let mut pwm = unwrap!(SequencePwm::new(
30 p.PWM0, p.P0_13, NoPin, NoPin, NoPin, config, 33 p.PWM0, p.P0_13, NoPin, NoPin, NoPin, config,
31 )); 34 ));
32 35
33 let _ = pwm.start(&seq_values, SequenceMode::Times(1));
34 // pwm.stop() deconfigures pins, and then the task_start_seq0 task cant work 36 // pwm.stop() deconfigures pins, and then the task_start_seq0 task cant work
35 // so its going to have to start running in order load the configuration 37 // so its going to have to start running in order load the configuration
36 38
@@ -51,6 +53,9 @@ async fn main(_spawner: Spawner, p: Peripherals) {
51 let start = unsafe { pwm.task_start_seq0() }; 53 let start = unsafe { pwm.task_start_seq0() };
52 let stop = unsafe { pwm.task_stop() }; 54 let stop = unsafe { pwm.task_stop() };
53 55
56 let sequencer = SingleSequencer::new(&mut pwm, &seq_words, seq_config);
57 unwrap!(sequencer.start(SingleSequenceMode::Infinite));
58
54 let mut ppi = Ppi::new_one_to_one(p.PPI_CH1, button1.event_in(), start); 59 let mut ppi = Ppi::new_one_to_one(p.PPI_CH1, button1.event_in(), start);
55 ppi.enable(); 60 ppi.enable();
56 61
diff --git a/examples/nrf/src/bin/pwm_sequence_ws2812b.rs b/examples/nrf/src/bin/pwm_sequence_ws2812b.rs
new file mode 100644
index 000000000..d1a027a7e
--- /dev/null
+++ b/examples/nrf/src/bin/pwm_sequence_ws2812b.rs
@@ -0,0 +1,80 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5#[path = "../example_common.rs"]
6mod example_common;
7use defmt::*;
8use embassy::executor::Spawner;
9use embassy::time::{Duration, Timer};
10use embassy_nrf::gpio::NoPin;
11use embassy_nrf::pwm::{
12 Config, Prescaler, SequenceConfig, SequenceLoad, SequencePwm, SingleSequenceMode,
13 SingleSequencer,
14};
15use embassy_nrf::Peripherals;
16
17// WS2812B LED light demonstration. Drives just one light.
18// The following reference on WS2812B may be of use:
19// https://cdn-shop.adafruit.com/datasheets/WS2812B.pdf.
20// This demo lights up a single LED in blue. It then proceeds
21// to pulsate the LED rapidly.
22
23// In the following declarations, setting the high bit tells the PWM
24// to reverse polarity, which is what the WS2812B expects.
25
26const T1H: u16 = 0x8000 | 13; // Duty = 13/20 ticks (0.8us/1.25us) for a 1
27const T0H: u16 = 0x8000 | 7; // Duty 7/20 ticks (0.4us/1.25us) for a 0
28const RES: u16 = 0x8000;
29
30// Provides data to a WS2812b (Neopixel) LED and makes it go blue. The data
31// line is assumed to be P1_05.
32#[embassy::main]
33async fn main(_spawner: Spawner, p: Peripherals) {
34 let mut config = Config::default();
35 config.sequence_load = SequenceLoad::Common;
36 config.prescaler = Prescaler::Div1;
37 config.max_duty = 20; // 1.25us (1s / 16Mhz * 20)
38 let mut pwm = unwrap!(SequencePwm::new(
39 p.PWM0, p.P1_05, NoPin, NoPin, NoPin, config,
40 ));
41
42 // Declare the bits of 24 bits in a buffer we'll be
43 // mutating later.
44 let mut seq_words = [
45 T0H, T0H, T0H, T0H, T0H, T0H, T0H, T0H, // G
46 T0H, T0H, T0H, T0H, T0H, T0H, T0H, T0H, // R
47 T1H, T1H, T1H, T1H, T1H, T1H, T1H, T1H, // B
48 RES,
49 ];
50 let mut seq_config = SequenceConfig::default();
51 seq_config.end_delay = 799; // 50us (20 ticks * 40) - 1 tick because we've already got one RES;
52
53 let mut color_bit = 16;
54 let mut bit_value = T0H;
55
56 loop {
57 let sequences = SingleSequencer::new(&mut pwm, &seq_words, seq_config.clone());
58 unwrap!(sequences.start(SingleSequenceMode::Times(1)));
59
60 Timer::after(Duration::from_millis(50)).await;
61
62 if bit_value == T0H {
63 if color_bit == 20 {
64 bit_value = T1H;
65 } else {
66 color_bit += 1;
67 }
68 } else {
69 if color_bit == 16 {
70 bit_value = T0H;
71 } else {
72 color_bit -= 1;
73 }
74 }
75
76 drop(sequences);
77
78 seq_words[color_bit] = bit_value;
79 }
80}