aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2023-05-08 09:17:51 +0000
committerGitHub <[email protected]>2023-05-08 09:17:51 +0000
commit79c60f4a7d17613269f795df867c3c83ca90cbcc (patch)
tree34d841fd742d6b3e7fa4919a9bd60f5bc67e0afb
parenta9c7263ba02181fc4d54975a63d8a1e92426dff3 (diff)
parentdb9b8eb88f095687ed624171cf79fbacf06c199a (diff)
Merge #1434
1434: rp pio IV (the voyage home) r=Dirbaio a=pennae this should hopefully be the last entry in this series. after this we'll have a reasonably safe interface to pio, both for configuration and at runtime. pio now looks very much like the other peripherals (though not exactly, seeing how state machines can't be constructed from a config but only have it applied to them later). the generated code for `StateMachine::set_config` is still larger than we'd like (almost 300 bytes at Oz), but it's a great step up in safety from the previous interface at approximately the same code space cost. Co-authored-by: pennae <[email protected]>
-rw-r--r--embassy-rp/src/pio.rs810
-rw-r--r--embassy-rp/src/pio_instr_util.rs20
-rw-r--r--embassy-rp/src/relocate.rs10
-rw-r--r--examples/rp/Cargo.toml2
-rw-r--r--examples/rp/src/bin/pio_async.rs62
-rw-r--r--examples/rp/src/bin/pio_dma.rs32
-rw-r--r--examples/rp/src/bin/pio_hd44780.rs66
-rw-r--r--examples/rp/src/bin/ws2812-pio.rs58
8 files changed, 564 insertions, 496 deletions
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs
index 2cf4761a5..1e41bed30 100644
--- a/embassy-rp/src/pio.rs
+++ b/embassy-rp/src/pio.rs
@@ -6,15 +6,21 @@ use core::task::{Context, Poll};
6 6
7use atomic_polyfill::{AtomicU32, AtomicU8}; 7use atomic_polyfill::{AtomicU32, AtomicU8};
8use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; 8use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
9use embassy_embedded_hal::SetConfig;
9use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 10use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
10use embassy_sync::waitqueue::AtomicWaker; 11use embassy_sync::waitqueue::AtomicWaker;
12use fixed::types::extra::U8;
13use fixed::FixedU32;
11use pac::io::vals::Gpio0ctrlFuncsel; 14use pac::io::vals::Gpio0ctrlFuncsel;
15use pac::pio::vals::SmExecctrlStatusSel;
16use pio::{SideSet, Wrap};
12 17
13use crate::dma::{Channel, Transfer, Word}; 18use crate::dma::{Channel, Transfer, Word};
14use crate::gpio::sealed::Pin as SealedPin; 19use crate::gpio::sealed::Pin as SealedPin;
15use crate::gpio::{self, AnyPin, Drive, Pull, SlewRate}; 20use crate::gpio::{self, AnyPin, Drive, Level, Pull, SlewRate};
16use crate::pac::dma::vals::TreqSel; 21use crate::pac::dma::vals::TreqSel;
17use crate::{interrupt, pac, peripherals, RegExt}; 22use crate::relocate::RelocatedProgram;
23use crate::{interrupt, pac, peripherals, pio_instr_util, RegExt};
18 24
19struct Wakers([AtomicWaker; 12]); 25struct Wakers([AtomicWaker; 12]);
20 26
@@ -37,8 +43,12 @@ const NEW_AW: AtomicWaker = AtomicWaker::new();
37const PIO_WAKERS_INIT: Wakers = Wakers([NEW_AW; 12]); 43const PIO_WAKERS_INIT: Wakers = Wakers([NEW_AW; 12]);
38static WAKERS: [Wakers; 2] = [PIO_WAKERS_INIT; 2]; 44static WAKERS: [Wakers; 2] = [PIO_WAKERS_INIT; 2];
39 45
46#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
47#[cfg_attr(feature = "defmt", derive(defmt::Format))]
48#[repr(u8)]
40pub enum FifoJoin { 49pub enum FifoJoin {
41 /// Both TX and RX fifo is enabled 50 /// Both TX and RX fifo is enabled
51 #[default]
42 Duplex, 52 Duplex,
43 /// Rx fifo twice as deep. TX fifo disabled 53 /// Rx fifo twice as deep. TX fifo disabled
44 RxOnly, 54 RxOnly,
@@ -46,12 +56,32 @@ pub enum FifoJoin {
46 TxOnly, 56 TxOnly,
47} 57}
48 58
49#[derive(PartialEq)] 59#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
60#[cfg_attr(feature = "defmt", derive(defmt::Format))]
61#[repr(u8)]
50pub enum ShiftDirection { 62pub enum ShiftDirection {
63 #[default]
51 Right = 1, 64 Right = 1,
52 Left = 0, 65 Left = 0,
53} 66}
54 67
68#[derive(Clone, Copy, PartialEq, Eq, Debug)]
69#[cfg_attr(feature = "defmt", derive(defmt::Format))]
70#[repr(u8)]
71pub enum Direction {
72 In = 0,
73 Out = 1,
74}
75
76#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
77#[cfg_attr(feature = "defmt", derive(defmt::Format))]
78#[repr(u8)]
79pub enum StatusSource {
80 #[default]
81 TxFifoLevel = 0,
82 RxFifoLevel = 1,
83}
84
55const RXNEMPTY_MASK: u32 = 1 << 0; 85const RXNEMPTY_MASK: u32 = 1 << 0;
56const TXNFULL_MASK: u32 = 1 << 4; 86const TXNFULL_MASK: u32 = 1 << 4;
57const SMIRQ_MASK: u32 = 1 << 8; 87const SMIRQ_MASK: u32 = 1 << 8;
@@ -96,18 +126,18 @@ pub(crate) unsafe fn init() {
96 126
97/// Future that waits for TX-FIFO to become writable 127/// Future that waits for TX-FIFO to become writable
98#[must_use = "futures do nothing unless you `.await` or poll them"] 128#[must_use = "futures do nothing unless you `.await` or poll them"]
99pub struct FifoOutFuture<'a, 'd, PIO: PioInstance, const SM: usize> { 129pub struct FifoOutFuture<'a, 'd, PIO: Instance, const SM: usize> {
100 sm_tx: &'a mut PioStateMachineTx<'d, PIO, SM>, 130 sm_tx: &'a mut StateMachineTx<'d, PIO, SM>,
101 value: u32, 131 value: u32,
102} 132}
103 133
104impl<'a, 'd, PIO: PioInstance, const SM: usize> FifoOutFuture<'a, 'd, PIO, SM> { 134impl<'a, 'd, PIO: Instance, const SM: usize> FifoOutFuture<'a, 'd, PIO, SM> {
105 pub fn new(sm: &'a mut PioStateMachineTx<'d, PIO, SM>, value: u32) -> Self { 135 pub fn new(sm: &'a mut StateMachineTx<'d, PIO, SM>, value: u32) -> Self {
106 FifoOutFuture { sm_tx: sm, value } 136 FifoOutFuture { sm_tx: sm, value }
107 } 137 }
108} 138}
109 139
110impl<'a, 'd, PIO: PioInstance, const SM: usize> Future for FifoOutFuture<'a, 'd, PIO, SM> { 140impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoOutFuture<'a, 'd, PIO, SM> {
111 type Output = (); 141 type Output = ();
112 fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { 142 fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
113 //debug!("Poll {},{}", PIO::PIO_NO, SM); 143 //debug!("Poll {},{}", PIO::PIO_NO, SM);
@@ -127,7 +157,7 @@ impl<'a, 'd, PIO: PioInstance, const SM: usize> Future for FifoOutFuture<'a, 'd,
127 } 157 }
128} 158}
129 159
130impl<'a, 'd, PIO: PioInstance, const SM: usize> Drop for FifoOutFuture<'a, 'd, PIO, SM> { 160impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoOutFuture<'a, 'd, PIO, SM> {
131 fn drop(&mut self) { 161 fn drop(&mut self) {
132 unsafe { 162 unsafe {
133 PIO::PIO.irqs(0).inte().write_clear(|m| { 163 PIO::PIO.irqs(0).inte().write_clear(|m| {
@@ -139,17 +169,17 @@ impl<'a, 'd, PIO: PioInstance, const SM: usize> Drop for FifoOutFuture<'a, 'd, P
139 169
140/// Future that waits for RX-FIFO to become readable 170/// Future that waits for RX-FIFO to become readable
141#[must_use = "futures do nothing unless you `.await` or poll them"] 171#[must_use = "futures do nothing unless you `.await` or poll them"]
142pub struct FifoInFuture<'a, 'd, PIO: PioInstance, const SM: usize> { 172pub struct FifoInFuture<'a, 'd, PIO: Instance, const SM: usize> {
143 sm_rx: &'a mut PioStateMachineRx<'d, PIO, SM>, 173 sm_rx: &'a mut StateMachineRx<'d, PIO, SM>,
144} 174}
145 175
146impl<'a, 'd, PIO: PioInstance, const SM: usize> FifoInFuture<'a, 'd, PIO, SM> { 176impl<'a, 'd, PIO: Instance, const SM: usize> FifoInFuture<'a, 'd, PIO, SM> {
147 pub fn new(sm: &'a mut PioStateMachineRx<'d, PIO, SM>) -> Self { 177 pub fn new(sm: &'a mut StateMachineRx<'d, PIO, SM>) -> Self {
148 FifoInFuture { sm_rx: sm } 178 FifoInFuture { sm_rx: sm }
149 } 179 }
150} 180}
151 181
152impl<'a, 'd, PIO: PioInstance, const SM: usize> Future for FifoInFuture<'a, 'd, PIO, SM> { 182impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoInFuture<'a, 'd, PIO, SM> {
153 type Output = u32; 183 type Output = u32;
154 fn poll(mut self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { 184 fn poll(mut self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
155 //debug!("Poll {},{}", PIO::PIO_NO, SM); 185 //debug!("Poll {},{}", PIO::PIO_NO, SM);
@@ -168,7 +198,7 @@ impl<'a, 'd, PIO: PioInstance, const SM: usize> Future for FifoInFuture<'a, 'd,
168 } 198 }
169} 199}
170 200
171impl<'a, 'd, PIO: PioInstance, const SM: usize> Drop for FifoInFuture<'a, 'd, PIO, SM> { 201impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoInFuture<'a, 'd, PIO, SM> {
172 fn drop(&mut self) { 202 fn drop(&mut self) {
173 unsafe { 203 unsafe {
174 PIO::PIO.irqs(0).inte().write_clear(|m| { 204 PIO::PIO.irqs(0).inte().write_clear(|m| {
@@ -180,28 +210,21 @@ impl<'a, 'd, PIO: PioInstance, const SM: usize> Drop for FifoInFuture<'a, 'd, PI
180 210
181/// Future that waits for IRQ 211/// Future that waits for IRQ
182#[must_use = "futures do nothing unless you `.await` or poll them"] 212#[must_use = "futures do nothing unless you `.await` or poll them"]
183pub struct IrqFuture<'a, 'd, PIO: PioInstance> { 213pub struct IrqFuture<'a, 'd, PIO: Instance> {
184 pio: PhantomData<&'a PioIrq<'d, PIO, 0>>, 214 pio: PhantomData<&'a mut Irq<'d, PIO, 0>>,
185 irq_no: u8, 215 irq_no: u8,
186} 216}
187 217
188impl<'a, 'd, PIO: PioInstance> Future for IrqFuture<'a, 'd, PIO> { 218impl<'a, 'd, PIO: Instance> Future for IrqFuture<'a, 'd, PIO> {
189 type Output = (); 219 type Output = ();
190 fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { 220 fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
191 //debug!("Poll {},{}", PIO::PIO_NO, SM); 221 //debug!("Poll {},{}", PIO::PIO_NO, SM);
192 222
193 // Check if IRQ flag is already set 223 // Check if IRQ flag is already set
194 if critical_section::with(|_| unsafe { 224 if unsafe { PIO::PIO.irq().read().0 & (1 << self.irq_no) != 0 } {
195 let irq_flags = PIO::PIO.irq(); 225 unsafe {
196 if irq_flags.read().0 & (1 << self.irq_no) != 0 { 226 PIO::PIO.irq().write(|m| m.0 = 1 << self.irq_no);
197 irq_flags.write(|m| {
198 m.0 = 1 << self.irq_no;
199 });
200 true
201 } else {
202 false
203 } 227 }
204 }) {
205 return Poll::Ready(()); 228 return Poll::Ready(());
206 } 229 }
207 230
@@ -215,7 +238,7 @@ impl<'a, 'd, PIO: PioInstance> Future for IrqFuture<'a, 'd, PIO> {
215 } 238 }
216} 239}
217 240
218impl<'a, 'd, PIO: PioInstance> Drop for IrqFuture<'a, 'd, PIO> { 241impl<'a, 'd, PIO: Instance> Drop for IrqFuture<'a, 'd, PIO> {
219 fn drop(&mut self) { 242 fn drop(&mut self) {
220 unsafe { 243 unsafe {
221 PIO::PIO.irqs(0).inte().write_clear(|m| { 244 PIO::PIO.irqs(0).inte().write_clear(|m| {
@@ -225,12 +248,12 @@ impl<'a, 'd, PIO: PioInstance> Drop for IrqFuture<'a, 'd, PIO> {
225 } 248 }
226} 249}
227 250
228pub struct Pin<'l, PIO: PioInstance> { 251pub struct Pin<'l, PIO: Instance> {
229 pin: PeripheralRef<'l, AnyPin>, 252 pin: PeripheralRef<'l, AnyPin>,
230 pio: PhantomData<PIO>, 253 pio: PhantomData<PIO>,
231} 254}
232 255
233impl<'l, PIO: PioInstance> Pin<'l, PIO> { 256impl<'l, PIO: Instance> Pin<'l, PIO> {
234 /// Set the pin's drive strength. 257 /// Set the pin's drive strength.
235 #[inline] 258 #[inline]
236 pub fn set_drive_strength(&mut self, strength: Drive) { 259 pub fn set_drive_strength(&mut self, strength: Drive) {
@@ -293,11 +316,11 @@ impl<'l, PIO: PioInstance> Pin<'l, PIO> {
293 } 316 }
294} 317}
295 318
296pub struct PioStateMachineRx<'d, PIO: PioInstance, const SM: usize> { 319pub struct StateMachineRx<'d, PIO: Instance, const SM: usize> {
297 pio: PhantomData<&'d PIO>, 320 pio: PhantomData<&'d mut PIO>,
298} 321}
299 322
300impl<'d, PIO: PioInstance, const SM: usize> PioStateMachineRx<'d, PIO, SM> { 323impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
301 pub fn empty(&self) -> bool { 324 pub fn empty(&self) -> bool {
302 unsafe { PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0 } 325 unsafe { PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0 }
303 } 326 }
@@ -314,7 +337,9 @@ impl<'d, PIO: PioInstance, const SM: usize> PioStateMachineRx<'d, PIO, SM> {
314 unsafe { 337 unsafe {
315 let fdebug = PIO::PIO.fdebug(); 338 let fdebug = PIO::PIO.fdebug();
316 let ret = fdebug.read().rxstall() & (1 << SM) != 0; 339 let ret = fdebug.read().rxstall() & (1 << SM) != 0;
317 fdebug.write(|w| w.set_rxstall(1 << SM)); 340 if ret {
341 fdebug.write(|w| w.set_rxstall(1 << SM));
342 }
318 ret 343 ret
319 } 344 }
320 } 345 }
@@ -323,7 +348,9 @@ impl<'d, PIO: PioInstance, const SM: usize> PioStateMachineRx<'d, PIO, SM> {
323 unsafe { 348 unsafe {
324 let fdebug = PIO::PIO.fdebug(); 349 let fdebug = PIO::PIO.fdebug();
325 let ret = fdebug.read().rxunder() & (1 << SM) != 0; 350 let ret = fdebug.read().rxunder() & (1 << SM) != 0;
326 fdebug.write(|w| w.set_rxunder(1 << SM)); 351 if ret {
352 fdebug.write(|w| w.set_rxunder(1 << SM));
353 }
327 ret 354 ret
328 } 355 }
329 } 356 }
@@ -370,11 +397,11 @@ impl<'d, PIO: PioInstance, const SM: usize> PioStateMachineRx<'d, PIO, SM> {
370 } 397 }
371} 398}
372 399
373pub struct PioStateMachineTx<'d, PIO: PioInstance, const SM: usize> { 400pub struct StateMachineTx<'d, PIO: Instance, const SM: usize> {
374 pio: PhantomData<&'d PIO>, 401 pio: PhantomData<&'d mut PIO>,
375} 402}
376 403
377impl<'d, PIO: PioInstance, const SM: usize> PioStateMachineTx<'d, PIO, SM> { 404impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
378 pub fn empty(&self) -> bool { 405 pub fn empty(&self) -> bool {
379 unsafe { PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0 } 406 unsafe { PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0 }
380 } 407 }
@@ -390,7 +417,9 @@ impl<'d, PIO: PioInstance, const SM: usize> PioStateMachineTx<'d, PIO, SM> {
390 unsafe { 417 unsafe {
391 let fdebug = PIO::PIO.fdebug(); 418 let fdebug = PIO::PIO.fdebug();
392 let ret = fdebug.read().txstall() & (1 << SM) != 0; 419 let ret = fdebug.read().txstall() & (1 << SM) != 0;
393 fdebug.write(|w| w.set_txstall(1 << SM)); 420 if ret {
421 fdebug.write(|w| w.set_txstall(1 << SM));
422 }
394 ret 423 ret
395 } 424 }
396 } 425 }
@@ -399,7 +428,9 @@ impl<'d, PIO: PioInstance, const SM: usize> PioStateMachineTx<'d, PIO, SM> {
399 unsafe { 428 unsafe {
400 let fdebug = PIO::PIO.fdebug(); 429 let fdebug = PIO::PIO.fdebug();
401 let ret = fdebug.read().txover() & (1 << SM) != 0; 430 let ret = fdebug.read().txover() & (1 << SM) != 0;
402 fdebug.write(|w| w.set_txover(1 << SM)); 431 if ret {
432 fdebug.write(|w| w.set_txover(1 << SM));
433 }
403 ret 434 ret
404 } 435 }
405 } 436 }
@@ -445,12 +476,12 @@ impl<'d, PIO: PioInstance, const SM: usize> PioStateMachineTx<'d, PIO, SM> {
445 } 476 }
446} 477}
447 478
448pub struct PioStateMachine<'d, PIO: PioInstance, const SM: usize> { 479pub struct StateMachine<'d, PIO: Instance, const SM: usize> {
449 rx: PioStateMachineRx<'d, PIO, SM>, 480 rx: StateMachineRx<'d, PIO, SM>,
450 tx: PioStateMachineTx<'d, PIO, SM>, 481 tx: StateMachineTx<'d, PIO, SM>,
451} 482}
452 483
453impl<'d, PIO: PioInstance, const SM: usize> Drop for PioStateMachine<'d, PIO, SM> { 484impl<'d, PIO: Instance, const SM: usize> Drop for StateMachine<'d, PIO, SM> {
454 fn drop(&mut self) { 485 fn drop(&mut self) {
455 unsafe { 486 unsafe {
456 PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(1 << SM)); 487 PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(1 << SM));
@@ -459,377 +490,394 @@ impl<'d, PIO: PioInstance, const SM: usize> Drop for PioStateMachine<'d, PIO, SM
459 } 490 }
460} 491}
461 492
462impl<'d, PIO: PioInstance + 'd, const SM: usize> PioStateMachine<'d, PIO, SM> { 493fn assert_consecutive<'d, PIO: Instance>(pins: &[&Pin<'d, PIO>]) {
463 #[inline(always)] 494 for (p1, p2) in pins.iter().zip(pins.iter().skip(1)) {
464 fn this_sm() -> crate::pac::pio::StateMachine { 495 // purposely does not allow wrap-around because we can't claim pins 30 and 31.
465 PIO::PIO.sm(SM) 496 assert!(p1.pin() + 1 == p2.pin(), "pins must be consecutive");
466 } 497 }
498}
467 499
468 pub fn restart(&mut self) { 500#[derive(Clone, Copy, Default, Debug)]
469 let mask = 1u8 << SM; 501#[cfg_attr(feature = "defmt", derive(defmt::Format))]
470 unsafe { 502#[non_exhaustive]
471 PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask)); 503pub struct ExecConfig {
472 } 504 pub side_en: bool,
473 } 505 pub side_pindir: bool,
474 pub fn set_enable(&mut self, enable: bool) { 506 pub jmp_pin: u8,
475 let mask = 1u8 << SM; 507 pub wrap_top: u8,
476 unsafe { 508 pub wrap_bottom: u8,
477 if enable { 509}
478 PIO::PIO.ctrl().write_set(|w| w.set_sm_enable(mask));
479 } else {
480 PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask));
481 }
482 }
483 }
484 510
485 pub fn is_enabled(&self) -> bool { 511#[derive(Clone, Copy, Default, Debug)]
486 unsafe { PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0 } 512#[cfg_attr(feature = "defmt", derive(defmt::Format))]
487 } 513pub struct ShiftConfig {
514 pub threshold: u8,
515 pub direction: ShiftDirection,
516 pub auto_fill: bool,
517}
488 518
489 pub fn set_clkdiv(&mut self, div_x_256: u32) { 519#[derive(Clone, Copy, Default, Debug)]
490 unsafe { 520#[cfg_attr(feature = "defmt", derive(defmt::Format))]
491 Self::this_sm().clkdiv().write(|w| w.0 = div_x_256 << 8); 521pub struct PinConfig {
492 } 522 pub sideset_count: u8,
493 } 523 pub set_count: u8,
524 pub out_count: u8,
525 pub in_base: u8,
526 pub sideset_base: u8,
527 pub set_base: u8,
528 pub out_base: u8,
529}
494 530
495 pub fn get_clkdiv(&self) -> u32 { 531#[derive(Clone, Copy, Debug)]
496 unsafe { Self::this_sm().clkdiv().read().0 >> 8 } 532pub struct Config<'d, PIO: Instance> {
497 } 533 // CLKDIV
534 pub clock_divider: FixedU32<U8>,
535 // EXECCTRL
536 pub out_en_sel: u8,
537 pub inline_out_en: bool,
538 pub out_sticky: bool,
539 pub status_sel: StatusSource,
540 pub status_n: u8,
541 exec: ExecConfig,
542 origin: Option<u8>,
543 // SHIFTCTRL
544 pub fifo_join: FifoJoin,
545 pub shift_in: ShiftConfig,
546 pub shift_out: ShiftConfig,
547 // PINCTRL
548 pins: PinConfig,
549 in_count: u8,
550 _pio: PhantomData<&'d mut PIO>,
551}
498 552
499 pub fn clkdiv_restart(&mut self) { 553impl<'d, PIO: Instance> Default for Config<'d, PIO> {
500 let mask = 1u8 << SM; 554 fn default() -> Self {
501 unsafe { 555 Self {
502 PIO::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask)); 556 clock_divider: 1u8.into(),
557 out_en_sel: Default::default(),
558 inline_out_en: Default::default(),
559 out_sticky: Default::default(),
560 status_sel: Default::default(),
561 status_n: Default::default(),
562 exec: Default::default(),
563 origin: Default::default(),
564 fifo_join: Default::default(),
565 shift_in: Default::default(),
566 shift_out: Default::default(),
567 pins: Default::default(),
568 in_count: Default::default(),
569 _pio: Default::default(),
503 } 570 }
504 } 571 }
572}
505 573
506 pub fn set_side_enable(&self, enable: bool) { 574impl<'d, PIO: Instance> Config<'d, PIO> {
507 unsafe { 575 pub fn get_exec(&self) -> ExecConfig {
508 Self::this_sm().execctrl().modify(|w| w.set_side_en(enable)); 576 self.exec
509 }
510 } 577 }
511 578 pub unsafe fn set_exec(&mut self, e: ExecConfig) {
512 pub fn is_side_enabled(&self) -> bool { 579 self.exec = e;
513 unsafe { Self::this_sm().execctrl().read().side_en() }
514 } 580 }
515 581
516 pub fn set_side_pindir(&mut self, pindir: bool) { 582 pub fn get_pins(&self) -> PinConfig {
517 unsafe { 583 self.pins
518 Self::this_sm().execctrl().modify(|w| w.set_side_pindir(pindir));
519 }
520 } 584 }
521 585 pub unsafe fn set_pins(&mut self, p: PinConfig) {
522 pub fn is_side_pindir(&self) -> bool { 586 self.pins = p;
523 unsafe { Self::this_sm().execctrl().read().side_pindir() }
524 } 587 }
525 588
526 pub fn set_jmp_pin(&mut self, pin: u8) { 589 /// Configures this state machine to use the given program, including jumping to the origin
527 unsafe { 590 /// of the program. The state machine is not started.
528 Self::this_sm().execctrl().modify(|w| w.set_jmp_pin(pin)); 591 ///
529 } 592 /// `side_set` sets the range of pins affected by side-sets. The range must be consecutive.
593 /// Side-set pins must configured as outputs using [`StateMachine::set_pin_dirs`] to be
594 /// effective.
595 pub fn use_program(&mut self, prog: &LoadedProgram<'d, PIO>, side_set: &[&Pin<'d, PIO>]) {
596 assert!((prog.side_set.bits() - prog.side_set.optional() as u8) as usize == side_set.len());
597 assert_consecutive(side_set);
598 self.exec.side_en = prog.side_set.optional();
599 self.exec.side_pindir = prog.side_set.pindirs();
600 self.exec.wrap_bottom = prog.wrap.target;
601 self.exec.wrap_top = prog.wrap.source;
602 self.pins.sideset_count = prog.side_set.bits();
603 self.pins.sideset_base = side_set.first().map_or(0, |p| p.pin());
604 self.origin = Some(prog.origin);
530 } 605 }
531 606
532 pub fn get_jmp_pin(&mut self) -> u8 { 607 pub fn set_jmp_pin(&mut self, pin: &Pin<'d, PIO>) {
533 unsafe { Self::this_sm().execctrl().read().jmp_pin() } 608 self.exec.jmp_pin = pin.pin();
534 } 609 }
535 610
536 pub fn set_wrap(&self, source: u8, target: u8) { 611 /// Sets the range of pins affected by SET instructions. The range must be consecutive.
537 unsafe { 612 /// Set pins must configured as outputs using [`StateMachine::set_pin_dirs`] to be
538 Self::this_sm().execctrl().modify(|w| { 613 /// effective.
539 w.set_wrap_top(source); 614 pub fn set_set_pins(&mut self, pins: &[&Pin<'d, PIO>]) {
540 w.set_wrap_bottom(target) 615 assert!(pins.len() <= 5);
541 }); 616 assert_consecutive(pins);
542 } 617 self.pins.set_base = pins.first().map_or(0, |p| p.pin());
618 self.pins.set_count = pins.len() as u8;
543 } 619 }
544 620
545 /// Get wrapping addresses. Returns (source, target). 621 /// Sets the range of pins affected by OUT instructions. The range must be consecutive.
546 pub fn get_wrap(&self) -> (u8, u8) { 622 /// Out pins must configured as outputs using [`StateMachine::set_pin_dirs`] to be
547 unsafe { 623 /// effective.
548 let r = Self::this_sm().execctrl().read(); 624 pub fn set_out_pins(&mut self, pins: &[&Pin<'d, PIO>]) {
549 (r.wrap_top(), r.wrap_bottom()) 625 assert_consecutive(pins);
550 } 626 self.pins.out_base = pins.first().map_or(0, |p| p.pin());
627 self.pins.out_count = pins.len() as u8;
551 } 628 }
552 629
553 pub fn set_fifo_join(&mut self, join: FifoJoin) { 630 /// Sets the range of pins used by IN instructions. The range must be consecutive.
554 let (rx, tx) = match join { 631 /// In pins must configured as inputs using [`StateMachine::set_pin_dirs`] to be
555 FifoJoin::Duplex => (false, false), 632 /// effective.
556 FifoJoin::RxOnly => (true, false), 633 pub fn set_in_pins(&mut self, pins: &[&Pin<'d, PIO>]) {
557 FifoJoin::TxOnly => (false, true), 634 assert_consecutive(pins);
558 }; 635 self.pins.in_base = pins.first().map_or(0, |p| p.pin());
559 unsafe { 636 self.in_count = pins.len() as u8;
560 Self::this_sm().shiftctrl().modify(|w| {
561 w.set_fjoin_rx(rx);
562 w.set_fjoin_tx(tx)
563 });
564 }
565 }
566 pub fn get_fifo_join(&self) -> FifoJoin {
567 unsafe {
568 let r = Self::this_sm().shiftctrl().read();
569 // Ignores the invalid state when both bits are set
570 if r.fjoin_rx() {
571 FifoJoin::RxOnly
572 } else if r.fjoin_tx() {
573 FifoJoin::TxOnly
574 } else {
575 FifoJoin::Duplex
576 }
577 }
578 } 637 }
638}
579 639
580 pub fn clear_fifos(&mut self) { 640impl<'d, PIO: Instance, const SM: usize> SetConfig for StateMachine<'d, PIO, SM> {
581 // Toggle FJOIN_RX to flush FIFOs 641 type Config = Config<'d, PIO>;
642
643 fn set_config(&mut self, config: &Self::Config) {
644 // sm expects 0 for 65536, truncation makes that happen
645 assert!(config.clock_divider <= 65536, "clkdiv must be <= 65536");
646 assert!(config.clock_divider >= 1, "clkdiv must be >= 1");
647 assert!(config.out_en_sel < 32, "out_en_sel must be < 32");
648 assert!(config.status_n < 32, "status_n must be < 32");
649 // sm expects 0 for 32, truncation makes that happen
650 assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32");
651 assert!(config.shift_out.threshold <= 32, "shift_out.threshold must be <= 32");
652 let sm = Self::this_sm();
582 unsafe { 653 unsafe {
583 let shiftctrl = Self::this_sm().shiftctrl(); 654 sm.clkdiv().write(|w| w.0 = config.clock_divider.to_bits() << 8);
584 shiftctrl.modify(|w| { 655 sm.execctrl().write(|w| {
585 w.set_fjoin_rx(!w.fjoin_rx()); 656 w.set_side_en(config.exec.side_en);
657 w.set_side_pindir(config.exec.side_pindir);
658 w.set_jmp_pin(config.exec.jmp_pin);
659 w.set_out_en_sel(config.out_en_sel);
660 w.set_inline_out_en(config.inline_out_en);
661 w.set_out_sticky(config.out_sticky);
662 w.set_wrap_top(config.exec.wrap_top);
663 w.set_wrap_bottom(config.exec.wrap_bottom);
664 w.set_status_sel(match config.status_sel {
665 StatusSource::TxFifoLevel => SmExecctrlStatusSel::TXLEVEL,
666 StatusSource::RxFifoLevel => SmExecctrlStatusSel::RXLEVEL,
667 });
668 w.set_status_n(config.status_n);
586 }); 669 });
587 shiftctrl.modify(|w| { 670 sm.shiftctrl().write(|w| {
588 w.set_fjoin_rx(!w.fjoin_rx()); 671 w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly);
672 w.set_fjoin_tx(config.fifo_join == FifoJoin::TxOnly);
673 w.set_pull_thresh(config.shift_out.threshold);
674 w.set_push_thresh(config.shift_in.threshold);
675 w.set_out_shiftdir(config.shift_out.direction == ShiftDirection::Right);
676 w.set_in_shiftdir(config.shift_in.direction == ShiftDirection::Right);
677 w.set_autopull(config.shift_out.auto_fill);
678 w.set_autopush(config.shift_in.auto_fill);
589 }); 679 });
680 sm.pinctrl().write(|w| {
681 w.set_sideset_count(config.pins.sideset_count);
682 w.set_set_count(config.pins.set_count);
683 w.set_out_count(config.pins.out_count);
684 w.set_in_base(config.pins.in_base);
685 w.set_sideset_base(config.pins.sideset_base);
686 w.set_set_base(config.pins.set_base);
687 w.set_out_base(config.pins.out_base);
688 });
689 if let Some(origin) = config.origin {
690 pio_instr_util::exec_jmp(self, origin);
691 }
590 } 692 }
591 } 693 }
694}
592 695
593 pub fn set_pull_threshold(&mut self, threshold: u8) { 696impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
594 unsafe { 697 #[inline(always)]
595 Self::this_sm().shiftctrl().modify(|w| w.set_pull_thresh(threshold)); 698 fn this_sm() -> crate::pac::pio::StateMachine {
596 } 699 PIO::PIO.sm(SM)
597 }
598
599 pub fn get_pull_threshold(&self) -> u8 {
600 unsafe { Self::this_sm().shiftctrl().read().pull_thresh() }
601 }
602 pub fn set_push_threshold(&mut self, threshold: u8) {
603 unsafe {
604 Self::this_sm().shiftctrl().modify(|w| w.set_push_thresh(threshold));
605 }
606 }
607
608 pub fn get_push_threshold(&self) -> u8 {
609 unsafe { Self::this_sm().shiftctrl().read().push_thresh() }
610 } 700 }
611 701
612 pub fn set_out_shift_dir(&mut self, dir: ShiftDirection) { 702 pub fn restart(&mut self) {
703 let mask = 1u8 << SM;
613 unsafe { 704 unsafe {
614 Self::this_sm() 705 PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask));
615 .shiftctrl()
616 .modify(|w| w.set_out_shiftdir(dir == ShiftDirection::Right));
617 } 706 }
618 } 707 }
619 pub fn get_out_shiftdir(&self) -> ShiftDirection { 708 pub fn set_enable(&mut self, enable: bool) {
709 let mask = 1u8 << SM;
620 unsafe { 710 unsafe {
621 if Self::this_sm().shiftctrl().read().out_shiftdir() { 711 if enable {
622 ShiftDirection::Right 712 PIO::PIO.ctrl().write_set(|w| w.set_sm_enable(mask));
623 } else { 713 } else {
624 ShiftDirection::Left 714 PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask));
625 } 715 }
626 } 716 }
627 } 717 }
628 718
629 pub fn set_in_shift_dir(&mut self, dir: ShiftDirection) { 719 pub fn is_enabled(&self) -> bool {
630 unsafe { 720 unsafe { PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0 }
631 Self::this_sm()
632 .shiftctrl()
633 .modify(|w| w.set_in_shiftdir(dir == ShiftDirection::Right));
634 }
635 }
636 pub fn get_in_shiftdir(&self) -> ShiftDirection {
637 unsafe {
638 if Self::this_sm().shiftctrl().read().in_shiftdir() {
639 ShiftDirection::Right
640 } else {
641 ShiftDirection::Left
642 }
643 }
644 } 721 }
645 722
646 pub fn set_autopull(&mut self, auto: bool) { 723 pub fn clkdiv_restart(&mut self) {
724 let mask = 1u8 << SM;
647 unsafe { 725 unsafe {
648 Self::this_sm().shiftctrl().modify(|w| w.set_autopull(auto)); 726 PIO::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask));
649 } 727 }
650 } 728 }
651 729
652 pub fn is_autopull(&self) -> bool { 730 fn with_paused(&mut self, f: impl FnOnce(&mut Self)) {
653 unsafe { Self::this_sm().shiftctrl().read().autopull() } 731 let enabled = self.is_enabled();
654 } 732 self.set_enable(false);
655 733 let pincfg = unsafe { Self::this_sm().pinctrl().read() };
656 pub fn set_autopush(&mut self, auto: bool) { 734 let execcfg = unsafe { Self::this_sm().execctrl().read() };
657 unsafe { 735 unsafe {
658 Self::this_sm().shiftctrl().modify(|w| w.set_autopush(auto)); 736 Self::this_sm().execctrl().write_clear(|w| w.set_out_sticky(true));
659 } 737 }
660 } 738 f(self);
661
662 pub fn is_autopush(&self) -> bool {
663 unsafe { Self::this_sm().shiftctrl().read().autopush() }
664 }
665
666 pub fn get_addr(&self) -> u8 {
667 unsafe { Self::this_sm().addr().read().addr() }
668 }
669 pub fn set_sideset_count(&mut self, count: u8) {
670 unsafe { 739 unsafe {
671 Self::this_sm().pinctrl().modify(|w| w.set_sideset_count(count)); 740 Self::this_sm().pinctrl().write_value(pincfg);
741 Self::this_sm().execctrl().write_value(execcfg);
672 } 742 }
743 self.set_enable(enabled);
673 } 744 }
674 745
675 pub fn get_sideset_count(&self) -> u8 { 746 /// Sets pin directions. This pauses the current state machine to run `SET` commands
676 unsafe { Self::this_sm().pinctrl().read().sideset_count() } 747 /// and temporarily unsets the `OUT_STICKY` bit.
677 } 748 pub fn set_pin_dirs(&mut self, dir: Direction, pins: &[&Pin<'d, PIO>]) {
678 749 self.with_paused(|sm| {
679 pub fn set_sideset_base_pin(&mut self, base_pin: &Pin<PIO>) { 750 for pin in pins {
680 unsafe { 751 unsafe {
681 Self::this_sm().pinctrl().modify(|w| w.set_sideset_base(base_pin.pin())); 752 Self::this_sm().pinctrl().write(|w| {
682 } 753 w.set_set_base(pin.pin());
754 w.set_set_count(1);
755 });
756 // SET PINDIRS, (dir)
757 sm.exec_instr(0b111_00000_100_00000 | dir as u16);
758 }
759 }
760 });
683 } 761 }
684 762
685 pub fn get_sideset_base(&self) -> u8 { 763 /// Sets pin output values. This pauses the current state machine to run
686 unsafe { 764 /// `SET` commands and temporarily unsets the `OUT_STICKY` bit.
687 let r = Self::this_sm().pinctrl().read(); 765 pub fn set_pins(&mut self, level: Level, pins: &[&Pin<'d, PIO>]) {
688 r.sideset_base() 766 self.with_paused(|sm| {
689 } 767 for pin in pins {
768 unsafe {
769 Self::this_sm().pinctrl().write(|w| {
770 w.set_set_base(pin.pin());
771 w.set_set_count(1);
772 });
773 // SET PINS, (dir)
774 sm.exec_instr(0b111_00000_000_00000 | level as u16);
775 }
776 }
777 });
690 } 778 }
691 779
692 /// Set the range of out pins affected by a set instruction. 780 pub fn clear_fifos(&mut self) {
693 pub fn set_set_range(&mut self, base: u8, count: u8) { 781 // Toggle FJOIN_RX to flush FIFOs
694 assert!(base + count < 32);
695 unsafe { 782 unsafe {
696 Self::this_sm().pinctrl().modify(|w| { 783 let shiftctrl = Self::this_sm().shiftctrl();
697 w.set_set_base(base); 784 shiftctrl.modify(|w| {
698 w.set_set_count(count) 785 w.set_fjoin_rx(!w.fjoin_rx());
699 }); 786 });
700 } 787 shiftctrl.modify(|w| {
701 } 788 w.set_fjoin_rx(!w.fjoin_rx());
702
703 /// Get the range of out pins affected by a set instruction. Returns (base, count).
704 pub fn get_set_range(&self) -> (u8, u8) {
705 unsafe {
706 let r = Self::this_sm().pinctrl().read();
707 (r.set_base(), r.set_count())
708 }
709 }
710
711 pub fn set_in_base_pin(&mut self, base: &Pin<PIO>) {
712 unsafe {
713 Self::this_sm().pinctrl().modify(|w| w.set_in_base(base.pin()));
714 }
715 }
716
717 pub fn get_in_base(&self) -> u8 {
718 unsafe {
719 let r = Self::this_sm().pinctrl().read();
720 r.in_base()
721 }
722 }
723
724 pub fn set_out_range(&mut self, base: u8, count: u8) {
725 assert!(base + count < 32);
726 unsafe {
727 Self::this_sm().pinctrl().modify(|w| {
728 w.set_out_base(base);
729 w.set_out_count(count)
730 }); 789 });
731 } 790 }
732 } 791 }
733 792
734 /// Get the range of out pins affected by a set instruction. Returns (base, count). 793 pub unsafe fn exec_instr(&mut self, instr: u16) {
735 pub fn get_out_range(&self) -> (u8, u8) { 794 Self::this_sm().instr().write(|w| w.set_instr(instr));
736 unsafe {
737 let r = Self::this_sm().pinctrl().read();
738 (r.out_base(), r.out_count())
739 }
740 }
741
742 pub fn set_out_pins<'a, 'b: 'a>(&'a mut self, pins: &'b [&Pin<PIO>]) {
743 let count = pins.len();
744 assert!(count >= 1);
745 let start = pins[0].pin() as usize;
746 assert!(start + pins.len() <= 32);
747 for i in 0..count {
748 assert!(pins[i].pin() as usize == start + i, "Pins must be sequential");
749 }
750 self.set_out_range(start as u8, count as u8);
751 }
752
753 pub fn set_set_pins<'a, 'b: 'a>(&'a mut self, pins: &'b [&Pin<PIO>]) {
754 let count = pins.len();
755 assert!(count >= 1);
756 let start = pins[0].pin() as usize;
757 assert!(start + pins.len() <= 32);
758 for i in 0..count {
759 assert!(pins[i].pin() as usize == start + i, "Pins must be sequential");
760 }
761 self.set_set_range(start as u8, count as u8);
762 }
763
764 pub fn get_current_instr() -> u32 {
765 unsafe { Self::this_sm().instr().read().0 }
766 }
767
768 pub fn exec_instr(&mut self, instr: u16) {
769 unsafe {
770 Self::this_sm().instr().write(|w| w.set_instr(instr));
771 }
772 } 795 }
773 796
774 pub fn rx(&mut self) -> &mut PioStateMachineRx<'d, PIO, SM> { 797 pub fn rx(&mut self) -> &mut StateMachineRx<'d, PIO, SM> {
775 &mut self.rx 798 &mut self.rx
776 } 799 }
777 pub fn tx(&mut self) -> &mut PioStateMachineTx<'d, PIO, SM> { 800 pub fn tx(&mut self) -> &mut StateMachineTx<'d, PIO, SM> {
778 &mut self.tx 801 &mut self.tx
779 } 802 }
780 pub fn rx_tx(&mut self) -> (&mut PioStateMachineRx<'d, PIO, SM>, &mut PioStateMachineTx<'d, PIO, SM>) { 803 pub fn rx_tx(&mut self) -> (&mut StateMachineRx<'d, PIO, SM>, &mut StateMachineTx<'d, PIO, SM>) {
781 (&mut self.rx, &mut self.tx) 804 (&mut self.rx, &mut self.tx)
782 } 805 }
783} 806}
784 807
785pub struct PioCommon<'d, PIO: PioInstance> { 808pub struct Common<'d, PIO: Instance> {
786 instructions_used: u32, 809 instructions_used: u32,
787 pio: PhantomData<&'d PIO>, 810 pio: PhantomData<&'d mut PIO>,
788} 811}
789 812
790impl<'d, PIO: PioInstance> Drop for PioCommon<'d, PIO> { 813impl<'d, PIO: Instance> Drop for Common<'d, PIO> {
791 fn drop(&mut self) { 814 fn drop(&mut self) {
792 on_pio_drop::<PIO>(); 815 on_pio_drop::<PIO>();
793 } 816 }
794} 817}
795 818
796pub struct PioInstanceMemory<'d, PIO: PioInstance> { 819pub struct InstanceMemory<'d, PIO: Instance> {
797 used_mask: u32, 820 used_mask: u32,
798 pio: PhantomData<&'d PIO>, 821 pio: PhantomData<&'d mut PIO>,
799} 822}
800 823
801impl<'d, PIO: PioInstance> PioCommon<'d, PIO> { 824pub struct LoadedProgram<'d, PIO: Instance> {
802 pub fn write_instr<I>(&mut self, start: usize, instrs: I) -> PioInstanceMemory<'d, PIO> 825 pub used_memory: InstanceMemory<'d, PIO>,
826 origin: u8,
827 wrap: Wrap,
828 side_set: SideSet,
829}
830
831impl<'d, PIO: Instance> Common<'d, PIO> {
832 pub fn load_program<const SIZE: usize>(&mut self, prog: &RelocatedProgram<SIZE>) -> LoadedProgram<'d, PIO> {
833 match self.try_load_program(prog) {
834 Ok(r) => r,
835 Err(at) => panic!("Trying to write already used PIO instruction memory at {}", at),
836 }
837 }
838
839 pub fn try_load_program<const SIZE: usize>(
840 &mut self,
841 prog: &RelocatedProgram<SIZE>,
842 ) -> Result<LoadedProgram<'d, PIO>, usize> {
843 let used_memory = self.try_write_instr(prog.origin() as _, prog.code())?;
844 Ok(LoadedProgram {
845 used_memory,
846 origin: prog.origin(),
847 wrap: prog.wrap(),
848 side_set: prog.side_set(),
849 })
850 }
851
852 pub fn try_write_instr<I>(&mut self, start: usize, instrs: I) -> Result<InstanceMemory<'d, PIO>, usize>
803 where 853 where
804 I: Iterator<Item = u16>, 854 I: Iterator<Item = u16>,
805 { 855 {
806 let mut used_mask = 0; 856 let mut used_mask = 0;
807 for (i, instr) in instrs.enumerate() { 857 for (i, instr) in instrs.enumerate() {
808 let addr = (i + start) as u8; 858 // wrapping around the end of program memory is valid, let's make use of that.
809 let mask = 1 << (addr as usize); 859 let addr = (i + start) % 32;
810 assert!( 860 let mask = 1 << addr;
811 self.instructions_used & mask == 0, 861 if (self.instructions_used | used_mask) & mask != 0 {
812 "Trying to write already used PIO instruction memory at {}", 862 return Err(addr);
813 addr 863 }
814 );
815 unsafe { 864 unsafe {
816 PIO::PIO.instr_mem(addr as usize).write(|w| { 865 PIO::PIO.instr_mem(addr).write(|w| {
817 w.set_instr_mem(instr); 866 w.set_instr_mem(instr);
818 }); 867 });
819 } 868 }
820 used_mask |= mask; 869 used_mask |= mask;
821 } 870 }
822 self.instructions_used |= used_mask; 871 self.instructions_used |= used_mask;
823 PioInstanceMemory { 872 Ok(InstanceMemory {
824 used_mask, 873 used_mask,
825 pio: PhantomData, 874 pio: PhantomData,
826 } 875 })
827 } 876 }
828 877
829 /// Free instruction memory previously allocated with [`PioCommon::write_instr`]. 878 /// Free instruction memory. This is always possible but unsafe if any
830 /// This is always possible but unsafe if any state machine is still using this 879 /// state machine is still using this bit of memory.
831 /// bit of memory. 880 pub unsafe fn free_instr(&mut self, instrs: InstanceMemory<PIO>) {
832 pub unsafe fn free_instr(&mut self, instrs: PioInstanceMemory<PIO>) {
833 self.instructions_used &= !instrs.used_mask; 881 self.instructions_used &= !instrs.used_mask;
834 } 882 }
835 883
@@ -848,8 +896,8 @@ impl<'d, PIO: PioInstance> PioCommon<'d, PIO> {
848 } 896 }
849 897
850 /// Register a pin for PIO usage. Pins will be released from the PIO block 898 /// Register a pin for PIO usage. Pins will be released from the PIO block
851 /// (i.e., have their `FUNCSEL` reset to `NULL`) when the [`PioCommon`] *and* 899 /// (i.e., have their `FUNCSEL` reset to `NULL`) when the [`Common`] *and*
852 /// all [`PioStateMachine`]s for this block have been dropped. **Other members 900 /// all [`StateMachine`]s for this block have been dropped. **Other members
853 /// of [`Pio`] do not keep pin registrations alive.** 901 /// of [`Pio`] do not keep pin registrations alive.**
854 pub fn make_pio_pin(&mut self, pin: impl Peripheral<P = impl PioPin + 'd> + 'd) -> Pin<'d, PIO> { 902 pub fn make_pio_pin(&mut self, pin: impl Peripheral<P = impl PioPin + 'd> + 'd) -> Pin<'d, PIO> {
855 into_ref!(pin); 903 into_ref!(pin);
@@ -863,13 +911,54 @@ impl<'d, PIO: PioInstance> PioCommon<'d, PIO> {
863 pio: PhantomData::default(), 911 pio: PhantomData::default(),
864 } 912 }
865 } 913 }
914
915 pub fn apply_sm_batch(&mut self, f: impl FnOnce(&mut PioBatch<'d, PIO>)) {
916 let mut batch = PioBatch {
917 clkdiv_restart: 0,
918 sm_restart: 0,
919 sm_enable_mask: 0,
920 sm_enable: 0,
921 _pio: PhantomData,
922 };
923 f(&mut batch);
924 unsafe {
925 PIO::PIO.ctrl().modify(|w| {
926 w.set_clkdiv_restart(batch.clkdiv_restart);
927 w.set_sm_restart(batch.sm_restart);
928 w.set_sm_enable((w.sm_enable() & !batch.sm_enable_mask) | batch.sm_enable);
929 });
930 }
931 }
932}
933
934pub struct PioBatch<'a, PIO: Instance> {
935 clkdiv_restart: u8,
936 sm_restart: u8,
937 sm_enable_mask: u8,
938 sm_enable: u8,
939 _pio: PhantomData<&'a PIO>,
940}
941
942impl<'a, PIO: Instance> PioBatch<'a, PIO> {
943 pub fn restart_clockdiv<const SM: usize>(&mut self, _sm: &mut StateMachine<'a, PIO, SM>) {
944 self.clkdiv_restart |= 1 << SM;
945 }
946
947 pub fn restart<const SM: usize>(&mut self, _sm: &mut StateMachine<'a, PIO, SM>) {
948 self.clkdiv_restart |= 1 << SM;
949 }
950
951 pub fn set_enable<const SM: usize>(&mut self, _sm: &mut StateMachine<'a, PIO, SM>, enable: bool) {
952 self.sm_enable_mask |= 1 << SM;
953 self.sm_enable |= (enable as u8) << SM;
954 }
866} 955}
867 956
868pub struct PioIrq<'d, PIO: PioInstance, const N: usize> { 957pub struct Irq<'d, PIO: Instance, const N: usize> {
869 pio: PhantomData<&'d PIO>, 958 pio: PhantomData<&'d mut PIO>,
870} 959}
871 960
872impl<'d, PIO: PioInstance, const N: usize> PioIrq<'d, PIO, N> { 961impl<'d, PIO: Instance, const N: usize> Irq<'d, PIO, N> {
873 pub fn wait<'a>(&'a mut self) -> IrqFuture<'a, 'd, PIO> { 962 pub fn wait<'a>(&'a mut self) -> IrqFuture<'a, 'd, PIO> {
874 IrqFuture { 963 IrqFuture {
875 pio: PhantomData, 964 pio: PhantomData,
@@ -879,11 +968,11 @@ impl<'d, PIO: PioInstance, const N: usize> PioIrq<'d, PIO, N> {
879} 968}
880 969
881#[derive(Clone)] 970#[derive(Clone)]
882pub struct PioIrqFlags<'d, PIO: PioInstance> { 971pub struct IrqFlags<'d, PIO: Instance> {
883 pio: PhantomData<&'d PIO>, 972 pio: PhantomData<&'d mut PIO>,
884} 973}
885 974
886impl<'d, PIO: PioInstance> PioIrqFlags<'d, PIO> { 975impl<'d, PIO: Instance> IrqFlags<'d, PIO> {
887 pub fn check(&self, irq_no: u8) -> bool { 976 pub fn check(&self, irq_no: u8) -> bool {
888 assert!(irq_no < 8); 977 assert!(irq_no < 8);
889 self.check_any(1 << irq_no) 978 self.check_any(1 << irq_no)
@@ -916,49 +1005,51 @@ impl<'d, PIO: PioInstance> PioIrqFlags<'d, PIO> {
916 } 1005 }
917} 1006}
918 1007
919pub struct Pio<'d, PIO: PioInstance> { 1008pub struct Pio<'d, PIO: Instance> {
920 pub common: PioCommon<'d, PIO>, 1009 pub common: Common<'d, PIO>,
921 pub irq_flags: PioIrqFlags<'d, PIO>, 1010 pub irq_flags: IrqFlags<'d, PIO>,
922 pub irq0: PioIrq<'d, PIO, 0>, 1011 pub irq0: Irq<'d, PIO, 0>,
923 pub irq1: PioIrq<'d, PIO, 1>, 1012 pub irq1: Irq<'d, PIO, 1>,
924 pub irq2: PioIrq<'d, PIO, 2>, 1013 pub irq2: Irq<'d, PIO, 2>,
925 pub irq3: PioIrq<'d, PIO, 3>, 1014 pub irq3: Irq<'d, PIO, 3>,
926 pub sm0: PioStateMachine<'d, PIO, 0>, 1015 pub sm0: StateMachine<'d, PIO, 0>,
927 pub sm1: PioStateMachine<'d, PIO, 1>, 1016 pub sm1: StateMachine<'d, PIO, 1>,
928 pub sm2: PioStateMachine<'d, PIO, 2>, 1017 pub sm2: StateMachine<'d, PIO, 2>,
929 pub sm3: PioStateMachine<'d, PIO, 3>, 1018 pub sm3: StateMachine<'d, PIO, 3>,
1019 _pio: PhantomData<&'d mut PIO>,
930} 1020}
931 1021
932impl<'d, PIO: PioInstance> Pio<'d, PIO> { 1022impl<'d, PIO: Instance> Pio<'d, PIO> {
933 pub fn new(_pio: impl Peripheral<P = PIO> + 'd) -> Self { 1023 pub fn new(_pio: impl Peripheral<P = PIO> + 'd) -> Self {
934 PIO::state().users.store(5, Ordering::Release); 1024 PIO::state().users.store(5, Ordering::Release);
935 PIO::state().used_pins.store(0, Ordering::Release); 1025 PIO::state().used_pins.store(0, Ordering::Release);
936 Self { 1026 Self {
937 common: PioCommon { 1027 common: Common {
938 instructions_used: 0, 1028 instructions_used: 0,
939 pio: PhantomData, 1029 pio: PhantomData,
940 }, 1030 },
941 irq_flags: PioIrqFlags { pio: PhantomData }, 1031 irq_flags: IrqFlags { pio: PhantomData },
942 irq0: PioIrq { pio: PhantomData }, 1032 irq0: Irq { pio: PhantomData },
943 irq1: PioIrq { pio: PhantomData }, 1033 irq1: Irq { pio: PhantomData },
944 irq2: PioIrq { pio: PhantomData }, 1034 irq2: Irq { pio: PhantomData },
945 irq3: PioIrq { pio: PhantomData }, 1035 irq3: Irq { pio: PhantomData },
946 sm0: PioStateMachine { 1036 sm0: StateMachine {
947 rx: PioStateMachineRx { pio: PhantomData }, 1037 rx: StateMachineRx { pio: PhantomData },
948 tx: PioStateMachineTx { pio: PhantomData }, 1038 tx: StateMachineTx { pio: PhantomData },
949 }, 1039 },
950 sm1: PioStateMachine { 1040 sm1: StateMachine {
951 rx: PioStateMachineRx { pio: PhantomData }, 1041 rx: StateMachineRx { pio: PhantomData },
952 tx: PioStateMachineTx { pio: PhantomData }, 1042 tx: StateMachineTx { pio: PhantomData },
953 }, 1043 },
954 sm2: PioStateMachine { 1044 sm2: StateMachine {
955 rx: PioStateMachineRx { pio: PhantomData }, 1045 rx: StateMachineRx { pio: PhantomData },
956 tx: PioStateMachineTx { pio: PhantomData }, 1046 tx: StateMachineTx { pio: PhantomData },
957 }, 1047 },
958 sm3: PioStateMachine { 1048 sm3: StateMachine {
959 rx: PioStateMachineRx { pio: PhantomData }, 1049 rx: StateMachineRx { pio: PhantomData },
960 tx: PioStateMachineTx { pio: PhantomData }, 1050 tx: StateMachineTx { pio: PhantomData },
961 }, 1051 },
1052 _pio: PhantomData,
962 } 1053 }
963 } 1054 }
964} 1055}
@@ -974,12 +1065,13 @@ pub struct State {
974 used_pins: AtomicU32, 1065 used_pins: AtomicU32,
975} 1066}
976 1067
977fn on_pio_drop<PIO: PioInstance>() { 1068fn on_pio_drop<PIO: Instance>() {
978 let state = PIO::state(); 1069 let state = PIO::state();
979 if state.users.fetch_sub(1, Ordering::AcqRel) == 1 { 1070 if state.users.fetch_sub(1, Ordering::AcqRel) == 1 {
980 let used_pins = state.used_pins.load(Ordering::Relaxed); 1071 let used_pins = state.used_pins.load(Ordering::Relaxed);
981 let null = Gpio0ctrlFuncsel::NULL.0; 1072 let null = Gpio0ctrlFuncsel::NULL.0;
982 for i in 0..32 { 1073 // we only have 30 pins. don't test the other two since gpio() asserts.
1074 for i in 0..30 {
983 if used_pins & (1 << i) != 0 { 1075 if used_pins & (1 << i) != 0 {
984 unsafe { 1076 unsafe {
985 pac::IO_BANK0.gpio(i).ctrl().write(|w| w.set_funcsel(null)); 1077 pac::IO_BANK0.gpio(i).ctrl().write(|w| w.set_funcsel(null));
@@ -994,7 +1086,7 @@ mod sealed {
994 1086
995 pub trait PioPin {} 1087 pub trait PioPin {}
996 1088
997 pub trait PioInstance { 1089 pub trait Instance {
998 const PIO_NO: u8; 1090 const PIO_NO: u8;
999 const PIO: &'static crate::pac::pio::Pio; 1091 const PIO: &'static crate::pac::pio::Pio;
1000 const FUNCSEL: crate::pac::io::vals::Gpio0ctrlFuncsel; 1092 const FUNCSEL: crate::pac::io::vals::Gpio0ctrlFuncsel;
@@ -1011,16 +1103,16 @@ mod sealed {
1011 } 1103 }
1012} 1104}
1013 1105
1014pub trait PioInstance: sealed::PioInstance + Sized + Unpin {} 1106pub trait Instance: sealed::Instance + Sized + Unpin {}
1015 1107
1016macro_rules! impl_pio { 1108macro_rules! impl_pio {
1017 ($name:ident, $pio:expr, $pac:ident, $funcsel:ident) => { 1109 ($name:ident, $pio:expr, $pac:ident, $funcsel:ident) => {
1018 impl sealed::PioInstance for peripherals::$name { 1110 impl sealed::Instance for peripherals::$name {
1019 const PIO_NO: u8 = $pio; 1111 const PIO_NO: u8 = $pio;
1020 const PIO: &'static pac::pio::Pio = &pac::$pac; 1112 const PIO: &'static pac::pio::Pio = &pac::$pac;
1021 const FUNCSEL: pac::io::vals::Gpio0ctrlFuncsel = pac::io::vals::Gpio0ctrlFuncsel::$funcsel; 1113 const FUNCSEL: pac::io::vals::Gpio0ctrlFuncsel = pac::io::vals::Gpio0ctrlFuncsel::$funcsel;
1022 } 1114 }
1023 impl PioInstance for peripherals::$name {} 1115 impl Instance for peripherals::$name {}
1024 }; 1116 };
1025} 1117}
1026 1118
diff --git a/embassy-rp/src/pio_instr_util.rs b/embassy-rp/src/pio_instr_util.rs
index 81abdb666..25393b476 100644
--- a/embassy-rp/src/pio_instr_util.rs
+++ b/embassy-rp/src/pio_instr_util.rs
@@ -1,8 +1,8 @@
1use pio::{InSource, InstructionOperands, JmpCondition, OutDestination, SetDestination}; 1use pio::{InSource, InstructionOperands, JmpCondition, OutDestination, SetDestination};
2 2
3use crate::pio::{PioInstance, PioStateMachine}; 3use crate::pio::{Instance, StateMachine};
4 4
5pub fn set_x<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, value: u32) { 5pub unsafe fn set_x<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, value: u32) {
6 const OUT: u16 = InstructionOperands::OUT { 6 const OUT: u16 = InstructionOperands::OUT {
7 destination: OutDestination::X, 7 destination: OutDestination::X,
8 bit_count: 32, 8 bit_count: 32,
@@ -12,7 +12,7 @@ pub fn set_x<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM
12 sm.exec_instr(OUT); 12 sm.exec_instr(OUT);
13} 13}
14 14
15pub fn get_x<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>) -> u32 { 15pub unsafe fn get_x<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>) -> u32 {
16 const IN: u16 = InstructionOperands::IN { 16 const IN: u16 = InstructionOperands::IN {
17 source: InSource::X, 17 source: InSource::X,
18 bit_count: 32, 18 bit_count: 32,
@@ -22,7 +22,7 @@ pub fn get_x<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM
22 sm.rx().pull() 22 sm.rx().pull()
23} 23}
24 24
25pub fn set_y<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, value: u32) { 25pub unsafe fn set_y<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, value: u32) {
26 const OUT: u16 = InstructionOperands::OUT { 26 const OUT: u16 = InstructionOperands::OUT {
27 destination: OutDestination::Y, 27 destination: OutDestination::Y,
28 bit_count: 32, 28 bit_count: 32,
@@ -32,7 +32,7 @@ pub fn set_y<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM
32 sm.exec_instr(OUT); 32 sm.exec_instr(OUT);
33} 33}
34 34
35pub fn get_y<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>) -> u32 { 35pub unsafe fn get_y<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>) -> u32 {
36 const IN: u16 = InstructionOperands::IN { 36 const IN: u16 = InstructionOperands::IN {
37 source: InSource::Y, 37 source: InSource::Y,
38 bit_count: 32, 38 bit_count: 32,
@@ -43,7 +43,7 @@ pub fn get_y<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM
43 sm.rx().pull() 43 sm.rx().pull()
44} 44}
45 45
46pub fn set_pindir<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, data: u8) { 46pub unsafe fn set_pindir<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u8) {
47 let set: u16 = InstructionOperands::SET { 47 let set: u16 = InstructionOperands::SET {
48 destination: SetDestination::PINDIRS, 48 destination: SetDestination::PINDIRS,
49 data, 49 data,
@@ -52,7 +52,7 @@ pub fn set_pindir<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PI
52 sm.exec_instr(set); 52 sm.exec_instr(set);
53} 53}
54 54
55pub fn set_pin<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, data: u8) { 55pub unsafe fn set_pin<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u8) {
56 let set: u16 = InstructionOperands::SET { 56 let set: u16 = InstructionOperands::SET {
57 destination: SetDestination::PINS, 57 destination: SetDestination::PINS,
58 data, 58 data,
@@ -61,7 +61,7 @@ pub fn set_pin<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO,
61 sm.exec_instr(set); 61 sm.exec_instr(set);
62} 62}
63 63
64pub fn set_out_pin<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, data: u32) { 64pub unsafe fn set_out_pin<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u32) {
65 const OUT: u16 = InstructionOperands::OUT { 65 const OUT: u16 = InstructionOperands::OUT {
66 destination: OutDestination::PINS, 66 destination: OutDestination::PINS,
67 bit_count: 32, 67 bit_count: 32,
@@ -70,7 +70,7 @@ pub fn set_out_pin<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<P
70 sm.tx().push(data); 70 sm.tx().push(data);
71 sm.exec_instr(OUT); 71 sm.exec_instr(OUT);
72} 72}
73pub fn set_out_pindir<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, data: u32) { 73pub unsafe fn set_out_pindir<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u32) {
74 const OUT: u16 = InstructionOperands::OUT { 74 const OUT: u16 = InstructionOperands::OUT {
75 destination: OutDestination::PINDIRS, 75 destination: OutDestination::PINDIRS,
76 bit_count: 32, 76 bit_count: 32,
@@ -80,7 +80,7 @@ pub fn set_out_pindir<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachin
80 sm.exec_instr(OUT); 80 sm.exec_instr(OUT);
81} 81}
82 82
83pub fn exec_jmp<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, to_addr: u8) { 83pub unsafe fn exec_jmp<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, to_addr: u8) {
84 let jmp: u16 = InstructionOperands::JMP { 84 let jmp: u16 = InstructionOperands::JMP {
85 address: to_addr, 85 address: to_addr,
86 condition: JmpCondition::Always, 86 condition: JmpCondition::Always,
diff --git a/embassy-rp/src/relocate.rs b/embassy-rp/src/relocate.rs
index f36170e03..9cb279ccd 100644
--- a/embassy-rp/src/relocate.rs
+++ b/embassy-rp/src/relocate.rs
@@ -26,11 +26,7 @@ where
26 Some(if instr & 0b1110_0000_0000_0000 == 0 { 26 Some(if instr & 0b1110_0000_0000_0000 == 0 {
27 // this is a JMP instruction -> add offset to address 27 // this is a JMP instruction -> add offset to address
28 let address = (instr & 0b1_1111) as u8; 28 let address = (instr & 0b1_1111) as u8;
29 let address = address + self.offset; 29 let address = address.wrapping_add(self.offset) % 32;
30 assert!(
31 address < pio::RP2040_MAX_PROGRAM_SIZE as u8,
32 "Invalid JMP out of the program after offset addition"
33 );
34 instr & (!0b11111) | address as u16 30 instr & (!0b11111) | address as u16
35 } else { 31 } else {
36 instr 32 instr
@@ -62,8 +58,8 @@ impl<'a, const PROGRAM_SIZE: usize> RelocatedProgram<'a, PROGRAM_SIZE> {
62 let wrap = self.program.wrap; 58 let wrap = self.program.wrap;
63 let origin = self.origin; 59 let origin = self.origin;
64 Wrap { 60 Wrap {
65 source: wrap.source + origin, 61 source: wrap.source.wrapping_add(origin) % 32,
66 target: wrap.target + origin, 62 target: wrap.target.wrapping_add(origin) % 32,
67 } 63 }
68 } 64 }
69 65
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index 57f6f5c67..d2829df99 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -22,6 +22,8 @@ lorawan = { version = "0.7.3", default-features = false, features = ["default-cr
22 22
23defmt = "0.3" 23defmt = "0.3"
24defmt-rtt = "0.4" 24defmt-rtt = "0.4"
25fixed = "1.23.1"
26fixed-macro = "1.2"
25 27
26#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 28#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
27cortex-m = { version = "0.7.6", features = ["inline-asm"] } 29cortex-m = { version = "0.7.6", features = ["inline-asm"] }
diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs
index 4e0ab5e3c..12484e882 100644
--- a/examples/rp/src/bin/pio_async.rs
+++ b/examples/rp/src/bin/pio_async.rs
@@ -2,14 +2,16 @@
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4use defmt::info; 4use defmt::info;
5use embassy_embedded_hal::SetConfig;
5use embassy_executor::Spawner; 6use embassy_executor::Spawner;
6use embassy_rp::peripherals::PIO0; 7use embassy_rp::peripherals::PIO0;
7use embassy_rp::pio::{Pio, PioCommon, PioIrq, PioPin, PioStateMachine, ShiftDirection}; 8use embassy_rp::pio::{Common, Config, Irq, Pio, PioPin, ShiftDirection, StateMachine};
8use embassy_rp::pio_instr_util;
9use embassy_rp::relocate::RelocatedProgram; 9use embassy_rp::relocate::RelocatedProgram;
10use fixed::traits::ToFixed;
11use fixed_macro::types::U56F8;
10use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
11 13
12fn setup_pio_task_sm0(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachine<PIO0, 0>, pin: impl PioPin) { 14fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: impl PioPin) {
13 // Setup sm0 15 // Setup sm0
14 16
15 // Send data serially to pin 17 // Send data serially to pin
@@ -22,22 +24,18 @@ fn setup_pio_task_sm0(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachine<PIO0,
22 ); 24 );
23 25
24 let relocated = RelocatedProgram::new(&prg.program); 26 let relocated = RelocatedProgram::new(&prg.program);
27 let mut cfg = Config::default();
28 cfg.use_program(&pio.load_program(&relocated), &[]);
25 let out_pin = pio.make_pio_pin(pin); 29 let out_pin = pio.make_pio_pin(pin);
26 let pio_pins = [&out_pin]; 30 cfg.set_out_pins(&[&out_pin]);
27 sm.set_out_pins(&pio_pins); 31 cfg.set_set_pins(&[&out_pin]);
28 pio.write_instr(relocated.origin() as usize, relocated.code()); 32 cfg.clock_divider = (U56F8!(125_000_000) / 20 / 200).to_fixed();
29 pio_instr_util::exec_jmp(sm, relocated.origin()); 33 cfg.shift_out.auto_fill = true;
30 sm.set_clkdiv((125e6 / 20.0 / 2e2 * 256.0) as u32); 34 sm.set_config(&cfg);
31 sm.set_set_range(0, 1);
32 let pio::Wrap { source, target } = relocated.wrap();
33 sm.set_wrap(source, target);
34
35 sm.set_autopull(true);
36 sm.set_out_shift_dir(ShiftDirection::Left);
37} 35}
38 36
39#[embassy_executor::task] 37#[embassy_executor::task]
40async fn pio_task_sm0(mut sm: PioStateMachine<'static, PIO0, 0>) { 38async fn pio_task_sm0(mut sm: StateMachine<'static, PIO0, 0>) {
41 sm.set_enable(true); 39 sm.set_enable(true);
42 40
43 let mut v = 0x0f0caffa; 41 let mut v = 0x0f0caffa;
@@ -48,26 +46,23 @@ async fn pio_task_sm0(mut sm: PioStateMachine<'static, PIO0, 0>) {
48 } 46 }
49} 47}
50 48
51fn setup_pio_task_sm1(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachine<PIO0, 1>) { 49fn setup_pio_task_sm1<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 1>) {
52 // Setupm sm1 50 // Setupm sm1
53 51
54 // Read 0b10101 repeatedly until ISR is full 52 // Read 0b10101 repeatedly until ISR is full
55 let prg = pio_proc::pio_asm!(".origin 8", "set x, 0x15", ".wrap_target", "in x, 5 [31]", ".wrap",); 53 let prg = pio_proc::pio_asm!(".origin 8", "set x, 0x15", ".wrap_target", "in x, 5 [31]", ".wrap",);
56 54
57 let relocated = RelocatedProgram::new(&prg.program); 55 let relocated = RelocatedProgram::new(&prg.program);
58 pio.write_instr(relocated.origin() as usize, relocated.code()); 56 let mut cfg = Config::default();
59 pio_instr_util::exec_jmp(sm, relocated.origin()); 57 cfg.use_program(&pio.load_program(&relocated), &[]);
60 sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32); 58 cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed();
61 sm.set_set_range(0, 0); 59 cfg.shift_in.auto_fill = true;
62 let pio::Wrap { source, target } = relocated.wrap(); 60 cfg.shift_in.direction = ShiftDirection::Right;
63 sm.set_wrap(source, target); 61 sm.set_config(&cfg);
64
65 sm.set_autopush(true);
66 sm.set_in_shift_dir(ShiftDirection::Right);
67} 62}
68 63
69#[embassy_executor::task] 64#[embassy_executor::task]
70async fn pio_task_sm1(mut sm: PioStateMachine<'static, PIO0, 1>) { 65async fn pio_task_sm1(mut sm: StateMachine<'static, PIO0, 1>) {
71 sm.set_enable(true); 66 sm.set_enable(true);
72 loop { 67 loop {
73 let rx = sm.rx().wait_pull().await; 68 let rx = sm.rx().wait_pull().await;
@@ -75,7 +70,7 @@ async fn pio_task_sm1(mut sm: PioStateMachine<'static, PIO0, 1>) {
75 } 70 }
76} 71}
77 72
78fn setup_pio_task_sm2(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachine<PIO0, 2>) { 73fn setup_pio_task_sm2<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 2>) {
79 // Setup sm2 74 // Setup sm2
80 75
81 // Repeatedly trigger IRQ 3 76 // Repeatedly trigger IRQ 3
@@ -89,17 +84,14 @@ fn setup_pio_task_sm2(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachine<PIO0,
89 ".wrap", 84 ".wrap",
90 ); 85 );
91 let relocated = RelocatedProgram::new(&prg.program); 86 let relocated = RelocatedProgram::new(&prg.program);
92 pio.write_instr(relocated.origin() as usize, relocated.code()); 87 let mut cfg = Config::default();
93 88 cfg.use_program(&pio.load_program(&relocated), &[]);
94 let pio::Wrap { source, target } = relocated.wrap(); 89 cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed();
95 sm.set_wrap(source, target); 90 sm.set_config(&cfg);
96
97 pio_instr_util::exec_jmp(sm, relocated.origin());
98 sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32);
99} 91}
100 92
101#[embassy_executor::task] 93#[embassy_executor::task]
102async fn pio_task_sm2(mut irq: PioIrq<'static, PIO0, 3>, mut sm: PioStateMachine<'static, PIO0, 2>) { 94async fn pio_task_sm2(mut irq: Irq<'static, PIO0, 3>, mut sm: StateMachine<'static, PIO0, 2>) {
103 sm.set_enable(true); 95 sm.set_enable(true);
104 loop { 96 loop {
105 irq.wait().await; 97 irq.wait().await;
diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs
index c664482e5..7f85288bf 100644
--- a/examples/rp/src/bin/pio_dma.rs
+++ b/examples/rp/src/bin/pio_dma.rs
@@ -2,11 +2,14 @@
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4use defmt::info; 4use defmt::info;
5use embassy_embedded_hal::SetConfig;
5use embassy_executor::Spawner; 6use embassy_executor::Spawner;
6use embassy_futures::join::join; 7use embassy_futures::join::join;
7use embassy_rp::pio::{Pio, ShiftDirection}; 8use embassy_rp::pio::{Config, Pio, ShiftConfig, ShiftDirection};
8use embassy_rp::relocate::RelocatedProgram; 9use embassy_rp::relocate::RelocatedProgram;
9use embassy_rp::{pio_instr_util, Peripheral}; 10use embassy_rp::Peripheral;
11use fixed::traits::ToFixed;
12use fixed_macro::types::U56F8;
10use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
11 14
12fn swap_nibbles(v: u32) -> u32 { 15fn swap_nibbles(v: u32) -> u32 {
@@ -38,18 +41,21 @@ async fn main(_spawner: Spawner) {
38 ); 41 );
39 42
40 let relocated = RelocatedProgram::new(&prg.program); 43 let relocated = RelocatedProgram::new(&prg.program);
41 common.write_instr(relocated.origin() as usize, relocated.code()); 44 let mut cfg = Config::default();
42 pio_instr_util::exec_jmp(&mut sm, relocated.origin()); 45 cfg.use_program(&common.load_program(&relocated), &[]);
43 sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32); 46 cfg.clock_divider = (U56F8!(125_000_000) / U56F8!(10_000)).to_fixed();
44 let pio::Wrap { source, target } = relocated.wrap(); 47 cfg.shift_in = ShiftConfig {
45 sm.set_wrap(source, target); 48 auto_fill: true,
46 sm.set_autopull(true); 49 threshold: 32,
47 sm.set_autopush(true); 50 direction: ShiftDirection::Left,
48 sm.set_pull_threshold(32); 51 };
49 sm.set_push_threshold(32); 52 cfg.shift_out = ShiftConfig {
50 sm.set_out_shift_dir(ShiftDirection::Right); 53 auto_fill: true,
51 sm.set_in_shift_dir(ShiftDirection::Left); 54 threshold: 32,
55 direction: ShiftDirection::Right,
56 };
52 57
58 sm.set_config(&cfg);
53 sm.set_enable(true); 59 sm.set_enable(true);
54 60
55 let mut dma_out_ref = p.DMA_CH0.into_ref(); 61 let mut dma_out_ref = p.DMA_CH0.into_ref();
diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs
index f76d334e7..088fd5649 100644
--- a/examples/rp/src/bin/pio_hd44780.rs
+++ b/examples/rp/src/bin/pio_hd44780.rs
@@ -4,11 +4,12 @@
4 4
5use core::fmt::Write; 5use core::fmt::Write;
6 6
7use embassy_embedded_hal::SetConfig;
7use embassy_executor::Spawner; 8use embassy_executor::Spawner;
8use embassy_rp::dma::{AnyChannel, Channel}; 9use embassy_rp::dma::{AnyChannel, Channel};
9use embassy_rp::peripherals::PIO0; 10use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::{FifoJoin, Pio, PioPin, PioStateMachine, ShiftDirection}; 11use embassy_rp::pio::{Config, Direction, FifoJoin, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine};
11use embassy_rp::pwm::{Config, Pwm}; 12use embassy_rp::pwm::{self, Pwm};
12use embassy_rp::relocate::RelocatedProgram; 13use embassy_rp::relocate::RelocatedProgram;
13use embassy_rp::{into_ref, Peripheral, PeripheralRef}; 14use embassy_rp::{into_ref, Peripheral, PeripheralRef};
14use embassy_time::{Duration, Instant, Timer}; 15use embassy_time::{Duration, Instant, Timer};
@@ -29,7 +30,7 @@ async fn main(_spawner: Spawner) {
29 let p = embassy_rp::init(Default::default()); 30 let p = embassy_rp::init(Default::default());
30 31
31 let _pwm = Pwm::new_output_b(p.PWM_CH7, p.PIN_15, { 32 let _pwm = Pwm::new_output_b(p.PWM_CH7, p.PIN_15, {
32 let mut c = Config::default(); 33 let mut c = pwm::Config::default();
33 c.divider = 125.into(); 34 c.divider = 125.into();
34 c.top = 100; 35 c.top = 100;
35 c.compare_b = 50; 36 c.compare_b = 50;
@@ -64,7 +65,7 @@ async fn main(_spawner: Spawner) {
64 65
65pub struct HD44780<'l> { 66pub struct HD44780<'l> {
66 dma: PeripheralRef<'l, AnyChannel>, 67 dma: PeripheralRef<'l, AnyChannel>,
67 sm: PioStateMachine<'l, PIO0, 0>, 68 sm: StateMachine<'l, PIO0, 0>,
68 69
69 buf: [u8; 40], 70 buf: [u8; 40],
70} 71}
@@ -83,7 +84,6 @@ impl<'l> HD44780<'l> {
83 ) -> HD44780<'l> { 84 ) -> HD44780<'l> {
84 into_ref!(dma); 85 into_ref!(dma);
85 86
86 let db7pin = db7.pin();
87 let Pio { 87 let Pio {
88 mut common, 88 mut common,
89 mut irq0, 89 mut irq0,
@@ -95,6 +95,7 @@ impl<'l> HD44780<'l> {
95 let prg = pio_proc::pio_asm!( 95 let prg = pio_proc::pio_asm!(
96 r#" 96 r#"
97 .side_set 1 opt 97 .side_set 1 opt
98 .origin 20
98 99
99 loop: 100 loop:
100 out x, 24 101 out x, 24
@@ -115,27 +116,20 @@ impl<'l> HD44780<'l> {
115 let db6 = common.make_pio_pin(db6); 116 let db6 = common.make_pio_pin(db6);
116 let db7 = common.make_pio_pin(db7); 117 let db7 = common.make_pio_pin(db7);
117 118
118 sm0.set_set_pins(&[&rs, &rw]); 119 sm0.set_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]);
119 embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b11);
120 sm0.set_set_pins(&[&e]);
121 embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b1);
122 sm0.set_set_pins(&[&db4, &db5, &db6, &db7]);
123 embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b11111);
124 120
125 let relocated = RelocatedProgram::new(&prg.program); 121 let relocated = RelocatedProgram::new(&prg.program);
126 common.write_instr(relocated.origin() as usize, relocated.code()); 122 let mut cfg = Config::default();
127 embassy_rp::pio_instr_util::exec_jmp(&mut sm0, relocated.origin()); 123 cfg.use_program(&common.load_program(&relocated), &[&e]);
128 sm0.set_clkdiv(125 * 256); 124 cfg.clock_divider = 125u8.into();
129 let pio::Wrap { source, target } = relocated.wrap(); 125 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
130 sm0.set_wrap(source, target); 126 cfg.shift_out = ShiftConfig {
131 sm0.set_side_enable(true); 127 auto_fill: true,
132 sm0.set_out_pins(&[&db4, &db5, &db6, &db7]); 128 direction: ShiftDirection::Left,
133 sm0.set_sideset_base_pin(&e); 129 threshold: 32,
134 sm0.set_sideset_count(2); 130 };
135 sm0.set_out_shift_dir(ShiftDirection::Left); 131 cfg.fifo_join = FifoJoin::TxOnly;
136 sm0.set_fifo_join(FifoJoin::TxOnly); 132 sm0.set_config(&cfg);
137 sm0.set_autopull(true);
138 sm0.set_pull_threshold(32);
139 133
140 sm0.set_enable(true); 134 sm0.set_enable(true);
141 // init to 8 bit thrice 135 // init to 8 bit thrice
@@ -155,7 +149,7 @@ impl<'l> HD44780<'l> {
155 // many side sets are only there to free up a delay bit! 149 // many side sets are only there to free up a delay bit!
156 let prg = pio_proc::pio_asm!( 150 let prg = pio_proc::pio_asm!(
157 r#" 151 r#"
158 .origin 7 152 .origin 27
159 .side_set 1 153 .side_set 1
160 154
161 .wrap_target 155 .wrap_target
@@ -199,19 +193,15 @@ impl<'l> HD44780<'l> {
199 ); 193 );
200 194
201 let relocated = RelocatedProgram::new(&prg.program); 195 let relocated = RelocatedProgram::new(&prg.program);
202 common.write_instr(relocated.origin() as usize, relocated.code()); 196 let mut cfg = Config::default();
203 embassy_rp::pio_instr_util::exec_jmp(&mut sm0, relocated.origin()); 197 cfg.use_program(&common.load_program(&relocated), &[&e]);
204 let pio::Wrap { source, target } = relocated.wrap(); 198 cfg.clock_divider = 8u8.into(); // ~64ns/insn
205 sm0.set_clkdiv(8 * 256); // ~64ns/insn 199 cfg.set_jmp_pin(&db7);
206 sm0.set_side_enable(false); 200 cfg.set_set_pins(&[&rs, &rw]);
207 sm0.set_jmp_pin(db7pin); 201 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
208 sm0.set_wrap(source, target); 202 cfg.shift_out.direction = ShiftDirection::Left;
209 sm0.set_set_pins(&[&rs, &rw]); 203 cfg.fifo_join = FifoJoin::TxOnly;
210 sm0.set_out_pins(&[&db4, &db5, &db6, &db7]); 204 sm0.set_config(&cfg);
211 sm0.set_sideset_base_pin(&e);
212 sm0.set_sideset_count(1);
213 sm0.set_out_shift_dir(ShiftDirection::Left);
214 sm0.set_fifo_join(FifoJoin::TxOnly);
215 205
216 sm0.set_enable(true); 206 sm0.set_enable(true);
217 207
diff --git a/examples/rp/src/bin/ws2812-pio.rs b/examples/rp/src/bin/ws2812-pio.rs
index c9c701a70..d7c4742d8 100644
--- a/examples/rp/src/bin/ws2812-pio.rs
+++ b/examples/rp/src/bin/ws2812-pio.rs
@@ -3,19 +3,20 @@
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use defmt::*; 5use defmt::*;
6use embassy_embedded_hal::SetConfig;
6use embassy_executor::Spawner; 7use embassy_executor::Spawner;
7use embassy_rp::pio::{FifoJoin, Pio, PioCommon, PioInstance, PioPin, PioStateMachine, ShiftDirection}; 8use embassy_rp::pio::{Common, Config, FifoJoin, Instance, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine};
8use embassy_rp::pio_instr_util;
9use embassy_rp::relocate::RelocatedProgram; 9use embassy_rp::relocate::RelocatedProgram;
10use embassy_time::{Duration, Timer}; 10use embassy_time::{Duration, Timer};
11use fixed_macro::fixed;
11use smart_leds::RGB8; 12use smart_leds::RGB8;
12use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
13pub struct Ws2812<'d, P: PioInstance, const S: usize> { 14pub struct Ws2812<'d, P: Instance, const S: usize> {
14 sm: PioStateMachine<'d, P, S>, 15 sm: StateMachine<'d, P, S>,
15} 16}
16 17
17impl<'d, P: PioInstance, const S: usize> Ws2812<'d, P, S> { 18impl<'d, P: Instance, const S: usize> Ws2812<'d, P, S> {
18 pub fn new(mut pio: PioCommon<'d, P>, mut sm: PioStateMachine<'d, P, S>, pin: impl PioPin) -> Self { 19 pub fn new(mut pio: Common<'d, P>, mut sm: StateMachine<'d, P, S>, pin: impl PioPin) -> Self {
19 // Setup sm0 20 // Setup sm0
20 21
21 // prepare the PIO program 22 // prepare the PIO program
@@ -44,41 +45,30 @@ impl<'d, P: PioInstance, const S: usize> Ws2812<'d, P, S> {
44 a.bind(&mut wrap_source); 45 a.bind(&mut wrap_source);
45 46
46 let prg = a.assemble_with_wrap(wrap_source, wrap_target); 47 let prg = a.assemble_with_wrap(wrap_source, wrap_target);
47 48 let mut cfg = Config::default();
48 let relocated = RelocatedProgram::new(&prg);
49 pio.write_instr(relocated.origin() as usize, relocated.code());
50 pio_instr_util::exec_jmp(&mut sm, relocated.origin());
51 49
52 // Pin config 50 // Pin config
53 let out_pin = pio.make_pio_pin(pin); 51 let out_pin = pio.make_pio_pin(pin);
54 sm.set_set_pins(&[&out_pin]);
55 sm.set_sideset_base_pin(&out_pin);
56 sm.set_sideset_count(1);
57 52
58 // Clock config 53 let relocated = RelocatedProgram::new(&prg);
59 // TODO CLOCK_FREQ should come from embassy_rp 54 cfg.use_program(&pio.load_program(&relocated), &[&out_pin]);
60 const CLOCK_FREQ: u32 = 125_000_000;
61 const WS2812_FREQ: u32 = 800_000;
62
63 let bit_freq = WS2812_FREQ * CYCLES_PER_BIT;
64 let mut int = CLOCK_FREQ / bit_freq;
65 let rem = CLOCK_FREQ - (int * bit_freq);
66 let frac = (rem * 256) / bit_freq;
67 // 65536.0 is represented as 0 in the pio's clock divider
68 if int == 65536 {
69 int = 0;
70 }
71 55
72 sm.set_clkdiv((int << 8) | frac); 56 // Clock config, measured in kHz to avoid overflows
73 let pio::Wrap { source, target } = relocated.wrap(); 57 // TODO CLOCK_FREQ should come from embassy_rp
74 sm.set_wrap(source, target); 58 let clock_freq = fixed!(125_000: U24F8);
59 let ws2812_freq = fixed!(800: U24F8);
60 let bit_freq = ws2812_freq * CYCLES_PER_BIT;
61 cfg.clock_divider = clock_freq / bit_freq;
75 62
76 // FIFO config 63 // FIFO config
77 sm.set_autopull(true); 64 cfg.fifo_join = FifoJoin::TxOnly;
78 sm.set_fifo_join(FifoJoin::TxOnly); 65 cfg.shift_out = ShiftConfig {
79 sm.set_pull_threshold(24); 66 auto_fill: true,
80 sm.set_out_shift_dir(ShiftDirection::Left); 67 threshold: 24,
81 68 direction: ShiftDirection::Left,
69 };
70
71 sm.set_config(&cfg);
82 sm.set_enable(true); 72 sm.set_enable(true);
83 73
84 Self { sm } 74 Self { sm }