aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-11-26 23:08:24 +0000
committerGitHub <[email protected]>2021-11-26 23:08:24 +0000
commitc7d97290284d2637c1eb89f65ff18f913342a71b (patch)
treebbe78c9b8f3e198dda88ebc7072c077cacfad488
parent524eed5db57c73fe06777283f5992bc514f8fc50 (diff)
parent4010a829aef42dd7aec5bdf967675119f2fa0857 (diff)
Merge #486
486: Pwm ppi events r=Dirbaio a=jacobrosenthal More PWM yak shaving. I was going to do some safe pwm ppi events stuff but I just dont think it fits this api design.. ppi is just very low level, im not sure how safe it will be in general * first we should probably have borrows of handlers for ppi with lifetime of the peripheral? hal does https://github.com/nrf-rs/nrf-hal/blob/eb4ba6ae4204c7f58fc968e57b2995df15f5ac77/nrf-hal-common/src/pwm.rs#L714-L716 * in general having access to tasks can put the state in some configuration the api doesnt understand anymore. for `SequencePwm` ideally id hand you back either only seq_start0 or seq_start1 because youd only use one based on if your `Times` is even or odd.. but again we only know that with this api AFTER start has been called. I dont think were ready for typestates SO I figured why not add the pwm ppi events but make them unsafe and commit this example since I started it. Somewhat related drop IS removing the last duty cycle from the pin correctly, but stop DOES NOT..the only thing that sets the pin back is pin.conf() as far as I can tell, so I tried to document that better and got rid of stop for the `SimplePwm` again since that doesnt need it then. However its ackward we dont have a way to unset the pwm without setting a new sequence of 0s, or dropping the peripheral Co-authored-by: Jacob Rosenthal <[email protected]>
-rw-r--r--embassy-nrf/src/pwm.rs170
-rw-r--r--examples/nrf/src/bin/pwm_sequence_ppi.rs73
2 files changed, 206 insertions, 37 deletions
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs
index 90cdf69c6..3fdc37ec0 100644
--- a/embassy-nrf/src/pwm.rs
+++ b/embassy-nrf/src/pwm.rs
@@ -9,6 +9,7 @@ use crate::gpio::sealed::Pin as _;
9use crate::gpio::{AnyPin, OptionalPin as GpioOptionalPin}; 9use crate::gpio::{AnyPin, OptionalPin as GpioOptionalPin};
10use crate::interrupt::Interrupt; 10use crate::interrupt::Interrupt;
11use crate::pac; 11use crate::pac;
12use crate::ppi::{Event, Task};
12use crate::util::slice_in_ram_or; 13use crate::util::slice_in_ram_or;
13 14
14/// SimplePwm is the traditional pwm interface you're probably used to, allowing 15/// SimplePwm is the traditional pwm interface you're probably used to, allowing
@@ -101,6 +102,13 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
101 // Disable all interrupts 102 // Disable all interrupts
102 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); 103 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
103 r.shorts.reset(); 104 r.shorts.reset();
105 r.events_stopped.reset();
106 r.events_loopsdone.reset();
107 r.events_seqend[0].reset();
108 r.events_seqend[1].reset();
109 r.events_pwmperiodend.reset();
110 r.events_seqstarted[0].reset();
111 r.events_seqstarted[1].reset();
104 112
105 r.seq0 113 r.seq0
106 .ptr 114 .ptr
@@ -200,12 +208,111 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
200 Ok(()) 208 Ok(())
201 } 209 }
202 210
203 /// Stop playback. 211 /// Returns reference to `Stopped` event endpoint for PPI.
204 #[inline(always)] 212 #[inline(always)]
205 pub fn stop(&self) { 213 pub fn event_stopped(&self) -> Event {
206 let r = T::regs(); 214 let r = T::regs();
207 215
208 r.enable.write(|w| w.enable().disabled()); 216 Event::from_reg(&r.events_stopped)
217 }
218
219 /// Returns reference to `LoopsDone` event endpoint for PPI.
220 #[inline(always)]
221 pub fn event_loops_done(&self) -> Event {
222 let r = T::regs();
223
224 Event::from_reg(&r.events_loopsdone)
225 }
226
227 /// Returns reference to `PwmPeriodEnd` event endpoint for PPI.
228 #[inline(always)]
229 pub fn event_pwm_period_end(&self) -> Event {
230 let r = T::regs();
231
232 Event::from_reg(&r.events_pwmperiodend)
233 }
234
235 /// Returns reference to `Seq0 End` event endpoint for PPI.
236 #[inline(always)]
237 pub fn event_seq_end(&self) -> Event {
238 let r = T::regs();
239
240 Event::from_reg(&r.events_seqend[0])
241 }
242
243 /// Returns reference to `Seq1 End` event endpoint for PPI.
244 #[inline(always)]
245 pub fn event_seq1_end(&self) -> Event {
246 let r = T::regs();
247
248 Event::from_reg(&r.events_seqend[1])
249 }
250
251 /// Returns reference to `Seq0 Started` event endpoint for PPI.
252 #[inline(always)]
253 pub fn event_seq0_started(&self) -> Event {
254 let r = T::regs();
255
256 Event::from_reg(&r.events_seqstarted[0])
257 }
258
259 /// Returns reference to `Seq1 Started` event endpoint for PPI.
260 #[inline(always)]
261 pub fn event_seq1_started(&self) -> Event {
262 let r = T::regs();
263
264 Event::from_reg(&r.events_seqstarted[1])
265 }
266
267 /// Returns reference to `Seq0 Start` task endpoint for PPI.
268 /// # Safety
269 ///
270 /// Interacting with the sequence while it runs puts it in an unknown state
271 #[inline(always)]
272 pub unsafe fn task_start_seq0(&self) -> Task {
273 let r = T::regs();
274
275 Task::from_reg(&r.tasks_seqstart[0])
276 }
277
278 /// Returns reference to `Seq1 Started` task endpoint for PPI.
279 /// # Safety
280 ///
281 /// Interacting with the sequence while it runs puts it in an unknown state
282 #[inline(always)]
283 pub unsafe fn task_start_seq1(&self) -> Task {
284 let r = T::regs();
285
286 Task::from_reg(&r.tasks_seqstart[1])
287 }
288
289 /// Returns reference to `NextStep` task endpoint for PPI.
290 /// # Safety
291 ///
292 /// Interacting with the sequence while it runs puts it in an unknown state
293 #[inline(always)]
294 pub unsafe fn task_next_step(&self) -> Task {
295 let r = T::regs();
296
297 Task::from_reg(&r.tasks_nextstep)
298 }
299
300 /// Returns reference to `Stop` task endpoint for PPI.
301 /// # Safety
302 ///
303 /// Interacting with the sequence while it runs puts it in an unknown state
304 #[inline(always)]
305 pub unsafe fn task_stop(&self) -> Task {
306 let r = T::regs();
307
308 Task::from_reg(&r.tasks_stop)
309 }
310
311 /// Stop playback. Disables the peripheral. Does NOT clear the last duty
312 /// cycle from the pin.
313 #[inline(always)]
314 pub fn stop(&self) {
315 let r = T::regs();
209 316
210 r.shorts.reset(); 317 r.shorts.reset();
211 318
@@ -213,6 +320,8 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
213 320
214 // tasks_stop() doesn't exist in all svds so write its bit instead 321 // tasks_stop() doesn't exist in all svds so write its bit instead
215 r.tasks_stop.write(|w| unsafe { w.bits(0x01) }); 322 r.tasks_stop.write(|w| unsafe { w.bits(0x01) });
323
324 r.enable.write(|w| w.enable().disabled());
216 } 325 }
217} 326}
218 327
@@ -224,23 +333,23 @@ impl<'a, T: Instance> Drop for SequencePwm<'a, T> {
224 333
225 if let Some(pin) = &self.ch0 { 334 if let Some(pin) = &self.ch0 {
226 pin.set_low(); 335 pin.set_low();
227 pin.conf().write(|w| w); 336 pin.conf().reset();
228 r.psel.out[0].write(|w| unsafe { w.bits(0x80000000) }); 337 r.psel.out[0].reset();
229 } 338 }
230 if let Some(pin) = &self.ch1 { 339 if let Some(pin) = &self.ch1 {
231 pin.set_low(); 340 pin.set_low();
232 pin.conf().write(|w| w); 341 pin.conf().reset();
233 r.psel.out[1].write(|w| unsafe { w.bits(0x80000000) }); 342 r.psel.out[1].reset();
234 } 343 }
235 if let Some(pin) = &self.ch2 { 344 if let Some(pin) = &self.ch2 {
236 pin.set_low(); 345 pin.set_low();
237 pin.conf().write(|w| w); 346 pin.conf().reset();
238 r.psel.out[2].write(|w| unsafe { w.bits(0x80000000) }); 347 r.psel.out[2].reset();
239 } 348 }
240 if let Some(pin) = &self.ch3 { 349 if let Some(pin) = &self.ch3 {
241 pin.set_low(); 350 pin.set_low();
242 pin.conf().write(|w| w); 351 pin.conf().reset();
243 r.psel.out[3].write(|w| unsafe { w.bits(0x80000000) }); 352 r.psel.out[3].reset();
244 } 353 }
245 } 354 }
246} 355}
@@ -325,8 +434,8 @@ pub enum CounterMode {
325impl<'d, T: Instance> SimplePwm<'d, T> { 434impl<'d, T: Instance> SimplePwm<'d, T> {
326 /// Creates the interface to a `SimplePwm` 435 /// Creates the interface to a `SimplePwm`
327 /// 436 ///
328 /// Defaults the freq to 1Mhz, max_duty 1000, duty 0, up mode, and pins low. 437 /// Enables the peripheral, defaults the freq to 1Mhz, max_duty 1000, duty
329 /// Must be started by calling `set_duty` 438 /// 0, up mode, and pins low. Must be started by calling `set_duty`
330 /// 439 ///
331 /// # Safety 440 /// # Safety
332 /// 441 ///
@@ -405,19 +514,6 @@ impl<'d, T: Instance> SimplePwm<'d, T> {
405 pwm 514 pwm
406 } 515 }
407 516
408 /// Stop playback
409 #[inline(always)]
410 pub fn stop(&self) {
411 let r = T::regs();
412
413 r.shorts.reset();
414
415 compiler_fence(Ordering::SeqCst);
416
417 // tasks_stop() doesn't exist in all svds so write its bit instead
418 r.tasks_stop.write(|w| unsafe { w.bits(0x01) });
419 }
420
421 /// Enables the PWM generator. 517 /// Enables the PWM generator.
422 #[inline(always)] 518 #[inline(always)]
423 pub fn enable(&self) { 519 pub fn enable(&self) {
@@ -425,7 +521,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> {
425 r.enable.write(|w| w.enable().enabled()); 521 r.enable.write(|w| w.enable().enabled());
426 } 522 }
427 523
428 /// Disables the PWM generator. 524 /// Disables the PWM generator. Does NOT clear the last duty cycle from the pin.
429 #[inline(always)] 525 #[inline(always)]
430 pub fn disable(&self) { 526 pub fn disable(&self) {
431 let r = T::regs(); 527 let r = T::regs();
@@ -446,13 +542,14 @@ impl<'d, T: Instance> SimplePwm<'d, T> {
446 // defensive before seqstart 542 // defensive before seqstart
447 compiler_fence(Ordering::SeqCst); 543 compiler_fence(Ordering::SeqCst);
448 544
545 r.events_seqend[0].reset();
546
449 // tasks_seqstart() doesn't exist in all svds so write its bit instead 547 // tasks_seqstart() doesn't exist in all svds so write its bit instead
450 r.tasks_seqstart[0].write(|w| unsafe { w.bits(1) }); 548 r.tasks_seqstart[0].write(|w| unsafe { w.bits(1) });
451 549
452 // defensive wait until waveform is loaded after seqstart so set_duty 550 // defensive wait until waveform is loaded after seqstart so set_duty
453 // can't be called again while dma is still reading 551 // can't be called again while dma is still reading
454 while r.events_seqend[0].read().bits() == 0 {} 552 while r.events_seqend[0].read().bits() == 0 {}
455 r.events_seqend[0].write(|w| w);
456 } 553 }
457 554
458 /// Sets the PWM clock prescaler. 555 /// Sets the PWM clock prescaler.
@@ -512,28 +609,27 @@ impl<'a, T: Instance> Drop for SimplePwm<'a, T> {
512 fn drop(&mut self) { 609 fn drop(&mut self) {
513 let r = T::regs(); 610 let r = T::regs();
514 611
515 self.stop();
516 self.disable(); 612 self.disable();
517 613
518 if let Some(pin) = &self.ch0 { 614 if let Some(pin) = &self.ch0 {
519 pin.set_low(); 615 pin.set_low();
520 pin.conf().write(|w| w); 616 pin.conf().reset();
521 r.psel.out[0].write(|w| unsafe { w.bits(0x80000000) }); 617 r.psel.out[0].reset();
522 } 618 }
523 if let Some(pin) = &self.ch1 { 619 if let Some(pin) = &self.ch1 {
524 pin.set_low(); 620 pin.set_low();
525 pin.conf().write(|w| w); 621 pin.conf().reset();
526 r.psel.out[1].write(|w| unsafe { w.bits(0x80000000) }); 622 r.psel.out[1].reset();
527 } 623 }
528 if let Some(pin) = &self.ch2 { 624 if let Some(pin) = &self.ch2 {
529 pin.set_low(); 625 pin.set_low();
530 pin.conf().write(|w| w); 626 pin.conf().reset();
531 r.psel.out[2].write(|w| unsafe { w.bits(0x80000000) }); 627 r.psel.out[2].reset();
532 } 628 }
533 if let Some(pin) = &self.ch3 { 629 if let Some(pin) = &self.ch3 {
534 pin.set_low(); 630 pin.set_low();
535 pin.conf().write(|w| w); 631 pin.conf().reset();
536 r.psel.out[3].write(|w| unsafe { w.bits(0x80000000) }); 632 r.psel.out[3].reset();
537 } 633 }
538 } 634 }
539} 635}
diff --git a/examples/nrf/src/bin/pwm_sequence_ppi.rs b/examples/nrf/src/bin/pwm_sequence_ppi.rs
new file mode 100644
index 000000000..aaea9ff00
--- /dev/null
+++ b/examples/nrf/src/bin/pwm_sequence_ppi.rs
@@ -0,0 +1,73 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4#![feature(array_from_fn)]
5
6#[path = "../example_common.rs"]
7mod example_common;
8use core::future::pending;
9use defmt::*;
10use embassy::executor::Spawner;
11use embassy_nrf::gpio::{Input, NoPin, Pull};
12use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity};
13use embassy_nrf::ppi::Ppi;
14use embassy_nrf::pwm::{Prescaler, SequenceConfig, SequenceMode, SequencePwm};
15use embassy_nrf::Peripherals;
16
17#[embassy::main]
18async fn main(_spawner: Spawner, p: Peripherals) {
19 let seq_values: [u16; 5] = [1000, 250, 100, 50, 0];
20
21 let mut config = SequenceConfig::default();
22 config.prescaler = Prescaler::Div128;
23 // 1 period is 1000 * (128/16mhz = 0.000008s = 0.008ms) = 8ms
24 // 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)
26 // thus our sequence takes 5 * 250ms or 1.25 seconds
27 config.refresh = 30;
28
29 let pwm = unwrap!(SequencePwm::new(
30 p.PWM0,
31 p.P0_13,
32 NoPin,
33 NoPin,
34 NoPin,
35 config,
36 &seq_values
37 ));
38
39 let _ = pwm.start(SequenceMode::Times(1));
40 // pwm.stop() deconfigures pins, and then the task_start_seq0 task cant work
41 // so its going to have to start running in order load the configuration
42
43 let button1 = InputChannel::new(
44 p.GPIOTE_CH0,
45 Input::new(p.P0_11, Pull::Up),
46 InputChannelPolarity::HiToLo,
47 );
48
49 let button2 = InputChannel::new(
50 p.GPIOTE_CH1,
51 Input::new(p.P0_12, Pull::Up),
52 InputChannelPolarity::HiToLo,
53 );
54
55 // messing with the pwm tasks is ill advised
56 // Times::Ininite and Times even are seq0, Times odd is seq1
57 let start = unsafe { pwm.task_start_seq0() };
58 let stop = unsafe { pwm.task_stop() };
59
60 let mut ppi = Ppi::new_one_to_one(p.PPI_CH1, button1.event_in(), start);
61 ppi.enable();
62
63 let mut ppi2 = Ppi::new_one_to_one(p.PPI_CH0, button2.event_in(), stop);
64 ppi2.enable();
65
66 info!("PPI setup!");
67 info!("Press button 1 to start LED 1");
68 info!("Press button 2 to stop LED 1");
69 info!("Note! task_stop stops the sequence, but not the pin output");
70
71 // Block forever so the above drivers don't get dropped
72 pending::<()>().await;
73}