diff options
| author | pennae <[email protected]> | 2023-04-25 23:17:57 +0200 |
|---|---|---|
| committer | pennae <[email protected]> | 2023-05-02 13:44:24 +0200 |
| commit | 6cec6fa09b3bcc01ada4d5d5decd02cc2a3a8e4f (patch) | |
| tree | 0060cd87b08c1cc150d4d3c909d514a0f23b930f | |
| parent | 0d224a00e1023082f03610b74c37933506561c26 (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.rs | 34 |
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 | ||
