aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-rp/Cargo.toml8
-rw-r--r--embassy-rp/src/gpio.rs42
-rw-r--r--embassy-rp/src/lib.rs9
-rw-r--r--embassy-rp/src/pio.rs1250
-rw-r--r--embassy-rp/src/pio_instr_util.rs90
-rw-r--r--examples/rp/Cargo.toml7
-rw-r--r--examples/rp/src/bin/pio_async.rs105
-rw-r--r--examples/rp/src/bin/pio_dma.rs67
8 files changed, 1576 insertions, 2 deletions
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index 284d458c6..751875710 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -26,6 +26,7 @@ time-driver = []
26rom-func-cache = [] 26rom-func-cache = []
27intrinsics = [] 27intrinsics = []
28rom-v2-intrinsics = [] 28rom-v2-intrinsics = []
29pio = ["dep:pio", "dep:pio-proc"]
29 30
30# Enable nightly-only features 31# Enable nightly-only features
31nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb-driver", "dep:embedded-io"] 32nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb-driver", "dep:embedded-io"]
@@ -64,3 +65,10 @@ embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["un
64embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} 65embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true}
65embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true} 66embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true}
66embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true} 67embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true}
68
69paste = "1.0"
70pio-proc = {version= "0.2", optional = true}
71pio = {version= "0.2", optional = true}
72
73[patch.crates-io]
74pio = {git = "https://github.com/rp-rs/pio-rs.git"} \ No newline at end of file
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index 930de2068..315cd2aca 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -48,6 +48,21 @@ pub enum Pull {
48 Down, 48 Down,
49} 49}
50 50
51/// Drive strength of an output
52#[derive(Debug, Eq, PartialEq)]
53pub enum Drive {
54 _2mA,
55 _4mA,
56 _8mA,
57 _12mA,
58}
59/// Slew rate of an output
60#[derive(Debug, Eq, PartialEq)]
61pub enum SlewRate {
62 Fast,
63 Slow,
64}
65
51/// A GPIO bank with up to 32 pins. 66/// A GPIO bank with up to 32 pins.
52#[derive(Debug, Eq, PartialEq)] 67#[derive(Debug, Eq, PartialEq)]
53pub enum Bank { 68pub enum Bank {
@@ -459,7 +474,7 @@ impl<'d, T: Pin> Flex<'d, T> {
459 #[inline] 474 #[inline]
460 pub fn set_pull(&mut self, pull: Pull) { 475 pub fn set_pull(&mut self, pull: Pull) {
461 unsafe { 476 unsafe {
462 self.pin.pad_ctrl().write(|w| { 477 self.pin.pad_ctrl().modify(|w| {
463 w.set_ie(true); 478 w.set_ie(true);
464 match pull { 479 match pull {
465 Pull::Up => w.set_pue(true), 480 Pull::Up => w.set_pue(true),
@@ -470,6 +485,31 @@ impl<'d, T: Pin> Flex<'d, T> {
470 } 485 }
471 } 486 }
472 487
488 /// Set the pin's drive strength.
489 #[inline]
490 pub fn set_drive_strength(&mut self, strength: Drive) {
491 unsafe {
492 self.pin.pad_ctrl().modify(|w| {
493 w.set_drive(match strength {
494 Drive::_2mA => pac::pads::vals::Drive::_2MA,
495 Drive::_4mA => pac::pads::vals::Drive::_4MA,
496 Drive::_8mA => pac::pads::vals::Drive::_8MA,
497 Drive::_12mA => pac::pads::vals::Drive::_12MA,
498 });
499 });
500 }
501 }
502
503 // Set the pin's slew rate.
504 #[inline]
505 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
506 unsafe {
507 self.pin.pad_ctrl().modify(|w| {
508 w.set_slewfast(slew_rate == SlewRate::Fast);
509 });
510 }
511 }
512
473 /// Put the pin into input mode. 513 /// Put the pin into input mode.
474 /// 514 ///
475 /// The pull setting is left unchanged. 515 /// The pull setting is left unchanged.
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index d21b5f7b0..67eb29d5e 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -12,6 +12,12 @@ pub mod dma;
12pub mod gpio; 12pub mod gpio;
13pub mod i2c; 13pub mod i2c;
14pub mod interrupt; 14pub mod interrupt;
15
16#[cfg(feature = "pio")]
17pub mod pio;
18#[cfg(feature = "pio")]
19pub mod pio_instr_util;
20
15pub mod rom_data; 21pub mod rom_data;
16pub mod rtc; 22pub mod rtc;
17pub mod spi; 23pub mod spi;
@@ -102,6 +108,9 @@ embassy_hal_common::peripherals! {
102 FLASH, 108 FLASH,
103 109
104 ADC, 110 ADC,
111
112 PIO0,
113 PIO1,
105} 114}
106 115
107#[link_section = ".boot2"] 116#[link_section = ".boot2"]
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs
new file mode 100644
index 000000000..f049a16e7
--- /dev/null
+++ b/embassy-rp/src/pio.rs
@@ -0,0 +1,1250 @@
1use core::future::Future;
2use core::marker::PhantomData;
3use core::pin::Pin as FuturePin;
4use core::sync::atomic::{compiler_fence, Ordering};
5use core::task::{Context, Poll};
6
7use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
8use embassy_hal_common::PeripheralRef;
9use embassy_sync::waitqueue::AtomicWaker;
10
11use crate::dma::{self, Channel, Transfer};
12use crate::gpio::sealed::Pin as SealedPin;
13use crate::gpio::{Drive, Pin, Pull, SlewRate};
14use crate::pac::dma::vals::{DataSize, TreqSel};
15use crate::{interrupt, pac, peripherals};
16
17const PIOS: [&pac::pio::Pio; 2] = [&pac::PIO0, &pac::PIO1];
18const NEW_AW: AtomicWaker = AtomicWaker::new();
19const PIO_WAKERS_INIT: [AtomicWaker; 4] = [NEW_AW; 4];
20static FIFO_OUT_WAKERS: [[AtomicWaker; 4]; 2] = [PIO_WAKERS_INIT; 2];
21static FIFO_IN_WAKERS: [[AtomicWaker; 4]; 2] = [PIO_WAKERS_INIT; 2];
22static IRQ_WAKERS: [[AtomicWaker; 4]; 2] = [PIO_WAKERS_INIT; 2];
23
24pub enum FifoJoin {
25 /// Both TX and RX fifo is enabled
26 Duplex,
27 /// Rx fifo twice as deep. TX fifo disabled
28 RxOnly,
29 /// Tx fifo twice as deep. RX fifo disabled
30 TxOnly,
31}
32
33#[derive(PartialEq)]
34pub enum ShiftDirection {
35 Right = 1,
36 Left = 0,
37}
38
39const RXNEMPTY_MASK: u32 = 1 << 0;
40const TXNFULL_MASK: u32 = 1 << 4;
41const SMIRQ_MASK: u32 = 1 << 8;
42
43#[interrupt]
44unsafe fn PIO0_IRQ_1() {
45 use crate::pac;
46 let ints = pac::PIO0.irqs(1).ints().read().0;
47 let inte = pac::PIO0.irqs(1).inte();
48 for i in 0..4 {
49 // Check RXNEMPTY
50 if ints & (RXNEMPTY_MASK << i) != 0 {
51 inte.modify(|m| {
52 m.0 &= !(RXNEMPTY_MASK << i);
53 });
54 FIFO_IN_WAKERS[0][i].wake();
55 }
56 // Check IRQ flgs
57 if ints & (SMIRQ_MASK << i) != 0 {
58 inte.modify(|m| {
59 m.0 &= !(SMIRQ_MASK << i);
60 });
61 IRQ_WAKERS[0][i].wake();
62 }
63 }
64}
65
66#[interrupt]
67unsafe fn PIO1_IRQ_1() {
68 use crate::pac;
69 let ints = pac::PIO1.irqs(1).ints().read().0;
70 let inte = pac::PIO1.irqs(1).inte();
71 for i in 0..4 {
72 // Check all RXNEMPTY
73 if ints & (RXNEMPTY_MASK << i) != 0 {
74 inte.modify(|m| {
75 m.0 &= !(RXNEMPTY_MASK << i);
76 });
77 FIFO_IN_WAKERS[1][i].wake();
78 }
79 // Check IRQ flgs
80 if ints & (SMIRQ_MASK << i) != 0 {
81 inte.modify(|m| {
82 m.0 &= !(SMIRQ_MASK << i);
83 });
84 IRQ_WAKERS[1][i].wake();
85 }
86 }
87}
88
89#[interrupt]
90unsafe fn PIO0_IRQ_0() {
91 use crate::pac;
92 let ints = pac::PIO0.irqs(0).ints().read().0;
93 let inte = pac::PIO0.irqs(0).inte();
94 //debug!("!{:04x}",ints);
95 // Check all TXNFULL
96 for i in 0..4 {
97 if ints & (TXNFULL_MASK << i) != 0 {
98 inte.modify(|m| {
99 m.0 &= !(TXNFULL_MASK << i);
100 });
101 FIFO_OUT_WAKERS[0][i].wake();
102 }
103 }
104}
105
106#[interrupt]
107unsafe fn PIO1_IRQ_0() {
108 use crate::pac;
109 let ints = pac::PIO1.irqs(0).ints().read().0;
110 let inte = pac::PIO1.irqs(0).inte();
111 // Check all TXNFULL
112 for i in 0..4 {
113 if ints & (TXNFULL_MASK << i) != 0 {
114 inte.modify(|m| {
115 m.0 &= !(TXNFULL_MASK << i);
116 });
117 FIFO_OUT_WAKERS[1][i].wake();
118 }
119 }
120}
121
122/// Future that waits for TX-FIFO to become writable
123pub struct FifoOutFuture<'a, PIO: PioInstance, SM: PioStateMachine + Unpin> {
124 sm: &'a mut SM,
125 pio: PhantomData<PIO>,
126 value: u32,
127}
128
129impl<'a, PIO: PioInstance, SM: PioStateMachine + Unpin> FifoOutFuture<'a, PIO, SM> {
130 pub fn new(sm: &'a mut SM, value: u32) -> Self {
131 unsafe {
132 critical_section::with(|_| {
133 let irq = PIO::IrqOut::steal();
134 irq.set_priority(interrupt::Priority::P3);
135
136 irq.enable();
137 });
138 }
139 FifoOutFuture {
140 sm,
141 pio: PhantomData::default(),
142 value,
143 }
144 }
145}
146
147impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Future for FifoOutFuture<'d, PIO, SM> {
148 type Output = ();
149 fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
150 //debug!("Poll {},{}", PIO::PIO_NO, SM);
151 let value = self.value;
152 if self.get_mut().sm.try_push_tx(value) {
153 Poll::Ready(())
154 } else {
155 FIFO_OUT_WAKERS[PIO::PIO_NO as usize][SM::Sm::SM_NO as usize].register(cx.waker());
156 unsafe {
157 let irq = PIO::IrqOut::steal();
158 irq.disable();
159 critical_section::with(|_| {
160 PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| {
161 m.0 |= TXNFULL_MASK << SM::Sm::SM_NO;
162 });
163 });
164 irq.enable();
165 }
166 // debug!("Pending");
167 Poll::Pending
168 }
169 }
170}
171
172impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Drop for FifoOutFuture<'d, PIO, SM> {
173 fn drop(&mut self) {
174 unsafe {
175 critical_section::with(|_| {
176 PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| {
177 m.0 &= !(TXNFULL_MASK << SM::Sm::SM_NO);
178 });
179 });
180 }
181 }
182}
183
184/// Future that waits for RX-FIFO to become readable
185pub struct FifoInFuture<'a, PIO: PioInstance, SM: PioStateMachine> {
186 sm: &'a mut SM,
187 pio: PhantomData<PIO>,
188}
189
190impl<'a, PIO: PioInstance, SM: PioStateMachine> FifoInFuture<'a, PIO, SM> {
191 pub fn new(sm: &'a mut SM) -> Self {
192 unsafe {
193 critical_section::with(|_| {
194 let irq = PIO::IrqIn::steal();
195 irq.set_priority(interrupt::Priority::P3);
196
197 irq.enable();
198 });
199 }
200 FifoInFuture {
201 sm,
202 pio: PhantomData::default(),
203 }
204 }
205}
206
207impl<'d, PIO: PioInstance, SM: PioStateMachine> Future for FifoInFuture<'d, PIO, SM> {
208 type Output = u32;
209 fn poll(mut self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
210 //debug!("Poll {},{}", PIO::PIO_NO, SM);
211 if let Some(v) = self.sm.try_pull_rx() {
212 Poll::Ready(v)
213 } else {
214 FIFO_IN_WAKERS[PIO::PIO_NO as usize][SM::Sm::SM_NO as usize].register(cx.waker());
215 unsafe {
216 let irq = PIO::IrqIn::steal();
217 irq.disable();
218 critical_section::with(|_| {
219 PIOS[PIO::PIO_NO as usize].irqs(1).inte().modify(|m| {
220 m.0 |= RXNEMPTY_MASK << SM::Sm::SM_NO;
221 });
222 });
223 irq.enable();
224 }
225 //debug!("Pending");
226 Poll::Pending
227 }
228 }
229}
230
231impl<'d, PIO: PioInstance, SM: PioStateMachine> Drop for FifoInFuture<'d, PIO, SM> {
232 fn drop(&mut self) {
233 unsafe {
234 critical_section::with(|_| {
235 PIOS[PIO::PIO_NO as usize].irqs(1).inte().modify(|m| {
236 m.0 &= !(RXNEMPTY_MASK << SM::Sm::SM_NO);
237 });
238 });
239 }
240 }
241}
242
243/// Future that waits for IRQ
244pub struct IrqFuture<PIO: PioInstance> {
245 pio: PhantomData<PIO>,
246 irq_no: u8,
247}
248
249impl<'a, PIO: PioInstance> IrqFuture<PIO> {
250 pub fn new(irq_no: u8) -> Self {
251 unsafe {
252 critical_section::with(|_| {
253 let irq = PIO::IrqSm::steal();
254 irq.set_priority(interrupt::Priority::P3);
255
256 irq.enable();
257 });
258 }
259 IrqFuture {
260 pio: PhantomData::default(),
261 irq_no,
262 }
263 }
264}
265
266impl<'d, PIO: PioInstance> Future for IrqFuture<PIO> {
267 type Output = ();
268 fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
269 //debug!("Poll {},{}", PIO::PIO_NO, SM);
270
271 // Check if IRQ flag is already set
272 if critical_section::with(|_| unsafe {
273 let irq_flags = PIOS[PIO::PIO_NO as usize].irq();
274 if irq_flags.read().0 & (1 << self.irq_no) != 0 {
275 irq_flags.write(|m| {
276 m.0 = 1 << self.irq_no;
277 });
278 true
279 } else {
280 false
281 }
282 }) {
283 return Poll::Ready(());
284 }
285
286 IRQ_WAKERS[PIO::PIO_NO as usize][self.irq_no as usize].register(cx.waker());
287 unsafe {
288 let irq = PIO::IrqSm::steal();
289 irq.disable();
290 critical_section::with(|_| {
291 PIOS[PIO::PIO_NO as usize].irqs(1).inte().modify(|m| {
292 m.0 |= SMIRQ_MASK << self.irq_no;
293 });
294 });
295 irq.enable();
296 }
297 Poll::Pending
298 }
299}
300
301impl<'d, PIO: PioInstance> Drop for IrqFuture<PIO> {
302 fn drop(&mut self) {
303 unsafe {
304 critical_section::with(|_| {
305 PIOS[PIO::PIO_NO as usize].irqs(1).inte().modify(|m| {
306 m.0 &= !(SMIRQ_MASK << self.irq_no);
307 });
308 });
309 }
310 }
311}
312
313pub struct PioPin<PIO: PioInstance> {
314 pin_bank: u8,
315 pio: PhantomData<PIO>,
316}
317
318impl<PIO: PioInstance> PioPin<PIO> {
319 /// Set the pin's drive strength.
320 #[inline]
321 pub fn set_drive_strength(&mut self, strength: Drive) {
322 unsafe {
323 self.pad_ctrl().modify(|w| {
324 w.set_drive(match strength {
325 Drive::_2mA => pac::pads::vals::Drive::_2MA,
326 Drive::_4mA => pac::pads::vals::Drive::_4MA,
327 Drive::_8mA => pac::pads::vals::Drive::_8MA,
328 Drive::_12mA => pac::pads::vals::Drive::_12MA,
329 });
330 });
331 }
332 }
333
334 // Set the pin's slew rate.
335 #[inline]
336 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
337 unsafe {
338 self.pad_ctrl().modify(|w| {
339 w.set_slewfast(slew_rate == SlewRate::Fast);
340 });
341 }
342 }
343
344 /// Set the pin's pull.
345 #[inline]
346 pub fn set_pull(&mut self, pull: Pull) {
347 unsafe {
348 self.pad_ctrl().modify(|w| match pull {
349 Pull::Up => w.set_pue(true),
350 Pull::Down => w.set_pde(true),
351 Pull::None => {}
352 });
353 }
354 }
355
356 /// Set the pin's pull.
357 #[inline]
358 pub fn set_schmitt(&mut self, enable: bool) {
359 unsafe {
360 self.pad_ctrl().modify(|w| {
361 w.set_schmitt(enable);
362 });
363 }
364 }
365
366 pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) {
367 let mask = 1 << self.pin();
368 unsafe {
369 PIOS[PIO::PIO_NO as usize]
370 .input_sync_bypass()
371 .modify(|w| *w = if bypass { *w & !mask } else { *w | mask });
372 }
373 }
374
375 pub fn pin(&self) -> u8 {
376 self._pin()
377 }
378}
379
380impl<PIO: PioInstance> SealedPin for PioPin<PIO> {
381 fn pin_bank(&self) -> u8 {
382 self.pin_bank
383 }
384}
385
386pub struct PioStateMachineInstance<PIO: PioInstance, SM: SmInstance> {
387 pio: PhantomData<PIO>,
388 sm: PhantomData<SM>,
389}
390
391impl<PIO: PioInstance, SM: SmInstance> PioStateMachine for PioStateMachineInstance<PIO, SM> {
392 type Pio = PIO;
393 type Sm = SM;
394}
395
396pub trait PioStateMachine: Sized + Unpin {
397 type Pio: PioInstance;
398 type Sm: SmInstance;
399 fn pio_no(&self) -> u8 {
400 let _ = self;
401 Self::Pio::PIO_NO
402 }
403
404 fn sm_no(&self) -> u8 {
405 Self::Sm::SM_NO
406 }
407
408 fn restart(&mut self) {
409 let _ = self;
410 unsafe {
411 PIOS[Self::Pio::PIO_NO as usize]
412 .ctrl()
413 .modify(|w| w.set_sm_restart(1u8 << Self::Sm::SM_NO));
414 }
415 }
416 fn set_enable(&mut self, enable: bool) {
417 let _ = self;
418 let mask = 1u8 << Self::Sm::SM_NO;
419 unsafe {
420 PIOS[Self::Pio::PIO_NO as usize]
421 .ctrl()
422 .modify(|w| w.set_sm_enable((w.sm_enable() & !mask) | (if enable { mask } else { 0 })));
423 }
424 }
425
426 fn is_enabled(&self) -> bool {
427 let _ = self;
428 unsafe { PIOS[Self::Pio::PIO_NO as usize].ctrl().read().sm_enable() & (1u8 << Self::Sm::SM_NO) != 0 }
429 }
430
431 fn is_tx_empty(&self) -> bool {
432 let _ = self;
433 unsafe { PIOS[Self::Pio::PIO_NO as usize].fstat().read().txempty() & (1u8 << Self::Sm::SM_NO) != 0 }
434 }
435 fn is_tx_full(&self) -> bool {
436 let _ = self;
437 unsafe { PIOS[Self::Pio::PIO_NO as usize].fstat().read().txfull() & (1u8 << Self::Sm::SM_NO) != 0 }
438 }
439
440 fn is_rx_empty(&self) -> bool {
441 let _ = self;
442 unsafe { PIOS[Self::Pio::PIO_NO as usize].fstat().read().rxempty() & (1u8 << Self::Sm::SM_NO) != 0 }
443 }
444 fn is_rx_full(&self) -> bool {
445 let _ = self;
446 unsafe { PIOS[Self::Pio::PIO_NO as usize].fstat().read().rxfull() & (1u8 << Self::Sm::SM_NO) != 0 }
447 }
448
449 fn tx_level(&self) -> u8 {
450 unsafe {
451 let flevel = PIOS[Self::Pio::PIO_NO as usize].flevel().read().0;
452 (flevel >> (Self::Sm::SM_NO * 8)) as u8 & 0x0f
453 }
454 }
455
456 fn rx_level(&self) -> u8 {
457 unsafe {
458 let flevel = PIOS[Self::Pio::PIO_NO as usize].flevel().read().0;
459 (flevel >> (Self::Sm::SM_NO * 8 + 4)) as u8 & 0x0f
460 }
461 }
462
463 fn push_tx(&mut self, v: u32) {
464 unsafe {
465 PIOS[Self::Pio::PIO_NO as usize]
466 .txf(Self::Sm::SM_NO as usize)
467 .write_value(v);
468 }
469 }
470
471 fn try_push_tx(&mut self, v: u32) -> bool {
472 if self.is_tx_full() {
473 return false;
474 }
475 self.push_tx(v);
476 true
477 }
478
479 fn pull_rx(&mut self) -> u32 {
480 unsafe { PIOS[Self::Pio::PIO_NO as usize].rxf(Self::Sm::SM_NO as usize).read() }
481 }
482
483 fn try_pull_rx(&mut self) -> Option<u32> {
484 if self.is_rx_empty() {
485 return None;
486 }
487 Some(self.pull_rx())
488 }
489
490 fn set_clkdiv(&mut self, div_x_256: u32) {
491 unsafe {
492 PIOS[Self::Pio::PIO_NO as usize]
493 .sm(Self::Sm::SM_NO as usize)
494 .clkdiv()
495 .write(|w| w.0 = div_x_256 << 8);
496 }
497 }
498
499 fn get_clkdiv(&self) -> u32 {
500 unsafe {
501 PIOS[Self::Pio::PIO_NO as usize]
502 .sm(Self::Sm::SM_NO as usize)
503 .clkdiv()
504 .read()
505 .0
506 >> 8
507 }
508 }
509
510 fn clkdiv_restart(&mut self) {
511 let _ = self;
512 unsafe {
513 PIOS[Self::Pio::PIO_NO as usize]
514 .ctrl()
515 .modify(|w| w.set_clkdiv_restart(1u8 << Self::Sm::SM_NO));
516 }
517 }
518
519 fn set_side_enable(&self, enable: bool) {
520 unsafe {
521 PIOS[Self::Pio::PIO_NO as usize]
522 .sm(Self::Sm::SM_NO as usize)
523 .execctrl()
524 .modify(|w| w.set_side_en(enable));
525 }
526 }
527
528 fn is_side_enabled(&self) -> bool {
529 unsafe {
530 PIOS[Self::Pio::PIO_NO as usize]
531 .sm(Self::Sm::SM_NO as usize)
532 .execctrl()
533 .read()
534 .side_en()
535 }
536 }
537
538 fn set_side_pindir(&mut self, pindir: bool) {
539 unsafe {
540 PIOS[Self::Pio::PIO_NO as usize]
541 .sm(Self::Sm::SM_NO as usize)
542 .execctrl()
543 .modify(|w| w.set_side_pindir(pindir));
544 }
545 }
546
547 fn is_side_pindir(&self) -> bool {
548 unsafe {
549 PIOS[Self::Pio::PIO_NO as usize]
550 .sm(Self::Sm::SM_NO as usize)
551 .execctrl()
552 .read()
553 .side_pindir()
554 }
555 }
556
557 fn set_jmp_pin(&mut self, pin: u8) {
558 unsafe {
559 PIOS[Self::Pio::PIO_NO as usize]
560 .sm(Self::Sm::SM_NO as usize)
561 .execctrl()
562 .modify(|w| w.set_jmp_pin(pin));
563 }
564 }
565
566 fn get_jmp_pin(&mut self) -> u8 {
567 unsafe {
568 PIOS[Self::Pio::PIO_NO as usize]
569 .sm(Self::Sm::SM_NO as usize)
570 .execctrl()
571 .read()
572 .jmp_pin()
573 }
574 }
575
576 fn set_wrap(&self, source: u8, target: u8) {
577 unsafe {
578 PIOS[Self::Pio::PIO_NO as usize]
579 .sm(Self::Sm::SM_NO as usize)
580 .execctrl()
581 .modify(|w| {
582 w.set_wrap_top(source);
583 w.set_wrap_bottom(target)
584 });
585 }
586 }
587
588 /// Get wrapping addresses. Returns (source, target).
589 fn get_wrap(&self) -> (u8, u8) {
590 unsafe {
591 let r = PIOS[Self::Pio::PIO_NO as usize]
592 .sm(Self::Sm::SM_NO as usize)
593 .execctrl()
594 .read();
595 (r.wrap_top(), r.wrap_bottom())
596 }
597 }
598
599 fn set_fifo_join(&mut self, join: FifoJoin) {
600 let (rx, tx) = match join {
601 FifoJoin::Duplex => (false, false),
602 FifoJoin::RxOnly => (true, false),
603 FifoJoin::TxOnly => (false, true),
604 };
605 unsafe {
606 PIOS[Self::Pio::PIO_NO as usize]
607 .sm(Self::Sm::SM_NO as usize)
608 .shiftctrl()
609 .modify(|w| {
610 w.set_fjoin_rx(rx);
611 w.set_fjoin_tx(tx)
612 });
613 }
614 }
615 fn get_fifo_join(&self) -> FifoJoin {
616 unsafe {
617 let r = PIOS[Self::Pio::PIO_NO as usize]
618 .sm(Self::Sm::SM_NO as usize)
619 .shiftctrl()
620 .read();
621 // Ignores the invalid state when both bits are set
622 if r.fjoin_rx() {
623 FifoJoin::RxOnly
624 } else if r.fjoin_tx() {
625 FifoJoin::TxOnly
626 } else {
627 FifoJoin::Duplex
628 }
629 }
630 }
631
632 fn clear_fifos(&mut self) {
633 // Toggle FJOIN_RX to flush FIFOs
634 unsafe {
635 let shiftctrl = PIOS[Self::Pio::PIO_NO as usize]
636 .sm(Self::Sm::SM_NO as usize)
637 .shiftctrl();
638 shiftctrl.modify(|w| {
639 w.set_fjoin_rx(!w.fjoin_rx());
640 });
641 shiftctrl.modify(|w| {
642 w.set_fjoin_rx(!w.fjoin_rx());
643 });
644 }
645 }
646
647 fn set_pull_threshold(&mut self, threshold: u8) {
648 unsafe {
649 PIOS[Self::Pio::PIO_NO as usize]
650 .sm(Self::Sm::SM_NO as usize)
651 .shiftctrl()
652 .modify(|w| w.set_pull_thresh(threshold));
653 }
654 }
655
656 fn get_pull_threshold(&self) -> u8 {
657 unsafe {
658 let r = PIOS[Self::Pio::PIO_NO as usize]
659 .sm(Self::Sm::SM_NO as usize)
660 .shiftctrl()
661 .read();
662 r.pull_thresh()
663 }
664 }
665 fn set_push_threshold(&mut self, threshold: u8) {
666 unsafe {
667 PIOS[Self::Pio::PIO_NO as usize]
668 .sm(Self::Sm::SM_NO as usize)
669 .shiftctrl()
670 .modify(|w| w.set_push_thresh(threshold));
671 }
672 }
673
674 fn get_push_threshold(&self) -> u8 {
675 unsafe {
676 let r = PIOS[Self::Pio::PIO_NO as usize]
677 .sm(Self::Sm::SM_NO as usize)
678 .shiftctrl()
679 .read();
680 r.push_thresh()
681 }
682 }
683
684 fn set_out_shift_dir(&mut self, dir: ShiftDirection) {
685 unsafe {
686 PIOS[Self::Pio::PIO_NO as usize]
687 .sm(Self::Sm::SM_NO as usize)
688 .shiftctrl()
689 .modify(|w| w.set_out_shiftdir(dir == ShiftDirection::Right));
690 }
691 }
692 fn get_out_shiftdir(&self) -> ShiftDirection {
693 unsafe {
694 if PIOS[Self::Pio::PIO_NO as usize]
695 .sm(Self::Sm::SM_NO as usize)
696 .shiftctrl()
697 .read()
698 .out_shiftdir()
699 {
700 ShiftDirection::Right
701 } else {
702 ShiftDirection::Left
703 }
704 }
705 }
706
707 fn set_in_shift_dir(&mut self, dir: ShiftDirection) {
708 unsafe {
709 PIOS[Self::Pio::PIO_NO as usize]
710 .sm(Self::Sm::SM_NO as usize)
711 .shiftctrl()
712 .modify(|w| w.set_in_shiftdir(dir == ShiftDirection::Right));
713 }
714 }
715 fn get_in_shiftdir(&self) -> ShiftDirection {
716 unsafe {
717 if PIOS[Self::Pio::PIO_NO as usize]
718 .sm(Self::Sm::SM_NO as usize)
719 .shiftctrl()
720 .read()
721 .in_shiftdir()
722 {
723 ShiftDirection::Right
724 } else {
725 ShiftDirection::Left
726 }
727 }
728 }
729
730 fn set_autopull(&mut self, auto: bool) {
731 unsafe {
732 PIOS[Self::Pio::PIO_NO as usize]
733 .sm(Self::Sm::SM_NO as usize)
734 .shiftctrl()
735 .modify(|w| w.set_autopull(auto));
736 }
737 }
738
739 fn is_autopull(&self) -> bool {
740 unsafe {
741 PIOS[Self::Pio::PIO_NO as usize]
742 .sm(Self::Sm::SM_NO as usize)
743 .shiftctrl()
744 .read()
745 .autopull()
746 }
747 }
748
749 fn set_autopush(&mut self, auto: bool) {
750 unsafe {
751 PIOS[Self::Pio::PIO_NO as usize]
752 .sm(Self::Sm::SM_NO as usize)
753 .shiftctrl()
754 .modify(|w| w.set_autopush(auto));
755 }
756 }
757
758 fn is_autopush(&self) -> bool {
759 unsafe {
760 PIOS[Self::Pio::PIO_NO as usize]
761 .sm(Self::Sm::SM_NO as usize)
762 .shiftctrl()
763 .read()
764 .autopush()
765 }
766 }
767
768 fn get_addr(&self) -> u8 {
769 unsafe {
770 let r = PIOS[Self::Pio::PIO_NO as usize]
771 .sm(Self::Sm::SM_NO as usize)
772 .addr()
773 .read();
774 r.addr()
775 }
776 }
777 fn set_sideset_count(&mut self, count: u8) {
778 unsafe {
779 PIOS[Self::Pio::PIO_NO as usize]
780 .sm(Self::Sm::SM_NO as usize)
781 .pinctrl()
782 .modify(|w| w.set_sideset_count(count));
783 }
784 }
785
786 fn get_sideset_count(&self) -> u8 {
787 unsafe {
788 let r = PIOS[Self::Pio::PIO_NO as usize]
789 .sm(Self::Sm::SM_NO as usize)
790 .pinctrl()
791 .read();
792 r.sideset_count()
793 }
794 }
795
796 fn make_pio_pin(&self, pin: impl Pin) -> PioPin<Self::Pio> {
797 unsafe {
798 pin.io().ctrl().write(|w| {
799 w.set_funcsel(
800 if Self::Pio::PIO_NO == 1 {
801 pac::io::vals::Gpio0ctrlFuncsel::PIO1_0
802 } else {
803 // PIO == 0
804 pac::io::vals::Gpio0ctrlFuncsel::PIO0_0
805 }
806 .0,
807 );
808 });
809 }
810 PioPin {
811 pin_bank: pin.pin_bank(),
812 pio: PhantomData::default(),
813 }
814 }
815
816 fn set_sideset_base_pin(&mut self, base_pin: &PioPin<Self::Pio>) {
817 unsafe {
818 PIOS[Self::Pio::PIO_NO as usize]
819 .sm(Self::Sm::SM_NO as usize)
820 .pinctrl()
821 .modify(|w| w.set_sideset_base(base_pin.pin()));
822 }
823 }
824
825 fn get_sideset_base(&self) -> u8 {
826 unsafe {
827 let r = PIOS[Self::Pio::PIO_NO as usize]
828 .sm(Self::Sm::SM_NO as usize)
829 .pinctrl()
830 .read();
831 r.sideset_base()
832 }
833 }
834
835 /// Set the range of out pins affected by a set instruction.
836 fn set_set_range(&mut self, base: u8, count: u8) {
837 assert!(base + count < 32);
838 unsafe {
839 PIOS[Self::Pio::PIO_NO as usize]
840 .sm(Self::Sm::SM_NO as usize)
841 .pinctrl()
842 .modify(|w| {
843 w.set_set_base(base);
844 w.set_set_count(count)
845 });
846 }
847 }
848
849 /// Get the range of out pins affected by a set instruction. Returns (base, count).
850 fn get_set_range(&self) -> (u8, u8) {
851 unsafe {
852 let r = PIOS[Self::Pio::PIO_NO as usize]
853 .sm(Self::Sm::SM_NO as usize)
854 .pinctrl()
855 .read();
856 (r.set_base(), r.set_count())
857 }
858 }
859
860 fn set_in_base_pin(&mut self, base: &PioPin<Self::Pio>) {
861 unsafe {
862 PIOS[Self::Pio::PIO_NO as usize]
863 .sm(Self::Sm::SM_NO as usize)
864 .pinctrl()
865 .modify(|w| w.set_in_base(base.pin()));
866 }
867 }
868
869 fn get_in_base(&self) -> u8 {
870 unsafe {
871 let r = PIOS[Self::Pio::PIO_NO as usize]
872 .sm(Self::Sm::SM_NO as usize)
873 .pinctrl()
874 .read();
875 r.in_base()
876 }
877 }
878
879 fn set_out_range(&mut self, base: u8, count: u8) {
880 assert!(base + count < 32);
881 unsafe {
882 PIOS[Self::Pio::PIO_NO as usize]
883 .sm(Self::Sm::SM_NO as usize)
884 .pinctrl()
885 .modify(|w| {
886 w.set_out_base(base);
887 w.set_out_count(count)
888 });
889 }
890 }
891
892 /// Get the range of out pins affected by a set instruction. Returns (base, count).
893 fn get_out_range(&self) -> (u8, u8) {
894 unsafe {
895 let r = PIOS[Self::Pio::PIO_NO as usize]
896 .sm(Self::Sm::SM_NO as usize)
897 .pinctrl()
898 .read();
899 (r.out_base(), r.out_count())
900 }
901 }
902
903 fn set_out_pins<'a, 'b: 'a>(&'a mut self, pins: &'b [&PioPin<Self::Pio>]) {
904 let count = pins.len();
905 assert!(count >= 1);
906 let start = pins[0].pin() as usize;
907 assert!(start + pins.len() <= 32);
908 for i in 0..count {
909 assert!(pins[i].pin() as usize == start + i, "Pins must be sequential");
910 }
911 self.set_out_range(start as u8, count as u8);
912 }
913
914 fn set_set_pins<'a, 'b: 'a>(&'a mut self, pins: &'b [&PioPin<Self::Pio>]) {
915 let count = pins.len();
916 assert!(count >= 1);
917 let start = pins[0].pin() as usize;
918 assert!(start + pins.len() <= 32);
919 for i in 0..count {
920 assert!(pins[i].pin() as usize == start + i, "Pins must be sequential");
921 }
922 self.set_set_range(start as u8, count as u8);
923 }
924
925 fn get_current_instr() -> u32 {
926 unsafe {
927 PIOS[Self::Pio::PIO_NO as usize]
928 .sm(Self::Sm::SM_NO as usize)
929 .instr()
930 .read()
931 .0
932 }
933 }
934
935 fn exec_instr(&mut self, instr: u16) {
936 unsafe {
937 PIOS[Self::Pio::PIO_NO as usize]
938 .sm(Self::Sm::SM_NO as usize)
939 .instr()
940 .write(|w| w.set_instr(instr));
941 }
942 }
943
944 fn write_instr(&mut self, start: usize, instrs: &[u16]) {
945 let _ = self;
946 write_instr(
947 Self::Pio::PIO_NO,
948 start,
949 instrs,
950 MEM_USED_BY_STATEMACHINE | Self::Sm::SM_NO as u32,
951 );
952 }
953
954 fn is_irq_set(&self, irq_no: u8) -> bool {
955 assert!(irq_no < 8);
956 unsafe {
957 let irq_flags = PIOS[Self::Pio::PIO_NO as usize].irq();
958 irq_flags.read().0 & (1 << irq_no) != 0
959 }
960 }
961
962 fn clear_irq(&mut self, irq_no: usize) {
963 assert!(irq_no < 8);
964 unsafe { PIOS[Self::Pio::PIO_NO as usize].irq().write(|w| w.set_irq(1 << irq_no)) }
965 }
966
967 fn wait_push<'a>(&'a mut self, value: u32) -> FifoOutFuture<'a, Self::Pio, Self> {
968 FifoOutFuture::new(self, value)
969 }
970
971 fn wait_pull<'a>(&'a mut self) -> FifoInFuture<'a, Self::Pio, Self> {
972 FifoInFuture::new(self)
973 }
974
975 fn wait_irq(&self, irq_no: u8) -> IrqFuture<Self::Pio> {
976 IrqFuture::new(irq_no)
977 }
978
979 fn has_tx_stalled(&self) -> bool {
980 unsafe {
981 let fdebug = PIOS[Self::Pio::PIO_NO as usize].fdebug();
982 let ret = fdebug.read().txstall() & (1 << Self::Sm::SM_NO) != 0;
983 fdebug.write(|w| w.set_txstall(1 << Self::Sm::SM_NO));
984 ret
985 }
986 }
987
988 fn has_tx_overflowed(&self) -> bool {
989 unsafe {
990 let fdebug = PIOS[Self::Pio::PIO_NO as usize].fdebug();
991 let ret = fdebug.read().txover() & (1 << Self::Sm::SM_NO) != 0;
992 fdebug.write(|w| w.set_txover(1 << Self::Sm::SM_NO));
993 ret
994 }
995 }
996
997 fn has_rx_stalled(&self) -> bool {
998 unsafe {
999 let fdebug = PIOS[Self::Pio::PIO_NO as usize].fdebug();
1000 let ret = fdebug.read().rxstall() & (1 << Self::Sm::SM_NO) != 0;
1001 fdebug.write(|w| w.set_rxstall(1 << Self::Sm::SM_NO));
1002 ret
1003 }
1004 }
1005
1006 fn has_rx_underflowed(&self) -> bool {
1007 unsafe {
1008 let fdebug = PIOS[Self::Pio::PIO_NO as usize].fdebug();
1009 let ret = fdebug.read().rxunder() & (1 << Self::Sm::SM_NO) != 0;
1010 fdebug.write(|w| w.set_rxunder(1 << Self::Sm::SM_NO));
1011 ret
1012 }
1013 }
1014
1015 fn dma_push<'a, C: Channel>(&'a self, ch: PeripheralRef<'a, C>, data: &'a [u32]) -> Transfer<'a, C> {
1016 unsafe {
1017 dma::init();
1018 let pio_no = Self::Pio::PIO_NO;
1019 let sm_no = Self::Sm::SM_NO;
1020 let p = ch.regs();
1021 p.read_addr().write_value(data.as_ptr() as u32);
1022 p.write_addr()
1023 .write_value(PIOS[pio_no as usize].txf(sm_no as usize).ptr() as u32);
1024 p.trans_count().write_value(data.len() as u32);
1025 p.ctrl_trig().write(|w| {
1026 // Set TX DREQ for this statemachine
1027 w.set_treq_sel(TreqSel(pio_no * 8 + sm_no));
1028 w.set_data_size(DataSize::SIZE_WORD);
1029 w.set_chain_to(ch.number());
1030 w.set_incr_read(true);
1031 w.set_incr_write(false);
1032 w.set_en(true);
1033 });
1034 compiler_fence(Ordering::SeqCst);
1035 }
1036 Transfer::new(ch)
1037 }
1038
1039 fn dma_pull<'a, C: Channel>(&'a self, ch: PeripheralRef<'a, C>, data: &'a mut [u32]) -> Transfer<'a, C> {
1040 unsafe {
1041 dma::init();
1042 let pio_no = Self::Pio::PIO_NO;
1043 let sm_no = Self::Sm::SM_NO;
1044 let p = ch.regs();
1045 p.write_addr().write_value(data.as_ptr() as u32);
1046 p.read_addr()
1047 .write_value(PIOS[pio_no as usize].rxf(sm_no as usize).ptr() as u32);
1048 p.trans_count().write_value(data.len() as u32);
1049 p.ctrl_trig().write(|w| {
1050 // Set TX DREQ for this statemachine
1051 w.set_treq_sel(TreqSel(pio_no * 8 + sm_no + 4));
1052 w.set_data_size(DataSize::SIZE_WORD);
1053 w.set_chain_to(ch.number());
1054 w.set_incr_read(false);
1055 w.set_incr_write(true);
1056 w.set_en(true);
1057 });
1058 compiler_fence(Ordering::SeqCst);
1059 }
1060 Transfer::new(ch)
1061 }
1062}
1063
1064/*
1065This is a bit array containing 4 bits for every word in the PIO instruction memory.
1066*/
1067// Bit 3-2
1068//const MEM_USE_MASK: u32 = 0b1100;
1069const MEM_NOT_USED: u32 = 0b0000;
1070const MEM_USED_BY_STATEMACHINE: u32 = 0b0100;
1071const MEM_USED_BY_COMMON: u32 = 0b1000;
1072
1073// Bit 1-0 is the number of the state machine
1074//const MEM_STATE_MASK: u32 = 0b0011;
1075
1076// Should use mutex if running on multiple cores
1077static mut INSTR_MEM_STATUS: &'static mut [[u32; 4]; 2] = &mut [[0; 4]; 2];
1078
1079fn instr_mem_get_status(pio_no: u8, addr: u8) -> u32 {
1080 ((unsafe { INSTR_MEM_STATUS[pio_no as usize][(addr >> 3) as usize] }) >> ((addr & 0x07) * 4)) & 0xf
1081}
1082
1083fn instr_mem_set_status(pio_no: u8, addr: u8, status: u32) {
1084 let w = unsafe { &mut INSTR_MEM_STATUS[pio_no as usize][(addr >> 3) as usize] };
1085 let shift = (addr & 0x07) * 4;
1086 *w = (*w & !(0xf << shift)) | (status << shift);
1087}
1088
1089fn instr_mem_is_free(pio_no: u8, addr: u8) -> bool {
1090 instr_mem_get_status(pio_no, addr) == MEM_NOT_USED
1091}
1092
1093pub struct PioCommonInstance<PIO: PioInstance> {
1094 pio: PhantomData<PIO>,
1095}
1096
1097impl<PIO: PioInstance> PioCommon for PioCommonInstance<PIO> {
1098 type Pio = PIO;
1099}
1100
1101fn write_instr(pio_no: u8, start: usize, instrs: &[u16], mem_user: u32) {
1102 for (i, instr) in instrs.iter().enumerate() {
1103 let addr = (i + start) as u8;
1104 assert!(
1105 instr_mem_is_free(pio_no, addr),
1106 "Trying to write already used PIO instruction memory at {}",
1107 addr
1108 );
1109 unsafe {
1110 PIOS[pio_no as usize].instr_mem(addr as usize).write(|w| {
1111 w.set_instr_mem(*instr);
1112 });
1113 instr_mem_set_status(pio_no, addr, mem_user);
1114 }
1115 }
1116}
1117
1118pub trait PioCommon: Sized {
1119 type Pio: PioInstance;
1120
1121 fn write_instr(&mut self, start: usize, instrs: &[u16]) {
1122 let _ = self;
1123 write_instr(Self::Pio::PIO_NO, start, instrs, MEM_USED_BY_COMMON);
1124 }
1125
1126 fn clear_irq(&mut self, irq_no: usize) {
1127 assert!(irq_no < 8);
1128 unsafe { PIOS[Self::Pio::PIO_NO as usize].irq().write(|w| w.set_irq(1 << irq_no)) }
1129 }
1130
1131 fn clear_irqs(&mut self, mask: u8) {
1132 unsafe { PIOS[Self::Pio::PIO_NO as usize].irq().write(|w| w.set_irq(mask)) }
1133 }
1134
1135 fn force_irq(&mut self, irq_no: usize) {
1136 assert!(irq_no < 8);
1137 unsafe {
1138 PIOS[Self::Pio::PIO_NO as usize]
1139 .irq_force()
1140 .write(|w| w.set_irq_force(1 << irq_no))
1141 }
1142 }
1143
1144 fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) {
1145 unsafe {
1146 PIOS[Self::Pio::PIO_NO as usize]
1147 .input_sync_bypass()
1148 .modify(|w| *w = (*w & !mask) | (bypass & mask));
1149 }
1150 }
1151
1152 fn get_input_sync_bypass(&self) -> u32 {
1153 unsafe { PIOS[Self::Pio::PIO_NO as usize].input_sync_bypass().read() }
1154 }
1155}
1156
1157// Identifies a specific state machine inside a PIO device
1158pub struct SmInstanceBase<const SM_NO: u8> {}
1159
1160pub trait SmInstance: Unpin {
1161 const SM_NO: u8;
1162}
1163
1164impl<const SM_NO: u8> SmInstance for SmInstanceBase<SM_NO> {
1165 const SM_NO: u8 = SM_NO;
1166}
1167
1168pub trait PioPeripherial: Sized {
1169 type Pio: PioInstance;
1170 fn pio(&self) -> u8 {
1171 let _ = self;
1172 Self::Pio::PIO_NO
1173 }
1174
1175 fn split(
1176 self,
1177 ) -> (
1178 PioCommonInstance<Self::Pio>,
1179 PioStateMachineInstance<Self::Pio, SmInstanceBase<0>>,
1180 PioStateMachineInstance<Self::Pio, SmInstanceBase<1>>,
1181 PioStateMachineInstance<Self::Pio, SmInstanceBase<2>>,
1182 PioStateMachineInstance<Self::Pio, SmInstanceBase<3>>,
1183 ) {
1184 let _ = self;
1185 (
1186 PioCommonInstance {
1187 pio: PhantomData::default(),
1188 },
1189 PioStateMachineInstance {
1190 sm: PhantomData::default(),
1191 pio: PhantomData::default(),
1192 },
1193 PioStateMachineInstance {
1194 sm: PhantomData::default(),
1195 pio: PhantomData::default(),
1196 },
1197 PioStateMachineInstance {
1198 sm: PhantomData::default(),
1199 pio: PhantomData::default(),
1200 },
1201 PioStateMachineInstance {
1202 sm: PhantomData::default(),
1203 pio: PhantomData::default(),
1204 },
1205 )
1206 }
1207}
1208
1209// Identifies a specific PIO device
1210pub struct PioInstanceBase<const PIO_NO: u8> {}
1211
1212pub trait PioInstance: Unpin {
1213 const PIO_NO: u8;
1214 type IrqOut: Interrupt;
1215 type IrqIn: Interrupt;
1216 type IrqSm: Interrupt;
1217}
1218
1219impl PioInstance for PioInstanceBase<0> {
1220 const PIO_NO: u8 = 0;
1221 type IrqOut = interrupt::PIO0_IRQ_0;
1222 type IrqIn = interrupt::PIO0_IRQ_1;
1223 type IrqSm = interrupt::PIO0_IRQ_1;
1224}
1225
1226impl PioInstance for PioInstanceBase<1> {
1227 const PIO_NO: u8 = 1;
1228 type IrqOut = interrupt::PIO1_IRQ_0;
1229 type IrqIn = interrupt::PIO1_IRQ_1;
1230 type IrqSm = interrupt::PIO1_IRQ_1;
1231}
1232
1233pub type Pio0 = PioInstanceBase<0>;
1234pub type Pio1 = PioInstanceBase<1>;
1235
1236pub type Sm0 = SmInstanceBase<0>;
1237pub type Sm1 = SmInstanceBase<1>;
1238pub type Sm2 = SmInstanceBase<2>;
1239pub type Sm3 = SmInstanceBase<3>;
1240
1241macro_rules! impl_pio_sm {
1242 ($name:ident, $pio:expr) => {
1243 impl PioPeripherial for peripherals::$name {
1244 type Pio = PioInstanceBase<$pio>;
1245 }
1246 };
1247}
1248
1249impl_pio_sm!(PIO0, 0);
1250impl_pio_sm!(PIO1, 1);
diff --git a/embassy-rp/src/pio_instr_util.rs b/embassy-rp/src/pio_instr_util.rs
new file mode 100644
index 000000000..ae26ff1dc
--- /dev/null
+++ b/embassy-rp/src/pio_instr_util.rs
@@ -0,0 +1,90 @@
1use pio::{InSource, InstructionOperands, JmpCondition, OutDestination, SetDestination};
2
3use crate::pio::PioStateMachine;
4
5pub fn set_x<SM: PioStateMachine>(sm: &mut SM, value: u32) {
6 const OUT: u16 = InstructionOperands::OUT {
7 destination: OutDestination::X,
8 bit_count: 32,
9 }
10 .encode();
11 sm.push_tx(value);
12 sm.exec_instr(OUT);
13}
14
15pub fn get_x<SM: PioStateMachine>(sm: &mut SM) -> u32 {
16 const IN: u16 = InstructionOperands::IN {
17 source: InSource::X,
18 bit_count: 32,
19 }
20 .encode();
21 sm.exec_instr(IN);
22 sm.pull_rx()
23}
24
25pub fn set_y<SM: PioStateMachine>(sm: &mut SM, value: u32) {
26 const OUT: u16 = InstructionOperands::OUT {
27 destination: OutDestination::Y,
28 bit_count: 32,
29 }
30 .encode();
31 sm.push_tx(value);
32 sm.exec_instr(OUT);
33}
34
35pub fn get_y<SM: PioStateMachine>(sm: &mut SM) -> u32 {
36 const IN: u16 = InstructionOperands::IN {
37 source: InSource::Y,
38 bit_count: 32,
39 }
40 .encode();
41 sm.exec_instr(IN);
42
43 sm.pull_rx()
44}
45
46pub fn set_pindir<SM: PioStateMachine>(sm: &mut SM, data: u8) {
47 let set: u16 = InstructionOperands::SET {
48 destination: SetDestination::PINDIRS,
49 data,
50 }
51 .encode();
52 sm.exec_instr(set);
53}
54
55pub fn set_pin<SM: PioStateMachine>(sm: &mut SM, data: u8) {
56 let set: u16 = InstructionOperands::SET {
57 destination: SetDestination::PINS,
58 data,
59 }
60 .encode();
61 sm.exec_instr(set);
62}
63
64pub fn set_out_pin<SM: PioStateMachine>(sm: &mut SM, data: u32) {
65 const OUT: u16 = InstructionOperands::OUT {
66 destination: OutDestination::PINS,
67 bit_count: 32,
68 }
69 .encode();
70 sm.push_tx(data);
71 sm.exec_instr(OUT);
72}
73pub fn set_out_pindir<SM: PioStateMachine>(sm: &mut SM, data: u32) {
74 const OUT: u16 = InstructionOperands::OUT {
75 destination: OutDestination::PINDIRS,
76 bit_count: 32,
77 }
78 .encode();
79 sm.push_tx(data);
80 sm.exec_instr(OUT);
81}
82
83pub fn exec_jmp<SM: PioStateMachine>(sm: &mut SM, to_addr: u8) {
84 let jmp: u16 = InstructionOperands::JMP {
85 address: to_addr,
86 condition: JmpCondition::Always,
87 }
88 .encode();
89 sm.exec_instr(jmp);
90}
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index 60a8ba94d..b07c471af 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
9embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 10embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
11embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 11embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
12embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver"] } 12embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "pio"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } 14embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] }
15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
@@ -34,6 +34,11 @@ embedded-io = { version = "0.4.0", features = ["async", "defmt"] }
34embedded-storage = { version = "0.3" } 34embedded-storage = { version = "0.3" }
35static_cell = "1.0.0" 35static_cell = "1.0.0"
36log = "0.4" 36log = "0.4"
37pio-proc = "0.2"
38pio = "0.2"
37 39
38[profile.release] 40[profile.release]
39debug = true 41debug = true
42
43[patch.crates-io]
44pio = {git = "https://github.com/rp-rs/pio-rs.git"} \ No newline at end of file
diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs
new file mode 100644
index 000000000..e9211db3b
--- /dev/null
+++ b/examples/rp/src/bin/pio_async.rs
@@ -0,0 +1,105 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4use defmt::info;
5use embassy_executor::Spawner;
6use embassy_rp::gpio::{AnyPin, Pin};
7use embassy_rp::pio::{Pio0, PioPeripherial, PioStateMachine, PioStateMachineInstance, ShiftDirection, Sm0, Sm1, Sm2};
8use embassy_rp::pio_instr_util;
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::task]
12async fn pio_task_sm0(mut sm: PioStateMachineInstance<Pio0, Sm0>, pin: AnyPin) {
13 // Setup sm0
14
15 // Send data serially to pin
16 let prg = pio_proc::pio_asm!(
17 ".origin 16",
18 "set pindirs, 1",
19 ".wrap_target",
20 "out pins,1 [19]",
21 ".wrap",
22 );
23
24 let origin = prg.program.origin.unwrap_or(0);
25 let out_pin = sm.make_pio_pin(pin);
26 let pio_pins = [&out_pin];
27 sm.set_out_pins(&pio_pins);
28 sm.write_instr(origin as usize, &prg.program.code);
29 pio_instr_util::exec_jmp(&mut sm, origin);
30 sm.set_clkdiv((125e6 / 20.0 / 2e2 * 256.0) as u32);
31 sm.set_set_range(0, 1);
32 sm.set_wrap(prg.program.wrap.source + origin, prg.program.wrap.target + origin);
33 sm.set_autopull(true);
34 sm.set_out_shift_dir(ShiftDirection::Left);
35
36 sm.set_enable(true);
37
38 let mut v = 0x0f0caffa;
39 loop {
40 sm.wait_push(v).await;
41 v ^= 0xffff;
42 info!("Pushed {:032b} to FIFO", v);
43 }
44}
45
46#[embassy_executor::task]
47async fn pio_task_sm1(mut sm: PioStateMachineInstance<Pio0, Sm1>) {
48 // Setupm sm1
49
50 // Read 0b10101 repeatedly until ISR is full
51 let prg = pio_proc::pio_asm!(".origin 8", "set x, 0x15", ".wrap_target", "in x, 5 [31]", ".wrap",);
52
53 let origin = prg.program.origin.unwrap_or(0);
54 sm.write_instr(origin as usize, &prg.program.code);
55 pio_instr_util::exec_jmp(&mut sm, origin);
56 sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32);
57 sm.set_set_range(0, 0);
58 sm.set_wrap(prg.program.wrap.source + origin, prg.program.wrap.target + origin);
59 sm.set_autopush(true);
60 sm.set_in_shift_dir(ShiftDirection::Right);
61 sm.set_enable(true);
62 loop {
63 let rx = sm.wait_pull().await;
64 info!("Pulled {:032b} from FIFO", rx);
65 }
66}
67
68#[embassy_executor::task]
69async fn pio_task_sm2(mut sm: PioStateMachineInstance<Pio0, Sm2>) {
70 // Setup sm2
71
72 // Repeatedly trigger IRQ 3
73 let prg = pio_proc::pio_asm!(
74 ".origin 0",
75 ".wrap_target",
76 "set x,10",
77 "delay:",
78 "jmp x-- delay [15]",
79 "irq 3 [15]",
80 ".wrap",
81 );
82 let origin = prg.program.origin.unwrap_or(0);
83
84 sm.write_instr(origin as usize, &prg.program.code);
85 sm.set_wrap(prg.program.wrap.source + origin, prg.program.wrap.target + origin);
86 pio_instr_util::exec_jmp(&mut sm, origin);
87 sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32);
88 sm.set_enable(true);
89 loop {
90 sm.wait_irq(3).await;
91 info!("IRQ trigged");
92 }
93}
94
95#[embassy_executor::main]
96async fn main(spawner: Spawner) {
97 let p = embassy_rp::init(Default::default());
98 let pio = p.PIO0;
99
100 let (_, sm0, sm1, sm2, ..) = pio.split();
101
102 spawner.spawn(pio_task_sm0(sm0, p.PIN_0.degrade())).unwrap();
103 spawner.spawn(pio_task_sm1(sm1)).unwrap();
104 spawner.spawn(pio_task_sm2(sm2)).unwrap();
105}
diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs
new file mode 100644
index 000000000..bdcdf200c
--- /dev/null
+++ b/examples/rp/src/bin/pio_dma.rs
@@ -0,0 +1,67 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4use defmt::info;
5use embassy_executor::Spawner;
6use embassy_futures::join::join;
7use embassy_rp::pio::{PioPeripherial, PioStateMachine, ShiftDirection};
8use embassy_rp::{pio_instr_util, Peripheral};
9use {defmt_rtt as _, panic_probe as _};
10
11fn swap_nibbles(v: u32) -> u32 {
12 let v = (v & 0x0f0f_0f0f) << 4 | (v & 0xf0f0_f0f0) >> 4;
13 let v = (v & 0x00ff_00ff) << 8 | (v & 0xff00_ff00) >> 8;
14 (v & 0x0000_ffff) << 16 | (v & 0xffff_0000) >> 16
15}
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = embassy_rp::init(Default::default());
20 let pio = p.PIO0;
21 let (_, mut sm, ..) = pio.split();
22
23 let prg = pio_proc::pio_asm!(
24 ".origin 0",
25 "set pindirs,1",
26 ".wrap_target",
27 "set y,7",
28 "loop:",
29 "out x,4",
30 "in x,4",
31 "jmp y--, loop",
32 ".wrap",
33 );
34
35 let origin = prg.program.origin.unwrap_or(0);
36 sm.write_instr(origin as usize, &prg.program.code);
37 pio_instr_util::exec_jmp(&mut sm, origin);
38 sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32);
39 sm.set_wrap(prg.program.wrap.source + origin, prg.program.wrap.target + origin);
40 sm.set_autopull(true);
41 sm.set_autopush(true);
42 sm.set_pull_threshold(32);
43 sm.set_push_threshold(32);
44 sm.set_out_shift_dir(ShiftDirection::Right);
45 sm.set_in_shift_dir(ShiftDirection::Left);
46
47 sm.set_enable(true);
48
49 let mut dma_out_ref = p.DMA_CH0.into_ref();
50 let mut dma_in_ref = p.DMA_CH1.into_ref();
51 let mut dout = [0x12345678u32; 29];
52 for i in 1..dout.len() {
53 dout[i] = (dout[i - 1] & 0x0fff_ffff) * 13 + 7;
54 }
55 let mut din = [0u32; 29];
56 loop {
57 join(
58 sm.dma_push(dma_out_ref.reborrow(), &dout),
59 sm.dma_pull(dma_in_ref.reborrow(), &mut din),
60 )
61 .await;
62 for i in 0..din.len() {
63 assert_eq!(din[i], swap_nibbles(dout[i]));
64 }
65 info!("Swapped {} words", dout.len());
66 }
67}