aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Rosenthal <[email protected]>2021-10-30 16:16:10 -0700
committerJacob Rosenthal <[email protected]>2021-10-30 16:16:10 -0700
commit763e250dfea4425912674ed68d77c3291b0505e0 (patch)
treedc6acf87b672b30c2866760b99267bc7bb0043c4
parentee8f76537b2dd8e886f44bd7e43d4ba9fd767778 (diff)
add ability to configure loop count from 1 to infinite
-rw-r--r--embassy-nrf/src/pwm.rs71
-rw-r--r--examples/nrf/src/bin/pwm_sequence.rs13
-rw-r--r--examples/nrf/src/bin/pwm_simple_sin.rs12
3 files changed, 66 insertions, 30 deletions
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs
index 422943124..3f05ed58e 100644
--- a/embassy-nrf/src/pwm.rs
+++ b/embassy-nrf/src/pwm.rs
@@ -24,10 +24,13 @@ pub enum Prescaler {
24 Div128, 24 Div128,
25} 25}
26 26
27/// How a sequence is read from RAM and is spread to the compare register
27#[derive(Debug, Eq, PartialEq, Clone, Copy)] 28#[derive(Debug, Eq, PartialEq, Clone, Copy)]
28pub enum SequenceLoad { 29pub enum SequenceLoad {
30 /// sequence in buffer will be used across all channels
29 Common, 31 Common,
30 Grouped, 32 Grouped,
33 /// buffer holds [ch0_0, ch1_0, ch2_0, ch3_0... ch0_n, ch1_n, ch2_n, ch3_n]
31 Individual, 34 Individual,
32 Waveform, 35 Waveform,
33} 36}
@@ -43,26 +46,32 @@ pub struct Pwm<'d, T: Instance> {
43 phantom: PhantomData<&'d mut T>, 46 phantom: PhantomData<&'d mut T>,
44} 47}
45 48
49#[derive(Debug, Eq, PartialEq, Clone, Copy)]
50pub enum LoopMode {
51 // Repeat n additional times after the first
52 Additional(u16),
53 /// Repeat until `stop` is called
54 Infinite,
55}
56
46// Configure an infinite looping sequence for `simple_playback` 57// Configure an infinite looping sequence for `simple_playback`
47pub struct LoopingConfig<'a> { 58pub struct LoopingConfig<'a> {
48 /// Selects up mode or up-and-down mode for the counter 59 /// Selects up mode or up-and-down mode for the counter
49 pub counter_mode: CounterMode, 60 pub counter_mode: CounterMode,
50 // top value to be compared against buffer values 61 // Top value to be compared against buffer values
51 pub top: u16, 62 pub top: u16,
52 /// Configuration for PWM_CLK 63 /// Configuration for PWM_CLK
53 pub prescaler: Prescaler, 64 pub prescaler: Prescaler,
54 /// In ram buffer to be played back 65 /// In ram buffer to be played back
55 pub sequence: &'a [u16], 66 pub sequence: &'a [u16],
56 /// Common Mode means seq in buffer will be used across all channels 67 /// How a sequence is read from RAM and is spread to the compare register
57 /// Individual Mode buffer holds [ch0_0, ch1_0, ch2_0, ch3_0, ch0_1, ch1_1,
58 /// ch2_1, ch3_1 ... ch0_n, ch1_n, ch2_n, ch3_n]
59 pub sequence_load: SequenceLoad, 68 pub sequence_load: SequenceLoad,
60 /// will instruct a new RAM stored pulse width value on every (N+1)th PWM 69 /// Number of additional PWM periods between samples loaded into compare register
61 /// period. Setting the register to zero will result in a new duty cycle 70 pub refresh: u32,
62 /// update every PWM period as long as the minimum PWM period is observed. 71 /// Number of additional PWM periods after the sequence ends
63 pub repeats: u32,
64 /// enddelay PWM period delays between last period on sequence 0 before repeating
65 pub enddelay: u32, 72 pub enddelay: u32,
73 /// How many times to repeat the sequence
74 pub additional_loops: LoopMode,
66} 75}
67 76
68#[derive(Debug, Clone, Copy, PartialEq, Eq)] 77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -146,6 +155,7 @@ impl<'d, T: Instance> Pwm<'d, T> {
146 } 155 }
147 } 156 }
148 157
158 /// Returns a configured pwm that has had start called on it
149 pub fn simple_playback( 159 pub fn simple_playback(
150 _pwm: impl Unborrow<Target = T> + 'd, 160 _pwm: impl Unborrow<Target = T> + 'd,
151 ch0: impl Unborrow<Target = impl GpioOptionalPin> + 'd, 161 ch0: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
@@ -209,7 +219,7 @@ impl<'d, T: Instance> Pwm<'d, T> {
209 r.seq0 219 r.seq0
210 .cnt 220 .cnt
211 .write(|w| unsafe { w.bits(config.sequence.len() as u32) }); 221 .write(|w| unsafe { w.bits(config.sequence.len() as u32) });
212 r.seq0.refresh.write(|w| unsafe { w.bits(config.repeats) }); 222 r.seq0.refresh.write(|w| unsafe { w.bits(config.refresh) });
213 r.seq0 223 r.seq0
214 .enddelay 224 .enddelay
215 .write(|w| unsafe { w.bits(config.enddelay) }); 225 .write(|w| unsafe { w.bits(config.enddelay) });
@@ -220,17 +230,42 @@ impl<'d, T: Instance> Pwm<'d, T> {
220 r.seq1 230 r.seq1
221 .cnt 231 .cnt
222 .write(|w| unsafe { w.bits(config.sequence.len() as u32) }); 232 .write(|w| unsafe { w.bits(config.sequence.len() as u32) });
223 r.seq1.refresh.write(|w| unsafe { w.bits(config.repeats) }); 233 r.seq1.refresh.write(|w| unsafe { w.bits(config.refresh) });
224 r.seq1 234 r.seq1
225 .enddelay 235 .enddelay
226 .write(|w| unsafe { w.bits(config.enddelay) }); 236 .write(|w| unsafe { w.bits(config.enddelay) });
227 237
228 r.loop_.write(|w| unsafe { w.cnt().bits(0x1) }); 238 match config.additional_loops {
229 239 LoopMode::Additional(0) => {
230 r.shorts.write(|w| w.loopsdone_seqstart1().set_bit()); 240 r.loop_.write(|w| w.cnt().disabled());
241 r.tasks_seqstart[0].write(|w| unsafe { w.bits(0x01) });
242 }
243 LoopMode::Additional(n) => {
244 let times = (n / 2) + 1;
245
246 r.loop_.write(|w| unsafe { w.cnt().bits(times) });
247 r.shorts.write(|w| {
248 w.loopsdone_seqstart1().enabled();
249 w.loopsdone_seqstart0().disabled();
250 w.loopsdone_stop().enabled()
251 });
252
253 if n & 1 == 1 {
254 r.tasks_seqstart[0].write(|w| unsafe { w.bits(0x01) });
255 } else {
256 r.tasks_seqstart[1].write(|w| unsafe { w.bits(0x01) });
257 }
258 }
231 259
232 // tasks_seqstart doesnt exist in all svds so write its bit instead 260 LoopMode::Infinite => {
233 r.tasks_seqstart[1].write(|w| unsafe { w.bits(0x01) }); 261 r.loop_.write(|w| unsafe { w.cnt().bits(0x1) });
262 r.shorts.write(|w| {
263 w.loopsdone_seqstart1().enabled();
264 w.loopsdone_seqstart0().disabled()
265 });
266 r.tasks_seqstart[1].write(|w| unsafe { w.bits(0x01) });
267 }
268 }
234 269
235 Ok(Self { 270 Ok(Self {
236 phantom: PhantomData, 271 phantom: PhantomData,
@@ -326,10 +361,8 @@ impl<'d, T: Instance> Pwm<'d, T> {
326 361
327impl<'a, T: Instance> Drop for Pwm<'a, T> { 362impl<'a, T: Instance> Drop for Pwm<'a, T> {
328 fn drop(&mut self) { 363 fn drop(&mut self) {
329 let r = T::regs();
330
331 self.stop(); 364 self.stop();
332 r.enable.write(|w| w.enable().disabled()); 365 self.disable();
333 366
334 info!("pwm drop: done"); 367 info!("pwm drop: done");
335 368
diff --git a/examples/nrf/src/bin/pwm_sequence.rs b/examples/nrf/src/bin/pwm_sequence.rs
index bc356c28b..8b7aeddcd 100644
--- a/examples/nrf/src/bin/pwm_sequence.rs
+++ b/examples/nrf/src/bin/pwm_sequence.rs
@@ -7,7 +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::{CounterMode, LoopingConfig, Prescaler, Pwm, SequenceLoad}; 10use embassy_nrf::pwm::{CounterMode, LoopMode, LoopingConfig, Prescaler, Pwm, SequenceLoad};
11use embassy_nrf::Peripherals; 11use embassy_nrf::Peripherals;
12 12
13#[embassy::main] 13#[embassy::main]
@@ -15,26 +15,23 @@ async fn main(_spawner: Spawner, p: Peripherals) {
15 let seq_values: [u16; 16] = [ 15 let seq_values: [u16; 16] = [
16 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,
17 ]; 17 ];
18
18 let config = LoopingConfig { 19 let config = LoopingConfig {
19 counter_mode: CounterMode::Up, 20 counter_mode: CounterMode::Up,
20 top: 15625, 21 top: 15625,
21 prescaler: Prescaler::Div128, 22 prescaler: Prescaler::Div128,
22 sequence: &seq_values, 23 sequence: &seq_values,
23 sequence_load: SequenceLoad::Individual, 24 sequence_load: SequenceLoad::Individual,
24 repeats: 0, 25 refresh: 0,
25 enddelay: 0, 26 enddelay: 0,
27 additional_loops: LoopMode::Additional(5),
26 }; 28 };
27 29
28 let pwm = unwrap!(Pwm::simple_playback( 30 let _pwm = unwrap!(Pwm::simple_playback(
29 p.PWM0, p.P0_13, p.P0_15, p.P0_16, p.P0_14, config 31 p.PWM0, p.P0_13, p.P0_15, p.P0_16, p.P0_14, config
30 )); 32 ));
31 info!("pwm started!"); 33 info!("pwm started!");
32 34
33 Timer::after(Duration::from_millis(10000)).await;
34
35 pwm.stop();
36 info!("pwm stopped!");
37
38 loop { 35 loop {
39 Timer::after(Duration::from_millis(1000)).await; 36 Timer::after(Duration::from_millis(1000)).await;
40 } 37 }
diff --git a/examples/nrf/src/bin/pwm_simple_sin.rs b/examples/nrf/src/bin/pwm_simple_sin.rs
index 866202a4c..3fbfc960f 100644
--- a/examples/nrf/src/bin/pwm_simple_sin.rs
+++ b/examples/nrf/src/bin/pwm_simple_sin.rs
@@ -9,7 +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::{CounterMode, LoopingConfig, Prescaler, Pwm, SequenceLoad}; 12use embassy_nrf::pwm::{CounterMode, LoopMode, LoopingConfig, Prescaler, Pwm, SequenceLoad};
13use embassy_nrf::Peripherals; 13use embassy_nrf::Peripherals;
14use micromath::F32Ext; 14use micromath::F32Ext;
15 15
@@ -26,15 +26,21 @@ async fn main(_spawner: Spawner, p: Peripherals) {
26 prescaler: Prescaler::Div16, 26 prescaler: Prescaler::Div16,
27 sequence: &seq_values, 27 sequence: &seq_values,
28 sequence_load: SequenceLoad::Common, 28 sequence_load: SequenceLoad::Common,
29 repeats: 0, 29 refresh: 0,
30 enddelay: 0, 30 enddelay: 0,
31 additional_loops: LoopMode::Infinite,
31 }; 32 };
32 33
33 let _pwm = unwrap!(Pwm::simple_playback( 34 let pwm = unwrap!(Pwm::simple_playback(
34 p.PWM0, p.P0_13, NoPin, NoPin, NoPin, config 35 p.PWM0, p.P0_13, NoPin, NoPin, NoPin, config
35 )); 36 ));
36 info!("pwm started!"); 37 info!("pwm started!");
37 38
39 Timer::after(Duration::from_millis(20000)).await;
40
41 pwm.stop();
42 info!("pwm stopped!");
43
38 loop { 44 loop {
39 Timer::after(Duration::from_millis(1000)).await; 45 Timer::after(Duration::from_millis(1000)).await;
40 } 46 }