aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpennae <[email protected]>2023-04-25 02:27:56 +0200
committerpennae <[email protected]>2023-05-01 12:53:32 +0200
commita10850a6dacc0672f998069457bf104eb970c746 (patch)
tree7dbea9aa55a7cbed002c6e95b85d93c07683548c
parentce04b732d131f488967846f6f593e10d7721ca86 (diff)
rp/pio: handle all pio irqs in one handler
dma does this too, also with 12 bits to check. this decreases code size significantly (increasing speed when the cache is cold), frees up an interrupt handler, and avoids read-modify-write cycles (which makes each processed flag cheaper). due to more iterations per handler invocation the actual runtime of the handler body remains roughly the same (slightly faster at O2, slightly slower at Oz). notably wakers are now kept in one large array indexed by the irq register bit number instead of three different arrays, this allows for machine code-level optimizations of waker lookups.
-rw-r--r--embassy-rp/src/pio.rs134
1 files changed, 44 insertions, 90 deletions
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs
index 3c7abea25..e3b6ca97c 100644
--- a/embassy-rp/src/pio.rs
+++ b/embassy-rp/src/pio.rs
@@ -12,14 +12,29 @@ use crate::dma::{self, Channel, Transfer};
12use crate::gpio::sealed::Pin as SealedPin; 12use crate::gpio::sealed::Pin as SealedPin;
13use crate::gpio::{Drive, Pin, Pull, SlewRate}; 13use crate::gpio::{Drive, Pin, Pull, SlewRate};
14use crate::pac::dma::vals::{DataSize, TreqSel}; 14use crate::pac::dma::vals::{DataSize, TreqSel};
15use crate::{interrupt, pac, peripherals}; 15use crate::{interrupt, pac, peripherals, RegExt};
16
17struct Wakers([AtomicWaker; 12]);
18
19impl Wakers {
20 #[inline(always)]
21 fn fifo_in(&self) -> &[AtomicWaker] {
22 &self.0[0..4]
23 }
24 #[inline(always)]
25 fn fifo_out(&self) -> &[AtomicWaker] {
26 &self.0[4..8]
27 }
28 #[inline(always)]
29 fn irq(&self) -> &[AtomicWaker] {
30 &self.0[8..12]
31 }
32}
16 33
17const PIOS: [&pac::pio::Pio; 2] = [&pac::PIO0, &pac::PIO1]; 34const PIOS: [&pac::pio::Pio; 2] = [&pac::PIO0, &pac::PIO1];
18const NEW_AW: AtomicWaker = AtomicWaker::new(); 35const NEW_AW: AtomicWaker = AtomicWaker::new();
19const PIO_WAKERS_INIT: [AtomicWaker; 4] = [NEW_AW; 4]; 36const PIO_WAKERS_INIT: Wakers = Wakers([NEW_AW; 12]);
20static FIFO_OUT_WAKERS: [[AtomicWaker; 4]; 2] = [PIO_WAKERS_INIT; 2]; 37static WAKERS: [Wakers; 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 38
24pub enum FifoJoin { 39pub enum FifoJoin {
25 /// Both TX and RX fifo is enabled 40 /// Both TX and RX fifo is enabled
@@ -41,82 +56,27 @@ const TXNFULL_MASK: u32 = 1 << 4;
41const SMIRQ_MASK: u32 = 1 << 8; 56const SMIRQ_MASK: u32 = 1 << 8;
42 57
43#[interrupt] 58#[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() { 59unsafe fn PIO0_IRQ_0() {
91 use crate::pac; 60 use crate::pac;
92 let ints = pac::PIO0.irqs(0).ints().read().0; 61 let ints = pac::PIO0.irqs(0).ints().read().0;
93 let inte = pac::PIO0.irqs(0).inte(); 62 for bit in 0..12 {
94 //debug!("!{:04x}",ints); 63 if ints & (1 << bit) != 0 {
95 // Check all TXNFULL 64 WAKERS[0].0[bit].wake();
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 } 65 }
103 } 66 }
67 pac::PIO0.irqs(0).inte().write_clear(|m| m.0 = ints);
104} 68}
105 69
106#[interrupt] 70#[interrupt]
107unsafe fn PIO1_IRQ_0() { 71unsafe fn PIO1_IRQ_0() {
108 use crate::pac; 72 use crate::pac;
109 let ints = pac::PIO1.irqs(0).ints().read().0; 73 let ints = pac::PIO1.irqs(0).ints().read().0;
110 let inte = pac::PIO1.irqs(0).inte(); 74 for bit in 0..12 {
111 // Check all TXNFULL 75 if ints & (1 << bit) != 0 {
112 for i in 0..4 { 76 WAKERS[1].0[bit].wake();
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 } 77 }
119 } 78 }
79 pac::PIO1.irqs(0).inte().write_clear(|m| m.0 = ints);
120} 80}
121 81
122/// Future that waits for TX-FIFO to become writable 82/// Future that waits for TX-FIFO to become writable
@@ -131,7 +91,7 @@ impl<'a, PIO: PioInstance, SM: PioStateMachine + Unpin> FifoOutFuture<'a, PIO, S
131 pub fn new(sm: &'a mut SM, value: u32) -> Self { 91 pub fn new(sm: &'a mut SM, value: u32) -> Self {
132 unsafe { 92 unsafe {
133 critical_section::with(|_| { 93 critical_section::with(|_| {
134 let irq = PIO::IrqOut::steal(); 94 let irq = PIO::Irq::steal();
135 irq.set_priority(interrupt::Priority::P3); 95 irq.set_priority(interrupt::Priority::P3);
136 96
137 irq.enable(); 97 irq.enable();
@@ -153,9 +113,9 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Future for FifoOutFuture
153 if self.get_mut().sm.try_push_tx(value) { 113 if self.get_mut().sm.try_push_tx(value) {
154 Poll::Ready(()) 114 Poll::Ready(())
155 } else { 115 } else {
156 FIFO_OUT_WAKERS[PIO::PIO_NO as usize][SM::Sm::SM_NO as usize].register(cx.waker()); 116 WAKERS[PIO::PIO_NO as usize].fifo_out()[SM::Sm::SM_NO as usize].register(cx.waker());
157 unsafe { 117 unsafe {
158 let irq = PIO::IrqOut::steal(); 118 let irq = PIO::Irq::steal();
159 irq.disable(); 119 irq.disable();
160 critical_section::with(|_| { 120 critical_section::with(|_| {
161 PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| { 121 PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| {
@@ -193,7 +153,7 @@ impl<'a, PIO: PioInstance, SM: PioStateMachine> FifoInFuture<'a, PIO, SM> {
193 pub fn new(sm: &'a mut SM) -> Self { 153 pub fn new(sm: &'a mut SM) -> Self {
194 unsafe { 154 unsafe {
195 critical_section::with(|_| { 155 critical_section::with(|_| {
196 let irq = PIO::IrqIn::steal(); 156 let irq = PIO::Irq::steal();
197 irq.set_priority(interrupt::Priority::P3); 157 irq.set_priority(interrupt::Priority::P3);
198 158
199 irq.enable(); 159 irq.enable();
@@ -213,12 +173,12 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Future for FifoInFuture<'d, PIO,
213 if let Some(v) = self.sm.try_pull_rx() { 173 if let Some(v) = self.sm.try_pull_rx() {
214 Poll::Ready(v) 174 Poll::Ready(v)
215 } else { 175 } else {
216 FIFO_IN_WAKERS[PIO::PIO_NO as usize][SM::Sm::SM_NO as usize].register(cx.waker()); 176 WAKERS[PIO::PIO_NO as usize].fifo_in()[SM::Sm::SM_NO as usize].register(cx.waker());
217 unsafe { 177 unsafe {
218 let irq = PIO::IrqIn::steal(); 178 let irq = PIO::Irq::steal();
219 irq.disable(); 179 irq.disable();
220 critical_section::with(|_| { 180 critical_section::with(|_| {
221 PIOS[PIO::PIO_NO as usize].irqs(1).inte().modify(|m| { 181 PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| {
222 m.0 |= RXNEMPTY_MASK << SM::Sm::SM_NO; 182 m.0 |= RXNEMPTY_MASK << SM::Sm::SM_NO;
223 }); 183 });
224 }); 184 });
@@ -234,7 +194,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Drop for FifoInFuture<'d, PIO, S
234 fn drop(&mut self) { 194 fn drop(&mut self) {
235 unsafe { 195 unsafe {
236 critical_section::with(|_| { 196 critical_section::with(|_| {
237 PIOS[PIO::PIO_NO as usize].irqs(1).inte().modify(|m| { 197 PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| {
238 m.0 &= !(RXNEMPTY_MASK << SM::Sm::SM_NO); 198 m.0 &= !(RXNEMPTY_MASK << SM::Sm::SM_NO);
239 }); 199 });
240 }); 200 });
@@ -253,7 +213,7 @@ impl<'a, PIO: PioInstance> IrqFuture<PIO> {
253 pub fn new(irq_no: u8) -> Self { 213 pub fn new(irq_no: u8) -> Self {
254 unsafe { 214 unsafe {
255 critical_section::with(|_| { 215 critical_section::with(|_| {
256 let irq = PIO::IrqSm::steal(); 216 let irq = PIO::Irq::steal();
257 irq.set_priority(interrupt::Priority::P3); 217 irq.set_priority(interrupt::Priority::P3);
258 218
259 irq.enable(); 219 irq.enable();
@@ -286,12 +246,12 @@ impl<'d, PIO: PioInstance> Future for IrqFuture<PIO> {
286 return Poll::Ready(()); 246 return Poll::Ready(());
287 } 247 }
288 248
289 IRQ_WAKERS[PIO::PIO_NO as usize][self.irq_no as usize].register(cx.waker()); 249 WAKERS[PIO::PIO_NO as usize].irq()[self.irq_no as usize].register(cx.waker());
290 unsafe { 250 unsafe {
291 let irq = PIO::IrqSm::steal(); 251 let irq = PIO::Irq::steal();
292 irq.disable(); 252 irq.disable();
293 critical_section::with(|_| { 253 critical_section::with(|_| {
294 PIOS[PIO::PIO_NO as usize].irqs(1).inte().modify(|m| { 254 PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| {
295 m.0 |= SMIRQ_MASK << self.irq_no; 255 m.0 |= SMIRQ_MASK << self.irq_no;
296 }); 256 });
297 }); 257 });
@@ -305,7 +265,7 @@ impl<'d, PIO: PioInstance> Drop for IrqFuture<PIO> {
305 fn drop(&mut self) { 265 fn drop(&mut self) {
306 unsafe { 266 unsafe {
307 critical_section::with(|_| { 267 critical_section::with(|_| {
308 PIOS[PIO::PIO_NO as usize].irqs(1).inte().modify(|m| { 268 PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| {
309 m.0 &= !(SMIRQ_MASK << self.irq_no); 269 m.0 &= !(SMIRQ_MASK << self.irq_no);
310 }); 270 });
311 }); 271 });
@@ -1223,23 +1183,17 @@ pub struct PioInstanceBase<const PIO_NO: u8> {}
1223 1183
1224pub trait PioInstance: Unpin { 1184pub trait PioInstance: Unpin {
1225 const PIO_NO: u8; 1185 const PIO_NO: u8;
1226 type IrqOut: Interrupt; 1186 type Irq: Interrupt;
1227 type IrqIn: Interrupt;
1228 type IrqSm: Interrupt;
1229} 1187}
1230 1188
1231impl PioInstance for PioInstanceBase<0> { 1189impl PioInstance for PioInstanceBase<0> {
1232 const PIO_NO: u8 = 0; 1190 const PIO_NO: u8 = 0;
1233 type IrqOut = interrupt::PIO0_IRQ_0; 1191 type Irq = interrupt::PIO0_IRQ_0;
1234 type IrqIn = interrupt::PIO0_IRQ_1;
1235 type IrqSm = interrupt::PIO0_IRQ_1;
1236} 1192}
1237 1193
1238impl PioInstance for PioInstanceBase<1> { 1194impl PioInstance for PioInstanceBase<1> {
1239 const PIO_NO: u8 = 1; 1195 const PIO_NO: u8 = 1;
1240 type IrqOut = interrupt::PIO1_IRQ_0; 1196 type Irq = interrupt::PIO1_IRQ_0;
1241 type IrqIn = interrupt::PIO1_IRQ_1;
1242 type IrqSm = interrupt::PIO1_IRQ_1;
1243} 1197}
1244 1198
1245pub type Pio0 = PioInstanceBase<0>; 1199pub type Pio0 = PioInstanceBase<0>;