Skip to content

Commit b9a8233

Browse files
Merge pull request #231 from kalkyl/pwm-dma
Use embedded-dma trait in PWM module
2 parents a20dfc3 + ced5036 commit b9a8233

File tree

3 files changed

+279
-151
lines changed

3 files changed

+279
-151
lines changed

examples/pwm-demo/src/main.rs

Lines changed: 54 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ pub enum AppStatus {
3232
Demo4,
3333
}
3434

35+
type SeqBuffer = &'static mut [u16; 48];
36+
3537
#[rtic::app(device = crate::hal::pac, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)]
3638
const APP: () = {
3739
struct Resources {
@@ -40,13 +42,16 @@ const APP: () = {
4042
btn2: Pin<Input<PullUp>>,
4143
btn3: Pin<Input<PullUp>>,
4244
btn4: Pin<Input<PullUp>>,
43-
pwm: Pwm<PWM0>,
4445
#[init(AppStatus::Idle)]
4546
status: AppStatus,
47+
pwm: Option<PwmSeq<PWM0, SeqBuffer, SeqBuffer>>,
4648
}
4749

4850
#[init]
4951
fn init(mut ctx: init::Context) -> init::LateResources {
52+
static mut BUF0: [u16; 48] = [0u16; 48];
53+
static mut BUF1: [u16; 48] = [0u16; 48];
54+
5055
let _clocks = hal::clocks::Clocks::new(ctx.device.CLOCK).enable_ext_hfosc();
5156
ctx.core.DCB.enable_trace();
5257
ctx.core.DWT.enable_cycle_counter();
@@ -84,7 +89,7 @@ const APP: () = {
8489
btn2,
8590
btn3,
8691
btn4,
87-
pwm,
92+
pwm: pwm.load(Some(BUF0), Some(BUF1), false).ok(),
8893
}
8994
}
9095

@@ -98,29 +103,30 @@ const APP: () = {
98103

99104
#[task(binds = PWM0, resources = [pwm])]
100105
fn on_pwm(ctx: on_pwm::Context) {
101-
let pwm = ctx.resources.pwm;
102-
if pwm.is_event_triggered(PwmEvent::Stopped) {
103-
pwm.reset_event(PwmEvent::Stopped);
106+
let pwm_seq = ctx.resources.pwm.as_ref().unwrap();
107+
if pwm_seq.is_event_triggered(PwmEvent::Stopped) {
108+
pwm_seq.reset_event(PwmEvent::Stopped);
104109
rprintln!("PWM generation was stopped");
105110
}
106111
}
107112

108113
#[task(binds = GPIOTE, resources = [gpiote], schedule = [debounce])]
109114
fn on_gpiote(ctx: on_gpiote::Context) {
110115
ctx.resources.gpiote.reset_events();
111-
ctx.schedule.debounce(ctx.start + 3_000_000.cycles()).ok();
116+
ctx.schedule.debounce(ctx.start + 2_500_000.cycles()).ok();
112117
}
113118

114119
#[task(resources = [btn1, btn2, btn3, btn4, pwm, status])]
115120
fn debounce(ctx: debounce::Context) {
116-
static mut BUF: [u16; 48] = [0u16; 48];
117-
let status = ctx.resources.status;
121+
let (buf0, buf1, pwm) = ctx.resources.pwm.take().unwrap().split();
122+
let BUF0 = buf0.unwrap();
123+
let BUF1 = buf1.unwrap();
118124

119-
let pwm = ctx.resources.pwm;
120125
let max_duty = pwm.max_duty();
121126
let (ch0, ch1, ch2, ch3) = pwm.split_channels();
122127
let (grp0, grp1) = pwm.split_groups();
123128

129+
let status = ctx.resources.status;
124130
if ctx.resources.btn1.is_low().unwrap() {
125131
match status {
126132
AppStatus::Demo1B => {
@@ -143,68 +149,65 @@ const APP: () = {
143149
pwm.set_duty_on_common(max_duty / 10);
144150
}
145151
}
146-
}
147-
if ctx.resources.btn2.is_low().unwrap() {
152+
*ctx.resources.pwm = pwm.load(Some(BUF0), Some(BUF1), false).ok();
153+
} else if ctx.resources.btn2.is_low().unwrap() {
148154
match status {
149155
AppStatus::Demo2B => {
150156
rprintln!("DEMO 2C: Play grouped sequence 4 times");
151157
*status = AppStatus::Demo2C;
152158
let ampl = max_duty as i32 / 20;
153-
let len: usize = 12;
159+
let len: usize = BUF0.len() / 2;
154160
// In `Grouped` mode, each step consists of two values [G0, G1]
155161
for x in 0..len {
156-
BUF[x * 2] = triangle_wave(x, len, ampl, 6, 0) as u16;
157-
BUF[x * 2 + 1] = triangle_wave(x, len, ampl, 0, 0) as u16;
162+
BUF0[x * 2] = triangle_wave(x, len, ampl, 6, 0) as u16;
163+
BUF0[x * 2 + 1] = triangle_wave(x, len, ampl, 0, 0) as u16;
158164
}
165+
BUF1.copy_from_slice(&BUF0[..]);
159166
pwm.set_load_mode(LoadMode::Grouped)
160167
.set_step_mode(StepMode::Auto)
161-
.set_seq_refresh(Seq::Seq0, 70) // Playback rate (periods per step)
162-
.set_seq_refresh(Seq::Seq1, 30)
168+
.set_seq_refresh(Seq::Seq0, 30) // Playback rate (periods per step)
169+
.set_seq_refresh(Seq::Seq1, 10)
163170
.repeat(4);
164-
pwm.load_seq(Seq::Seq0, &BUF[..len]).ok();
165-
pwm.load_seq(Seq::Seq1, &BUF[len..(2 * len)]).ok();
166-
pwm.start_seq(Seq::Seq0);
171+
*ctx.resources.pwm = pwm.load(Some(BUF0), Some(BUF1), true).ok();
167172
}
168173
AppStatus::Demo2A => {
169174
rprintln!("DEMO 2B: Loop individual sequences");
170175
*status = AppStatus::Demo2B;
171176
let ampl = max_duty as i32 / 5;
172177
let offset = max_duty as i32 / 300;
173-
let len = 12;
178+
let len = BUF0.len() / 4;
174179
// In `Individual` mode, each step consists of four values [C0, C1, C2, C3]
175180
for x in 0..len {
176-
BUF[4 * x] = triangle_wave(x, len, ampl, 0, offset) as u16;
177-
BUF[4 * x + 1] = triangle_wave(x, len, ampl, 3, offset) as u16;
178-
BUF[4 * x + 2] = triangle_wave(x, len, ampl, 6, offset) as u16;
179-
BUF[4 * x + 3] = triangle_wave(x, len, ampl, 9, offset) as u16;
181+
BUF0[4 * x] = triangle_wave(x, len, ampl, 0, offset) as u16;
182+
BUF0[4 * x + 1] = triangle_wave(x, len, ampl, 3, offset) as u16;
183+
BUF0[4 * x + 2] = triangle_wave(x, len, ampl, 6, offset) as u16;
184+
BUF0[4 * x + 3] = triangle_wave(x, len, ampl, 9, offset) as u16;
180185
}
186+
BUF1.copy_from_slice(&BUF0[..]);
181187
pwm.set_load_mode(LoadMode::Individual)
182188
.set_seq_refresh(Seq::Seq0, 30)
183189
.set_seq_refresh(Seq::Seq1, 30)
184190
.loop_inf();
185-
pwm.load_seq(Seq::Seq0, &BUF[..(4 * len)]).ok();
186-
pwm.load_seq(Seq::Seq1, &BUF[..(4 * len)]).ok();
187-
pwm.start_seq(Seq::Seq0);
191+
*ctx.resources.pwm = pwm.load(Some(BUF0), Some(BUF1), true).ok();
188192
}
189193
_ => {
190194
rprintln!("DEMO 2A: Play common sequence once");
191195
*status = AppStatus::Demo2A;
192-
let len = 10;
196+
let len = BUF0.len();
193197
// In `Common` mode, each step consists of one value for all channels.
194198
for x in 0..len {
195-
BUF[x] = triangle_wave(x, len, 2000, 0, 100) as u16;
199+
BUF0[x] = triangle_wave(x, len, 2000, 0, 100) as u16;
196200
}
201+
BUF1.copy_from_slice(&BUF0[..]);
197202
pwm.set_load_mode(LoadMode::Common)
198203
.set_step_mode(StepMode::Auto)
199-
.set_seq_refresh(Seq::Seq0, 50)
200-
.one_shot()
201-
.load_seq(Seq::Seq0, &BUF[..len])
202-
.ok();
203-
pwm.start_seq(Seq::Seq0);
204+
.set_seq_refresh(Seq::Seq0, 20)
205+
.set_seq_refresh(Seq::Seq1, 20)
206+
.one_shot();
207+
*ctx.resources.pwm = pwm.load(Some(BUF0), Some(BUF1), true).ok();
204208
}
205209
}
206-
}
207-
if ctx.resources.btn3.is_low().unwrap() {
210+
} else if ctx.resources.btn3.is_low().unwrap() {
208211
match status {
209212
AppStatus::Demo3 => {
210213
rprintln!("DEMO 3: Next step");
@@ -215,46 +218,46 @@ const APP: () = {
215218
pwm.stop();
216219
*status = AppStatus::Idle;
217220
}
221+
*ctx.resources.pwm = pwm.load(Some(BUF0), Some(BUF1), false).ok();
218222
}
219223
_ => {
220224
rprintln!("DEMO 3: Manually step through sequence");
221225
*status = AppStatus::Demo3;
222226
let amplitude = max_duty as i32 / 20;
223227
let offset = max_duty as i32 / 300;
224-
let len = 6;
228+
let len = BUF0.len();
225229
for x in 0..len {
226-
BUF[x] = triangle_wave(x, len, amplitude, 0, offset) as u16;
230+
BUF0[x] = triangle_wave(x * 8, len, amplitude, 0, offset) as u16;
227231
}
232+
BUF1.copy_from_slice(&BUF0[..]);
228233
pwm.set_load_mode(LoadMode::Common)
229234
.set_step_mode(StepMode::NextStep)
230235
.loop_inf();
231-
pwm.load_seq(Seq::Seq0, &BUF[..(len / 2)]).ok();
232-
pwm.load_seq(Seq::Seq1, &BUF[(len / 2)..len]).ok();
233-
pwm.start_seq(Seq::Seq0);
236+
*ctx.resources.pwm = pwm.load(Some(BUF0), Some(BUF1), true).ok();
234237
}
235238
}
236-
}
237-
if ctx.resources.btn4.is_low().unwrap() {
239+
} else if ctx.resources.btn4.is_low().unwrap() {
238240
rprintln!("DEMO 4: Waveform mode");
239241
*status = AppStatus::Demo4;
240-
let len = 12;
242+
let len = BUF0.len() / 4;
241243
// In `Waveform` mode, each step consists of four values [C0, C1, C2, MAX_DUTY]
242244
// So the maximum duty cycle can be set on a per step basis, affecting the PWM frequency
243245
for x in 0..len {
244246
let current_max = x * 2_200 + 5_000;
245-
BUF[4 * x] = ((x % 3) * current_max / (5 * (x + 1))) as u16;
246-
BUF[4 * x + 1] = (((x + 1) % 3) * current_max / (5 * (x + 1))) as u16;
247-
BUF[4 * x + 2] = (((x + 2) % 3) * current_max / (5 * (x + 1))) as u16;
248-
BUF[4 * x + 3] = current_max as u16;
247+
BUF0[4 * x] = ((x % 3) * current_max / (5 * (x + 1))) as u16;
248+
BUF0[4 * x + 1] = (((x + 1) % 3) * current_max / (5 * (x + 1))) as u16;
249+
BUF0[4 * x + 2] = (((x + 2) % 3) * current_max / (5 * (x + 1))) as u16;
250+
BUF0[4 * x + 3] = current_max as u16;
249251
}
252+
BUF1.copy_from_slice(&BUF0[..]);
250253
pwm.set_load_mode(LoadMode::Waveform)
251254
.set_step_mode(StepMode::Auto)
252255
.set_seq_refresh(Seq::Seq0, 150)
253256
.set_seq_refresh(Seq::Seq1, 150)
254257
.loop_inf();
255-
pwm.load_seq(Seq::Seq0, &BUF[..(4 * len)]).ok();
256-
pwm.load_seq(Seq::Seq1, &BUF[..(4 * len)]).ok();
257-
pwm.start_seq(Seq::Seq0);
258+
*ctx.resources.pwm = pwm.load(Some(BUF0), Some(BUF1), true).ok();
259+
} else {
260+
*ctx.resources.pwm = pwm.load(Some(BUF0), Some(BUF1), false).ok();
258261
}
259262
}
260263

nrf-hal-common/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub mod i2s;
4747
pub mod lpcomp;
4848
#[cfg(not(feature = "9160"))]
4949
pub mod ppi;
50-
#[cfg(any(feature = "52833", feature = "52840"))]
50+
#[cfg(not(any(feature = "51", feature = "52832", feature = "9160")))]
5151
pub mod pwm;
5252
#[cfg(not(any(feature = "51", feature = "9160")))]
5353
pub mod qdec;

0 commit comments

Comments
 (0)