aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nrf/src/pwm.rs108
-rw-r--r--examples/nrf/src/bin/pwm_sequence_ppi.rs73
2 files changed, 181 insertions, 0 deletions
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs
index 90cdf69c6..87a2d5b65 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,6 +208,106 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
200 Ok(()) 208 Ok(())
201 } 209 }
202 210
211 /// Returns reference to `Stopped` event endpoint for PPI.
212 #[inline(always)]
213 pub fn event_stopped(&self) -> Event {
214 let r = T::regs();
215
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
203 /// Stop playback. 311 /// Stop playback.
204 #[inline(always)] 312 #[inline(always)]
205 pub fn stop(&self) { 313 pub fn stop(&self) {
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}