aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpennae <[email protected]>2023-04-25 23:17:57 +0200
committerpennae <[email protected]>2023-05-02 13:44:24 +0200
commit6cec6fa09b3bcc01ada4d5d5decd02cc2a3a8e4f (patch)
tree0060cd87b08c1cc150d4d3c909d514a0f23b930f
parent0d224a00e1023082f03610b74c37933506561c26 (diff)
rp/pio: don't use modify on shared registers
pio control registers are notionally shared between state machines as well. state machine operations that change these registers must use atomic accesses (or critical sections, which would be overkill). notably PioPin::set_input_sync_bypass was even wrong, enabling the bypass on a pin requires the corresponding bit to be set (not cleared). the PioCommon function got it right.
-rw-r--r--embassy-rp/src/pio.rs34
1 files changed, 19 insertions, 15 deletions
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs
index b20ebbc77..e9a67fd48 100644
--- a/embassy-rp/src/pio.rs
+++ b/embassy-rp/src/pio.rs
@@ -298,9 +298,11 @@ impl<PIO: PioInstance> PioPin<PIO> {
298 pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) { 298 pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) {
299 let mask = 1 << self.pin(); 299 let mask = 1 << self.pin();
300 unsafe { 300 unsafe {
301 PIO::PIO 301 if bypass {
302 .input_sync_bypass() 302 PIO::PIO.input_sync_bypass().write_set(|w| *w = mask);
303 .modify(|w| *w = if bypass { *w & !mask } else { *w | mask }); 303 } else {
304 PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask);
305 }
304 } 306 }
305 } 307 }
306 308
@@ -336,18 +338,19 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
336 } 338 }
337 339
338 fn restart(&mut self) { 340 fn restart(&mut self) {
341 let mask = 1u8 << Self::Sm::SM_NO;
339 unsafe { 342 unsafe {
340 Self::Pio::PIO 343 Self::Pio::PIO.ctrl().write_set(|w| w.set_sm_restart(mask));
341 .ctrl()
342 .modify(|w| w.set_sm_restart(1u8 << Self::Sm::SM_NO));
343 } 344 }
344 } 345 }
345 fn set_enable(&mut self, enable: bool) { 346 fn set_enable(&mut self, enable: bool) {
346 let mask = 1u8 << Self::Sm::SM_NO; 347 let mask = 1u8 << Self::Sm::SM_NO;
347 unsafe { 348 unsafe {
348 Self::Pio::PIO 349 if enable {
349 .ctrl() 350 Self::Pio::PIO.ctrl().write_set(|w| w.set_sm_enable(mask));
350 .modify(|w| w.set_sm_enable((w.sm_enable() & !mask) | (if enable { mask } else { 0 }))); 351 } else {
352 Self::Pio::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask));
353 }
351 } 354 }
352 } 355 }
353 356
@@ -419,10 +422,9 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
419 } 422 }
420 423
421 fn clkdiv_restart(&mut self) { 424 fn clkdiv_restart(&mut self) {
425 let mask = 1u8 << Self::Sm::SM_NO;
422 unsafe { 426 unsafe {
423 Self::Pio::PIO 427 Self::Pio::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask));
424 .ctrl()
425 .modify(|w| w.set_clkdiv_restart(1u8 << Self::Sm::SM_NO));
426 } 428 }
427 } 429 }
428 430
@@ -869,9 +871,11 @@ pub trait PioCommon: sealed::PioCommon + Sized {
869 871
870 fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) { 872 fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) {
871 unsafe { 873 unsafe {
872 Self::Pio::PIO 874 // this can interfere with per-pin bypass functions. splitting the
873 .input_sync_bypass() 875 // modification is going to be fine since nothing that relies on
874 .modify(|w| *w = (*w & !mask) | (bypass & mask)); 876 // it can reasonably run before we finish.
877 Self::Pio::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass);
878 Self::Pio::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass);
875 } 879 }
876 } 880 }
877 881