aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-rp/Cargo.toml8
-rw-r--r--embassy-rp/src/gpio.rs54
-rw-r--r--embassy-rp/src/lib.rs11
-rw-r--r--embassy-rp/src/pio.rs1259
-rw-r--r--embassy-rp/src/pio_instr_util.rs90
-rw-r--r--embassy-rp/src/relocate.rs77
-rw-r--r--embassy-stm32/build.rs2
-rw-r--r--embassy-stm32/src/usart/buffered.rs27
-rw-r--r--embassy-stm32/src/usart/mod.rs26
-rw-r--r--examples/rp/Cargo.toml7
-rw-r--r--examples/rp/src/bin/pio_async.rs112
-rw-r--r--examples/rp/src/bin/pio_dma.rs69
12 files changed, 1735 insertions, 7 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..ec05de611 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,13 +474,40 @@ 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 let (pu, pd) = match pull {
465 Pull::Up => w.set_pue(true), 480 Pull::Up => (true, false),
466 Pull::Down => w.set_pde(true), 481 Pull::Down => (false, true),
467 Pull::None => {} 482 Pull::None => (false, false),
468 } 483 };
484 w.set_pue(pu);
485 w.set_pde(pd);
486 });
487 }
488 }
489
490 /// Set the pin's drive strength.
491 #[inline]
492 pub fn set_drive_strength(&mut self, strength: Drive) {
493 unsafe {
494 self.pin.pad_ctrl().modify(|w| {
495 w.set_drive(match strength {
496 Drive::_2mA => pac::pads::vals::Drive::_2MA,
497 Drive::_4mA => pac::pads::vals::Drive::_4MA,
498 Drive::_8mA => pac::pads::vals::Drive::_8MA,
499 Drive::_12mA => pac::pads::vals::Drive::_12MA,
500 });
501 });
502 }
503 }
504
505 // Set the pin's slew rate.
506 #[inline]
507 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
508 unsafe {
509 self.pin.pad_ctrl().modify(|w| {
510 w.set_slewfast(slew_rate == SlewRate::Fast);
469 }); 511 });
470 } 512 }
471 } 513 }
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index d21b5f7b0..551392725 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -12,6 +12,14 @@ 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#[cfg(feature = "pio")]
21pub mod relocate;
22
15pub mod rom_data; 23pub mod rom_data;
16pub mod rtc; 24pub mod rtc;
17pub mod spi; 25pub mod spi;
@@ -102,6 +110,9 @@ embassy_hal_common::peripherals! {
102 FLASH, 110 FLASH,
103 111
104 ADC, 112 ADC,
113
114 PIO0,
115 PIO1,
105} 116}
106 117
107#[link_section = ".boot2"] 118#[link_section = ".boot2"]
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs
new file mode 100644
index 000000000..1a067e54f
--- /dev/null
+++ b/embassy-rp/src/pio.rs
@@ -0,0 +1,1259 @@
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<I>(&mut self, start: usize, instrs: I)
945 where
946 I: Iterator<Item = u16>,
947 {
948 let _ = self;
949 write_instr(
950 Self::Pio::PIO_NO,
951 start,
952 instrs,
953 MEM_USED_BY_STATEMACHINE | Self::Sm::SM_NO as u32,
954 );
955 }
956
957 fn is_irq_set(&self, irq_no: u8) -> bool {
958 assert!(irq_no < 8);
959 unsafe {
960 let irq_flags = PIOS[Self::Pio::PIO_NO as usize].irq();
961 irq_flags.read().0 & (1 << irq_no) != 0
962 }
963 }
964
965 fn clear_irq(&mut self, irq_no: usize) {
966 assert!(irq_no < 8);
967 unsafe { PIOS[Self::Pio::PIO_NO as usize].irq().write(|w| w.set_irq(1 << irq_no)) }
968 }
969
970 fn wait_push<'a>(&'a mut self, value: u32) -> FifoOutFuture<'a, Self::Pio, Self> {
971 FifoOutFuture::new(self, value)
972 }
973
974 fn wait_pull<'a>(&'a mut self) -> FifoInFuture<'a, Self::Pio, Self> {
975 FifoInFuture::new(self)
976 }
977
978 fn wait_irq(&self, irq_no: u8) -> IrqFuture<Self::Pio> {
979 IrqFuture::new(irq_no)
980 }
981
982 fn has_tx_stalled(&self) -> bool {
983 unsafe {
984 let fdebug = PIOS[Self::Pio::PIO_NO as usize].fdebug();
985 let ret = fdebug.read().txstall() & (1 << Self::Sm::SM_NO) != 0;
986 fdebug.write(|w| w.set_txstall(1 << Self::Sm::SM_NO));
987 ret
988 }
989 }
990
991 fn has_tx_overflowed(&self) -> bool {
992 unsafe {
993 let fdebug = PIOS[Self::Pio::PIO_NO as usize].fdebug();
994 let ret = fdebug.read().txover() & (1 << Self::Sm::SM_NO) != 0;
995 fdebug.write(|w| w.set_txover(1 << Self::Sm::SM_NO));
996 ret
997 }
998 }
999
1000 fn has_rx_stalled(&self) -> bool {
1001 unsafe {
1002 let fdebug = PIOS[Self::Pio::PIO_NO as usize].fdebug();
1003 let ret = fdebug.read().rxstall() & (1 << Self::Sm::SM_NO) != 0;
1004 fdebug.write(|w| w.set_rxstall(1 << Self::Sm::SM_NO));
1005 ret
1006 }
1007 }
1008
1009 fn has_rx_underflowed(&self) -> bool {
1010 unsafe {
1011 let fdebug = PIOS[Self::Pio::PIO_NO as usize].fdebug();
1012 let ret = fdebug.read().rxunder() & (1 << Self::Sm::SM_NO) != 0;
1013 fdebug.write(|w| w.set_rxunder(1 << Self::Sm::SM_NO));
1014 ret
1015 }
1016 }
1017
1018 fn dma_push<'a, C: Channel>(&'a self, ch: PeripheralRef<'a, C>, data: &'a [u32]) -> Transfer<'a, C> {
1019 unsafe {
1020 dma::init();
1021 let pio_no = Self::Pio::PIO_NO;
1022 let sm_no = Self::Sm::SM_NO;
1023 let p = ch.regs();
1024 p.read_addr().write_value(data.as_ptr() as u32);
1025 p.write_addr()
1026 .write_value(PIOS[pio_no as usize].txf(sm_no as usize).ptr() as u32);
1027 p.trans_count().write_value(data.len() as u32);
1028 p.ctrl_trig().write(|w| {
1029 // Set TX DREQ for this statemachine
1030 w.set_treq_sel(TreqSel(pio_no * 8 + sm_no));
1031 w.set_data_size(DataSize::SIZE_WORD);
1032 w.set_chain_to(ch.number());
1033 w.set_incr_read(true);
1034 w.set_incr_write(false);
1035 w.set_en(true);
1036 });
1037 compiler_fence(Ordering::SeqCst);
1038 }
1039 Transfer::new(ch)
1040 }
1041
1042 fn dma_pull<'a, C: Channel>(&'a self, ch: PeripheralRef<'a, C>, data: &'a mut [u32]) -> Transfer<'a, C> {
1043 unsafe {
1044 dma::init();
1045 let pio_no = Self::Pio::PIO_NO;
1046 let sm_no = Self::Sm::SM_NO;
1047 let p = ch.regs();
1048 p.write_addr().write_value(data.as_ptr() as u32);
1049 p.read_addr()
1050 .write_value(PIOS[pio_no as usize].rxf(sm_no as usize).ptr() as u32);
1051 p.trans_count().write_value(data.len() as u32);
1052 p.ctrl_trig().write(|w| {
1053 // Set TX DREQ for this statemachine
1054 w.set_treq_sel(TreqSel(pio_no * 8 + sm_no + 4));
1055 w.set_data_size(DataSize::SIZE_WORD);
1056 w.set_chain_to(ch.number());
1057 w.set_incr_read(false);
1058 w.set_incr_write(true);
1059 w.set_en(true);
1060 });
1061 compiler_fence(Ordering::SeqCst);
1062 }
1063 Transfer::new(ch)
1064 }
1065}
1066
1067/*
1068This is a bit array containing 4 bits for every word in the PIO instruction memory.
1069*/
1070// Bit 3-2
1071//const MEM_USE_MASK: u32 = 0b1100;
1072const MEM_NOT_USED: u32 = 0b0000;
1073const MEM_USED_BY_STATEMACHINE: u32 = 0b0100;
1074const MEM_USED_BY_COMMON: u32 = 0b1000;
1075
1076// Bit 1-0 is the number of the state machine
1077//const MEM_STATE_MASK: u32 = 0b0011;
1078
1079// Should use mutex if running on multiple cores
1080static mut INSTR_MEM_STATUS: &'static mut [[u32; 4]; 2] = &mut [[0; 4]; 2];
1081
1082fn instr_mem_get_status(pio_no: u8, addr: u8) -> u32 {
1083 ((unsafe { INSTR_MEM_STATUS[pio_no as usize][(addr >> 3) as usize] }) >> ((addr & 0x07) * 4)) & 0xf
1084}
1085
1086fn instr_mem_set_status(pio_no: u8, addr: u8, status: u32) {
1087 let w = unsafe { &mut INSTR_MEM_STATUS[pio_no as usize][(addr >> 3) as usize] };
1088 let shift = (addr & 0x07) * 4;
1089 *w = (*w & !(0xf << shift)) | (status << shift);
1090}
1091
1092fn instr_mem_is_free(pio_no: u8, addr: u8) -> bool {
1093 instr_mem_get_status(pio_no, addr) == MEM_NOT_USED
1094}
1095
1096pub struct PioCommonInstance<PIO: PioInstance> {
1097 pio: PhantomData<PIO>,
1098}
1099
1100impl<PIO: PioInstance> PioCommon for PioCommonInstance<PIO> {
1101 type Pio = PIO;
1102}
1103
1104fn write_instr<I>(pio_no: u8, start: usize, instrs: I, mem_user: u32)
1105where
1106 I: Iterator<Item = u16>,
1107{
1108 for (i, instr) in instrs.enumerate() {
1109 let addr = (i + start) as u8;
1110 assert!(
1111 instr_mem_is_free(pio_no, addr),
1112 "Trying to write already used PIO instruction memory at {}",
1113 addr
1114 );
1115 unsafe {
1116 PIOS[pio_no as usize].instr_mem(addr as usize).write(|w| {
1117 w.set_instr_mem(instr);
1118 });
1119 instr_mem_set_status(pio_no, addr, mem_user);
1120 }
1121 }
1122}
1123
1124pub trait PioCommon: Sized {
1125 type Pio: PioInstance;
1126
1127 fn write_instr<I>(&mut self, start: usize, instrs: I)
1128 where
1129 I: Iterator<Item = u16>,
1130 {
1131 let _ = self;
1132 write_instr(Self::Pio::PIO_NO, start, instrs, MEM_USED_BY_COMMON);
1133 }
1134
1135 fn clear_irq(&mut self, irq_no: usize) {
1136 assert!(irq_no < 8);
1137 unsafe { PIOS[Self::Pio::PIO_NO as usize].irq().write(|w| w.set_irq(1 << irq_no)) }
1138 }
1139
1140 fn clear_irqs(&mut self, mask: u8) {
1141 unsafe { PIOS[Self::Pio::PIO_NO as usize].irq().write(|w| w.set_irq(mask)) }
1142 }
1143
1144 fn force_irq(&mut self, irq_no: usize) {
1145 assert!(irq_no < 8);
1146 unsafe {
1147 PIOS[Self::Pio::PIO_NO as usize]
1148 .irq_force()
1149 .write(|w| w.set_irq_force(1 << irq_no))
1150 }
1151 }
1152
1153 fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) {
1154 unsafe {
1155 PIOS[Self::Pio::PIO_NO as usize]
1156 .input_sync_bypass()
1157 .modify(|w| *w = (*w & !mask) | (bypass & mask));
1158 }
1159 }
1160
1161 fn get_input_sync_bypass(&self) -> u32 {
1162 unsafe { PIOS[Self::Pio::PIO_NO as usize].input_sync_bypass().read() }
1163 }
1164}
1165
1166// Identifies a specific state machine inside a PIO device
1167pub struct SmInstanceBase<const SM_NO: u8> {}
1168
1169pub trait SmInstance: Unpin {
1170 const SM_NO: u8;
1171}
1172
1173impl<const SM_NO: u8> SmInstance for SmInstanceBase<SM_NO> {
1174 const SM_NO: u8 = SM_NO;
1175}
1176
1177pub trait PioPeripherial: Sized {
1178 type Pio: PioInstance;
1179 fn pio(&self) -> u8 {
1180 let _ = self;
1181 Self::Pio::PIO_NO
1182 }
1183
1184 fn split(
1185 self,
1186 ) -> (
1187 PioCommonInstance<Self::Pio>,
1188 PioStateMachineInstance<Self::Pio, SmInstanceBase<0>>,
1189 PioStateMachineInstance<Self::Pio, SmInstanceBase<1>>,
1190 PioStateMachineInstance<Self::Pio, SmInstanceBase<2>>,
1191 PioStateMachineInstance<Self::Pio, SmInstanceBase<3>>,
1192 ) {
1193 let _ = self;
1194 (
1195 PioCommonInstance {
1196 pio: PhantomData::default(),
1197 },
1198 PioStateMachineInstance {
1199 sm: PhantomData::default(),
1200 pio: PhantomData::default(),
1201 },
1202 PioStateMachineInstance {
1203 sm: PhantomData::default(),
1204 pio: PhantomData::default(),
1205 },
1206 PioStateMachineInstance {
1207 sm: PhantomData::default(),
1208 pio: PhantomData::default(),
1209 },
1210 PioStateMachineInstance {
1211 sm: PhantomData::default(),
1212 pio: PhantomData::default(),
1213 },
1214 )
1215 }
1216}
1217
1218// Identifies a specific PIO device
1219pub struct PioInstanceBase<const PIO_NO: u8> {}
1220
1221pub trait PioInstance: Unpin {
1222 const PIO_NO: u8;
1223 type IrqOut: Interrupt;
1224 type IrqIn: Interrupt;
1225 type IrqSm: Interrupt;
1226}
1227
1228impl PioInstance for PioInstanceBase<0> {
1229 const PIO_NO: u8 = 0;
1230 type IrqOut = interrupt::PIO0_IRQ_0;
1231 type IrqIn = interrupt::PIO0_IRQ_1;
1232 type IrqSm = interrupt::PIO0_IRQ_1;
1233}
1234
1235impl PioInstance for PioInstanceBase<1> {
1236 const PIO_NO: u8 = 1;
1237 type IrqOut = interrupt::PIO1_IRQ_0;
1238 type IrqIn = interrupt::PIO1_IRQ_1;
1239 type IrqSm = interrupt::PIO1_IRQ_1;
1240}
1241
1242pub type Pio0 = PioInstanceBase<0>;
1243pub type Pio1 = PioInstanceBase<1>;
1244
1245pub type Sm0 = SmInstanceBase<0>;
1246pub type Sm1 = SmInstanceBase<1>;
1247pub type Sm2 = SmInstanceBase<2>;
1248pub type Sm3 = SmInstanceBase<3>;
1249
1250macro_rules! impl_pio_sm {
1251 ($name:ident, $pio:expr) => {
1252 impl PioPeripherial for peripherals::$name {
1253 type Pio = PioInstanceBase<$pio>;
1254 }
1255 };
1256}
1257
1258impl_pio_sm!(PIO0, 0);
1259impl_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/embassy-rp/src/relocate.rs b/embassy-rp/src/relocate.rs
new file mode 100644
index 000000000..f36170e03
--- /dev/null
+++ b/embassy-rp/src/relocate.rs
@@ -0,0 +1,77 @@
1use core::iter::Iterator;
2
3use pio::{Program, SideSet, Wrap};
4
5pub struct CodeIterator<'a, I>
6where
7 I: Iterator<Item = &'a u16>,
8{
9 iter: I,
10 offset: u8,
11}
12
13impl<'a, I: Iterator<Item = &'a u16>> CodeIterator<'a, I> {
14 pub fn new(iter: I, offset: u8) -> CodeIterator<'a, I> {
15 CodeIterator { iter, offset }
16 }
17}
18
19impl<'a, I> Iterator for CodeIterator<'a, I>
20where
21 I: Iterator<Item = &'a u16>,
22{
23 type Item = u16;
24 fn next(&mut self) -> Option<Self::Item> {
25 self.iter.next().and_then(|&instr| {
26 Some(if instr & 0b1110_0000_0000_0000 == 0 {
27 // this is a JMP instruction -> add offset to address
28 let address = (instr & 0b1_1111) as u8;
29 let address = address + self.offset;
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
35 } else {
36 instr
37 })
38 })
39 }
40}
41
42pub struct RelocatedProgram<'a, const PROGRAM_SIZE: usize> {
43 program: &'a Program<PROGRAM_SIZE>,
44 origin: u8,
45}
46
47impl<'a, const PROGRAM_SIZE: usize> RelocatedProgram<'a, PROGRAM_SIZE> {
48 pub fn new(program: &Program<PROGRAM_SIZE>) -> RelocatedProgram<PROGRAM_SIZE> {
49 let origin = program.origin.unwrap_or(0);
50 RelocatedProgram { program, origin }
51 }
52
53 pub fn new_with_origin(program: &Program<PROGRAM_SIZE>, origin: u8) -> RelocatedProgram<PROGRAM_SIZE> {
54 RelocatedProgram { program, origin }
55 }
56
57 pub fn code(&'a self) -> CodeIterator<'a, core::slice::Iter<'a, u16>> {
58 CodeIterator::new(self.program.code.iter(), self.origin)
59 }
60
61 pub fn wrap(&self) -> Wrap {
62 let wrap = self.program.wrap;
63 let origin = self.origin;
64 Wrap {
65 source: wrap.source + origin,
66 target: wrap.target + origin,
67 }
68 }
69
70 pub fn side_set(&self) -> SideSet {
71 self.program.side_set
72 }
73
74 pub fn origin(&self) -> u8 {
75 self.origin
76 }
77}
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index a4709f4ca..ddfa97b29 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -244,11 +244,13 @@ fn main() {
244 (("usart", "CTS"), quote!(crate::usart::CtsPin)), 244 (("usart", "CTS"), quote!(crate::usart::CtsPin)),
245 (("usart", "RTS"), quote!(crate::usart::RtsPin)), 245 (("usart", "RTS"), quote!(crate::usart::RtsPin)),
246 (("usart", "CK"), quote!(crate::usart::CkPin)), 246 (("usart", "CK"), quote!(crate::usart::CkPin)),
247 (("usart", "DE"), quote!(crate::usart::DePin)),
247 (("lpuart", "TX"), quote!(crate::usart::TxPin)), 248 (("lpuart", "TX"), quote!(crate::usart::TxPin)),
248 (("lpuart", "RX"), quote!(crate::usart::RxPin)), 249 (("lpuart", "RX"), quote!(crate::usart::RxPin)),
249 (("lpuart", "CTS"), quote!(crate::usart::CtsPin)), 250 (("lpuart", "CTS"), quote!(crate::usart::CtsPin)),
250 (("lpuart", "RTS"), quote!(crate::usart::RtsPin)), 251 (("lpuart", "RTS"), quote!(crate::usart::RtsPin)),
251 (("lpuart", "CK"), quote!(crate::usart::CkPin)), 252 (("lpuart", "CK"), quote!(crate::usart::CkPin)),
253 (("lpuart", "DE"), quote!(crate::usart::DePin)),
252 (("spi", "SCK"), quote!(crate::spi::SckPin)), 254 (("spi", "SCK"), quote!(crate::spi::SckPin)),
253 (("spi", "MOSI"), quote!(crate::spi::MosiPin)), 255 (("spi", "MOSI"), quote!(crate::spi::MosiPin)),
254 (("spi", "MISO"), quote!(crate::spi::MisoPin)), 256 (("spi", "MISO"), quote!(crate::spi::MisoPin)),
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index d024bedcf..874af1d73 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -89,6 +89,33 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
89 Self::new_inner(state, peri, rx, tx, irq, tx_buffer, rx_buffer, config) 89 Self::new_inner(state, peri, rx, tx, irq, tx_buffer, rx_buffer, config)
90 } 90 }
91 91
92 #[cfg(not(usart_v1))]
93 pub fn new_with_de(
94 state: &'d mut State<'d, T>,
95 peri: impl Peripheral<P = T> + 'd,
96 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
97 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
98 irq: impl Peripheral<P = T::Interrupt> + 'd,
99 de: impl Peripheral<P = impl DePin<T>> + 'd,
100 tx_buffer: &'d mut [u8],
101 rx_buffer: &'d mut [u8],
102 config: Config,
103 ) -> BufferedUart<'d, T> {
104 into_ref!(de);
105
106 T::enable();
107 T::reset();
108
109 unsafe {
110 de.set_as_af(de.af_num(), AFType::OutputPushPull);
111 T::regs().cr3().write(|w| {
112 w.set_dem(true);
113 });
114 }
115
116 Self::new_inner(state, peri, rx, tx, irq, tx_buffer, rx_buffer, config)
117 }
118
92 fn new_inner( 119 fn new_inner(
93 state: &'d mut State<'d, T>, 120 state: &'d mut State<'d, T>,
94 _peri: impl Peripheral<P = T> + 'd, 121 _peri: impl Peripheral<P = T> + 'd,
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index aea054a4b..ea75361fa 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -646,6 +646,31 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
646 Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config) 646 Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config)
647 } 647 }
648 648
649 #[cfg(not(usart_v1))]
650 pub fn new_with_de(
651 peri: impl Peripheral<P = T> + 'd,
652 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
653 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
654 irq: impl Peripheral<P = T::Interrupt> + 'd,
655 de: impl Peripheral<P = impl DePin<T>> + 'd,
656 tx_dma: impl Peripheral<P = TxDma> + 'd,
657 rx_dma: impl Peripheral<P = RxDma> + 'd,
658 config: Config,
659 ) -> Self {
660 into_ref!(de);
661
662 T::enable();
663 T::reset();
664
665 unsafe {
666 de.set_as_af(de.af_num(), AFType::OutputPushPull);
667 T::regs().cr3().write(|w| {
668 w.set_dem(true);
669 });
670 }
671 Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config)
672 }
673
649 fn new_inner( 674 fn new_inner(
650 peri: impl Peripheral<P = T> + 'd, 675 peri: impl Peripheral<P = T> + 'd,
651 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 676 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@@ -1040,6 +1065,7 @@ pin_trait!(TxPin, BasicInstance);
1040pin_trait!(CtsPin, BasicInstance); 1065pin_trait!(CtsPin, BasicInstance);
1041pin_trait!(RtsPin, BasicInstance); 1066pin_trait!(RtsPin, BasicInstance);
1042pin_trait!(CkPin, BasicInstance); 1067pin_trait!(CkPin, BasicInstance);
1068pin_trait!(DePin, BasicInstance);
1043 1069
1044dma_trait!(TxDma, BasicInstance); 1070dma_trait!(TxDma, BasicInstance);
1045dma_trait!(RxDma, BasicInstance); 1071dma_trait!(RxDma, BasicInstance);
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..45a8c73f7
--- /dev/null
+++ b/examples/rp/src/bin/pio_async.rs
@@ -0,0 +1,112 @@
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 embassy_rp::relocate::RelocatedProgram;
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::task]
13async fn pio_task_sm0(mut sm: PioStateMachineInstance<Pio0, Sm0>, pin: AnyPin) {
14 // Setup sm0
15
16 // Send data serially to pin
17 let prg = pio_proc::pio_asm!(
18 ".origin 16",
19 "set pindirs, 1",
20 ".wrap_target",
21 "out pins,1 [19]",
22 ".wrap",
23 );
24
25 let relocated = RelocatedProgram::new(&prg.program);
26 let out_pin = sm.make_pio_pin(pin);
27 let pio_pins = [&out_pin];
28 sm.set_out_pins(&pio_pins);
29 sm.write_instr(relocated.origin() as usize, relocated.code());
30 pio_instr_util::exec_jmp(&mut sm, relocated.origin());
31 sm.set_clkdiv((125e6 / 20.0 / 2e2 * 256.0) as u32);
32 sm.set_set_range(0, 1);
33 let pio::Wrap { source, target } = relocated.wrap();
34 sm.set_wrap(source, target);
35
36 sm.set_autopull(true);
37 sm.set_out_shift_dir(ShiftDirection::Left);
38
39 sm.set_enable(true);
40
41 let mut v = 0x0f0caffa;
42 loop {
43 sm.wait_push(v).await;
44 v ^= 0xffff;
45 info!("Pushed {:032b} to FIFO", v);
46 }
47}
48
49#[embassy_executor::task]
50async fn pio_task_sm1(mut sm: PioStateMachineInstance<Pio0, Sm1>) {
51 // Setupm sm1
52
53 // Read 0b10101 repeatedly until ISR is full
54 let prg = pio_proc::pio_asm!(".origin 8", "set x, 0x15", ".wrap_target", "in x, 5 [31]", ".wrap",);
55
56 let relocated = RelocatedProgram::new(&prg.program);
57 sm.write_instr(relocated.origin() as usize, relocated.code());
58 pio_instr_util::exec_jmp(&mut sm, relocated.origin());
59 sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32);
60 sm.set_set_range(0, 0);
61 let pio::Wrap { source, target } = relocated.wrap();
62 sm.set_wrap(source, target);
63
64 sm.set_autopush(true);
65 sm.set_in_shift_dir(ShiftDirection::Right);
66 sm.set_enable(true);
67 loop {
68 let rx = sm.wait_pull().await;
69 info!("Pulled {:032b} from FIFO", rx);
70 }
71}
72
73#[embassy_executor::task]
74async fn pio_task_sm2(mut sm: PioStateMachineInstance<Pio0, Sm2>) {
75 // Setup sm2
76
77 // Repeatedly trigger IRQ 3
78 let prg = pio_proc::pio_asm!(
79 ".origin 0",
80 ".wrap_target",
81 "set x,10",
82 "delay:",
83 "jmp x-- delay [15]",
84 "irq 3 [15]",
85 ".wrap",
86 );
87 let relocated = RelocatedProgram::new(&prg.program);
88 sm.write_instr(relocated.origin() as usize, relocated.code());
89
90 let pio::Wrap { source, target } = relocated.wrap();
91 sm.set_wrap(source, target);
92
93 pio_instr_util::exec_jmp(&mut sm, relocated.origin());
94 sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32);
95 sm.set_enable(true);
96 loop {
97 sm.wait_irq(3).await;
98 info!("IRQ trigged");
99 }
100}
101
102#[embassy_executor::main]
103async fn main(spawner: Spawner) {
104 let p = embassy_rp::init(Default::default());
105 let pio = p.PIO0;
106
107 let (_, sm0, sm1, sm2, ..) = pio.split();
108
109 spawner.spawn(pio_task_sm0(sm0, p.PIN_0.degrade())).unwrap();
110 spawner.spawn(pio_task_sm1(sm1)).unwrap();
111 spawner.spawn(pio_task_sm2(sm2)).unwrap();
112}
diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs
new file mode 100644
index 000000000..b19ef4083
--- /dev/null
+++ b/examples/rp/src/bin/pio_dma.rs
@@ -0,0 +1,69 @@
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::relocate::RelocatedProgram;
9use embassy_rp::{pio_instr_util, Peripheral};
10use {defmt_rtt as _, panic_probe as _};
11
12fn swap_nibbles(v: u32) -> u32 {
13 let v = (v & 0x0f0f_0f0f) << 4 | (v & 0xf0f0_f0f0) >> 4;
14 let v = (v & 0x00ff_00ff) << 8 | (v & 0xff00_ff00) >> 8;
15 (v & 0x0000_ffff) << 16 | (v & 0xffff_0000) >> 16
16}
17
18#[embassy_executor::main]
19async fn main(_spawner: Spawner) {
20 let p = embassy_rp::init(Default::default());
21 let pio = p.PIO0;
22 let (_, mut sm, ..) = pio.split();
23
24 let prg = pio_proc::pio_asm!(
25 ".origin 0",
26 "set pindirs,1",
27 ".wrap_target",
28 "set y,7",
29 "loop:",
30 "out x,4",
31 "in x,4",
32 "jmp y--, loop",
33 ".wrap",
34 );
35
36 let relocated = RelocatedProgram::new(&prg.program);
37 sm.write_instr(relocated.origin() as usize, relocated.code());
38 pio_instr_util::exec_jmp(&mut sm, relocated.origin());
39 sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32);
40 let pio::Wrap { source, target } = relocated.wrap();
41 sm.set_wrap(source, target);
42 sm.set_autopull(true);
43 sm.set_autopush(true);
44 sm.set_pull_threshold(32);
45 sm.set_push_threshold(32);
46 sm.set_out_shift_dir(ShiftDirection::Right);
47 sm.set_in_shift_dir(ShiftDirection::Left);
48
49 sm.set_enable(true);
50
51 let mut dma_out_ref = p.DMA_CH0.into_ref();
52 let mut dma_in_ref = p.DMA_CH1.into_ref();
53 let mut dout = [0x12345678u32; 29];
54 for i in 1..dout.len() {
55 dout[i] = (dout[i - 1] & 0x0fff_ffff) * 13 + 7;
56 }
57 let mut din = [0u32; 29];
58 loop {
59 join(
60 sm.dma_push(dma_out_ref.reborrow(), &dout),
61 sm.dma_pull(dma_in_ref.reborrow(), &mut din),
62 )
63 .await;
64 for i in 0..din.len() {
65 assert_eq!(din[i], swap_nibbles(dout[i]));
66 }
67 info!("Swapped {} words", dout.len());
68 }
69}