aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 }