defensive dma

This commit is contained in:
Jacob Rosenthal 2021-11-10 12:34:41 -07:00
parent 4751dbddc6
commit 903b8f032f

View File

@ -3,7 +3,7 @@
use core::marker::PhantomData; use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering}; use core::sync::atomic::{compiler_fence, Ordering};
use embassy::util::Unborrow; 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::sealed::Pin as _;
use crate::gpio::{AnyPin, OptionalPin as GpioOptionalPin}; 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()); r.enable.write(|w| w.enable().enabled());
// defensive before seqstart
compiler_fence(Ordering::SeqCst);
match times { match times {
// just the one time, no loop count // just the one time, no loop count
SequenceMode::Times(1) => { SequenceMode::Times(1) => {
r.loop_.write(|w| w.cnt().disabled()); r.loop_.write(|w| w.cnt().disabled());
// tasks_seqstart() doesn't exist in all svds so write its bit instead // tasks_seqstart() doesn't exist in all svds so write its bit instead
r.tasks_seqstart[0].write(|w| unsafe { w.bits(0x01) }); 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 // loop count is how many times to play BOTH sequences
// 2 total (1 x 2) // 2 total (1 x 2)
@ -177,17 +184,30 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
if odd { if odd {
// tasks_seqstart() doesn't exist in all svds so write its bit instead // tasks_seqstart() doesn't exist in all svds so write its bit instead
r.tasks_seqstart[1].write(|w| unsafe { w.bits(0x01) }); 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 { } else {
// tasks_seqstart() doesn't exist in all svds so write its bit instead // tasks_seqstart() doesn't exist in all svds so write its bit instead
r.tasks_seqstart[0].write(|w| unsafe { w.bits(0x01) }); 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 // to play infinitely, repeat the sequence one time, then have loops done self trigger seq0 again
SequenceMode::Infinite => { SequenceMode::Infinite => {
r.loop_.write(|w| unsafe { w.cnt().bits(0x1) }); r.loop_.write(|w| unsafe { w.cnt().bits(0x1) });
r.shorts.write(|w| w.loopsdone_seqstart0().enabled()); r.shorts.write(|w| w.loopsdone_seqstart0().enabled());
// tasks_seqstart() doesn't exist in all svds so write its bit instead // tasks_seqstart() doesn't exist in all svds so write its bit instead
r.tasks_seqstart[0].write(|w| unsafe { w.bits(0x01) }); 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(); r.shorts.reset();
compiler_fence(Ordering::SeqCst);
// tasks_stop() doesn't exist in all svds so write its bit instead // tasks_stop() doesn't exist in all svds so write its bit instead
r.tasks_stop.write(|w| unsafe { w.bits(0x01) }); r.tasks_stop.write(|w| unsafe { w.bits(0x01) });
} }
@ -404,6 +426,8 @@ impl<'d, T: Instance> SimplePwm<'d, T> {
r.shorts.reset(); r.shorts.reset();
compiler_fence(Ordering::SeqCst);
// tasks_stop() doesn't exist in all svds so write its bit instead // tasks_stop() doesn't exist in all svds so write its bit instead
r.tasks_stop.write(|w| unsafe { w.bits(0x01) }); r.tasks_stop.write(|w| unsafe { w.bits(0x01) });
} }
@ -432,11 +456,15 @@ impl<'d, T: Instance> SimplePwm<'d, T> {
.ptr .ptr
.write(|w| unsafe { w.bits(&self.duty as *const _ as u32) }); .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); compiler_fence(Ordering::SeqCst);
// tasks_seqstart() doesn't exist in all svds so write its bit instead // tasks_seqstart() doesn't exist in all svds so write its bit instead
r.tasks_seqstart[0].write(|w| unsafe { w.bits(1) }); 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. /// Sets the PWM clock prescaler.