aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf/src
diff options
context:
space:
mode:
authorhuntc <[email protected]>2022-01-25 18:06:42 +1100
committerhuntc <[email protected]>2022-01-28 11:20:04 +1100
commit47aeab152fff59e64d8244475dfbec338e6f98e5 (patch)
tree0bc694c01f575d9a26071416f803494b6988dbb7 /embassy-nrf/src
parentd76cd5ceaf5140c48ef97180beae156c0c0e07c8 (diff)
PWM WS2812B example and per sequence config
Demonstrates how to set the colour of a WS2812B to blue using PWM, and the use of multiple sequences along with their own config. This required an API change.
Diffstat (limited to 'embassy-nrf/src')
-rw-r--r--embassy-nrf/src/pwm.rs89
1 files changed, 62 insertions, 27 deletions
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs
index a77cd6332..21b450b19 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,12 +128,28 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
136 }) 128 })
137 } 129 }
138 130
139 /// Start or restart playback 131 /// Start or restart playback. Takes at least one sequence along with its
132 /// configuration. Optionally takes a second sequence and/or its configuration.
133 /// In the case where no second sequence is provided then the first sequence
134 /// is used. In the case where no second sequence configuration is supplied,
135 /// the first sequence configuration is used. The sequence mode applies to both
136 /// sequences combined as one.
140 #[inline(always)] 137 #[inline(always)]
141 pub fn start(&mut self, sequence: &'d [u16], times: SequenceMode) -> Result<(), Error> { 138 pub fn start(
142 slice_in_ram_or(sequence, Error::DMABufferNotInDataMemory)?; 139 &mut self,
143 140 sequence0: &'d [u16],
144 if sequence.len() > 32767 { 141 sequence_config0: SequenceConfig,
142 sequence1: Option<&'d [u16]>,
143 sequence_config1: Option<SequenceConfig>,
144 times: SequenceMode,
145 ) -> Result<(), Error> {
146 let alt_sequence = sequence1.unwrap_or(sequence0);
147 let alt_sequence_config = (&sequence_config1).as_ref().unwrap_or(&sequence_config0);
148
149 slice_in_ram_or(sequence0, Error::DMABufferNotInDataMemory)?;
150 slice_in_ram_or(alt_sequence, Error::DMABufferNotInDataMemory)?;
151
152 if sequence0.len() > MAX_SEQUENCE_LEN || alt_sequence.len() > MAX_SEQUENCE_LEN {
145 return Err(Error::SequenceTooLong); 153 return Err(Error::SequenceTooLong);
146 } 154 }
147 155
@@ -154,18 +162,30 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
154 let r = T::regs(); 162 let r = T::regs();
155 163
156 r.seq0 164 r.seq0
165 .refresh
166 .write(|w| unsafe { w.bits(sequence_config0.refresh) });
167 r.seq0
168 .enddelay
169 .write(|w| unsafe { w.bits(sequence_config0.end_delay) });
170 r.seq0
157 .ptr 171 .ptr
158 .write(|w| unsafe { w.bits(sequence.as_ptr() as u32) }); 172 .write(|w| unsafe { w.bits(sequence0.as_ptr() as u32) });
159 r.seq0 173 r.seq0
160 .cnt 174 .cnt
161 .write(|w| unsafe { w.bits(sequence.len() as u32) }); 175 .write(|w| unsafe { w.bits(sequence0.len() as u32) });
162 176
163 r.seq1 177 r.seq1
178 .refresh
179 .write(|w| unsafe { w.bits(alt_sequence_config.refresh) });
180 r.seq1
181 .enddelay
182 .write(|w| unsafe { w.bits(alt_sequence_config.end_delay) });
183 r.seq1
164 .ptr 184 .ptr
165 .write(|w| unsafe { w.bits(sequence.as_ptr() as u32) }); 185 .write(|w| unsafe { w.bits(alt_sequence.as_ptr() as u32) });
166 r.seq1 186 r.seq1
167 .cnt 187 .cnt
168 .write(|w| unsafe { w.bits(sequence.len() as u32) }); 188 .write(|w| unsafe { w.bits(alt_sequence.len() as u32) });
169 189
170 r.enable.write(|w| w.enable().enabled()); 190 r.enable.write(|w| w.enable().enabled());
171 191
@@ -356,9 +376,8 @@ impl<'a, T: Instance> Drop for SequencePwm<'a, T> {
356 } 376 }
357} 377}
358 378
359/// Configure an infinite looping sequence for `SequencePwm`
360#[non_exhaustive] 379#[non_exhaustive]
361pub struct SequenceConfig { 380pub struct Config {
362 /// Selects up mode or up-and-down mode for the counter 381 /// Selects up mode or up-and-down mode for the counter
363 pub counter_mode: CounterMode, 382 pub counter_mode: CounterMode,
364 /// Top value to be compared against buffer values 383 /// Top value to be compared against buffer values
@@ -367,6 +386,21 @@ pub struct SequenceConfig {
367 pub prescaler: Prescaler, 386 pub prescaler: Prescaler,
368 /// How a sequence is read from RAM and is spread to the compare register 387 /// How a sequence is read from RAM and is spread to the compare register
369 pub sequence_load: SequenceLoad, 388 pub sequence_load: SequenceLoad,
389}
390
391impl Default for Config {
392 fn default() -> Config {
393 Config {
394 counter_mode: CounterMode::Up,
395 max_duty: 1000,
396 prescaler: Prescaler::Div16,
397 sequence_load: SequenceLoad::Common,
398 }
399 }
400}
401
402#[non_exhaustive]
403pub struct SequenceConfig {
370 /// Number of PWM periods to delay between each sequence sample 404 /// Number of PWM periods to delay between each sequence sample
371 pub refresh: u32, 405 pub refresh: u32,
372 /// Number of PWM periods after the sequence ends before starting the next sequence 406 /// Number of PWM periods after the sequence ends before starting the next sequence
@@ -376,10 +410,6 @@ pub struct SequenceConfig {
376impl Default for SequenceConfig { 410impl Default for SequenceConfig {
377 fn default() -> SequenceConfig { 411 fn default() -> SequenceConfig {
378 SequenceConfig { 412 SequenceConfig {
379 counter_mode: CounterMode::Up,
380 max_duty: 1000,
381 prescaler: Prescaler::Div16,
382 sequence_load: SequenceLoad::Common,
383 refresh: 0, 413 refresh: 0,
384 end_delay: 0, 414 end_delay: 0,
385 } 415 }
@@ -389,7 +419,12 @@ impl Default for SequenceConfig {
389/// How many times to run the sequence 419/// How many times to run the sequence
390#[derive(Debug, Eq, PartialEq, Clone, Copy)] 420#[derive(Debug, Eq, PartialEq, Clone, Copy)]
391pub enum SequenceMode { 421pub enum SequenceMode {
392 /// Run sequence n Times total 422 /// Run sequence n Times total.
423 /// 1 = Run sequence 0 once
424 /// 2 = Run sequence 0 and then sequence 1
425 /// 3 to 4 = Run sequence 0, sequence 1, sequence 0 and then sequence 1
426 /// 5 to 6 = Run sequence 0, sequence 1, sequence 0, sequence 1, sequence 0 and then sequence 1
427 /// i.e the when >= 2 the loop count is determined by dividing by 2 and rounding up
393 Times(u16), 428 Times(u16),
394 /// Repeat until `stop` is called. 429 /// Repeat until `stop` is called.
395 Infinite, 430 Infinite,