diff options
| author | Jacob Rosenthal <[email protected]> | 2021-10-30 16:16:10 -0700 |
|---|---|---|
| committer | Jacob Rosenthal <[email protected]> | 2021-10-30 16:16:10 -0700 |
| commit | 763e250dfea4425912674ed68d77c3291b0505e0 (patch) | |
| tree | dc6acf87b672b30c2866760b99267bc7bb0043c4 | |
| parent | ee8f76537b2dd8e886f44bd7e43d4ba9fd767778 (diff) | |
add ability to configure loop count from 1 to infinite
| -rw-r--r-- | embassy-nrf/src/pwm.rs | 71 | ||||
| -rw-r--r-- | examples/nrf/src/bin/pwm_sequence.rs | 13 | ||||
| -rw-r--r-- | examples/nrf/src/bin/pwm_simple_sin.rs | 12 |
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)] |
| 28 | pub enum SequenceLoad { | 29 | pub 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)] | ||
| 50 | pub 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` |
| 47 | pub struct LoopingConfig<'a> { | 58 | pub 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 | ||
| 327 | impl<'a, T: Instance> Drop for Pwm<'a, T> { | 362 | impl<'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; | |||
| 7 | use defmt::*; | 7 | use defmt::*; |
| 8 | use embassy::executor::Spawner; | 8 | use embassy::executor::Spawner; |
| 9 | use embassy::time::{Duration, Timer}; | 9 | use embassy::time::{Duration, Timer}; |
| 10 | use embassy_nrf::pwm::{CounterMode, LoopingConfig, Prescaler, Pwm, SequenceLoad}; | 10 | use embassy_nrf::pwm::{CounterMode, LoopMode, LoopingConfig, Prescaler, Pwm, SequenceLoad}; |
| 11 | use embassy_nrf::Peripherals; | 11 | use 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::*; | |||
| 9 | use embassy::executor::Spawner; | 9 | use embassy::executor::Spawner; |
| 10 | use embassy::time::{Duration, Timer}; | 10 | use embassy::time::{Duration, Timer}; |
| 11 | use embassy_nrf::gpio::NoPin; | 11 | use embassy_nrf::gpio::NoPin; |
| 12 | use embassy_nrf::pwm::{CounterMode, LoopingConfig, Prescaler, Pwm, SequenceLoad}; | 12 | use embassy_nrf::pwm::{CounterMode, LoopMode, LoopingConfig, Prescaler, Pwm, SequenceLoad}; |
| 13 | use embassy_nrf::Peripherals; | 13 | use embassy_nrf::Peripherals; |
| 14 | use micromath::F32Ext; | 14 | use 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 | } |
