From 903b8f032fa36fb1bf8cd6f1d1b3c14ce7caa0dd Mon Sep 17 00:00:00 2001 From: Jacob Rosenthal Date: Wed, 10 Nov 2021 12:34:41 -0700 Subject: [PATCH] defensive dma --- embassy-nrf/src/pwm.rs | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 077a27cd..e4ddda39 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering}; use embassy::util::Unborrow; -use embassy_hal_common::unborrow; +use embassy_hal_common::{low_power_wait_until, unborrow}; use crate::gpio::sealed::Pin as _; use crate::gpio::{AnyPin, OptionalPin as GpioOptionalPin}; @@ -157,12 +157,19 @@ impl<'d, T: Instance> SequencePwm<'d, T> { r.enable.write(|w| w.enable().enabled()); + // defensive before seqstart + compiler_fence(Ordering::SeqCst); + match times { // just the one time, no loop count SequenceMode::Times(1) => { r.loop_.write(|w| w.cnt().disabled()); // tasks_seqstart() doesn't exist in all svds so write its bit instead r.tasks_seqstart[0].write(|w| unsafe { w.bits(0x01) }); + + // defensive wait until waveform is loaded after seqstart + low_power_wait_until(|| r.events_seqend[0].read().bits() == 1); + r.events_seqend[0].write(|w| w); } // loop count is how many times to play BOTH sequences // 2 total (1 x 2) @@ -177,17 +184,30 @@ impl<'d, T: Instance> SequencePwm<'d, T> { if odd { // tasks_seqstart() doesn't exist in all svds so write its bit instead r.tasks_seqstart[1].write(|w| unsafe { w.bits(0x01) }); + + // defensive wait until waveform is loaded after seqstart + low_power_wait_until(|| r.events_seqend[1].read().bits() == 1); + r.events_seqend[1].write(|w| w); } else { // tasks_seqstart() doesn't exist in all svds so write its bit instead r.tasks_seqstart[0].write(|w| unsafe { w.bits(0x01) }); + + // defensive wait until waveform is loaded after seqstart + low_power_wait_until(|| r.events_seqend[0].read().bits() == 1); + r.events_seqend[0].write(|w| w); } } // to play infinitely, repeat the sequence one time, then have loops done self trigger seq0 again SequenceMode::Infinite => { r.loop_.write(|w| unsafe { w.cnt().bits(0x1) }); r.shorts.write(|w| w.loopsdone_seqstart0().enabled()); + // tasks_seqstart() doesn't exist in all svds so write its bit instead r.tasks_seqstart[0].write(|w| unsafe { w.bits(0x01) }); + + // defensive wait until waveform is loaded after seqstart + low_power_wait_until(|| r.events_seqend[0].read().bits() == 1); + r.events_seqend[0].write(|w| w); } } @@ -201,6 +221,8 @@ impl<'d, T: Instance> SequencePwm<'d, T> { r.shorts.reset(); + compiler_fence(Ordering::SeqCst); + // tasks_stop() doesn't exist in all svds so write its bit instead r.tasks_stop.write(|w| unsafe { w.bits(0x01) }); } @@ -404,6 +426,8 @@ impl<'d, T: Instance> SimplePwm<'d, T> { r.shorts.reset(); + compiler_fence(Ordering::SeqCst); + // tasks_stop() doesn't exist in all svds so write its bit instead r.tasks_stop.write(|w| unsafe { w.bits(0x01) }); } @@ -432,11 +456,15 @@ impl<'d, T: Instance> SimplePwm<'d, T> { .ptr .write(|w| unsafe { w.bits(&self.duty as *const _ as u32) }); - // todo justify? should i fence elsehwere we task start? or + // defensive before seqstart compiler_fence(Ordering::SeqCst); // tasks_seqstart() doesn't exist in all svds so write its bit instead r.tasks_seqstart[0].write(|w| unsafe { w.bits(1) }); + + // defensive wait until waveform is loaded after seqstart + low_power_wait_until(|| r.events_seqend[0].read().bits() == 1); + r.events_seqend[0].write(|w| w); } /// Sets the PWM clock prescaler.