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.
This commit is contained in:
parent
ce04b732d1
commit
a10850a6da
@ -12,14 +12,29 @@ use crate::dma::{self, Channel, Transfer};
|
|||||||
use crate::gpio::sealed::Pin as SealedPin;
|
use crate::gpio::sealed::Pin as SealedPin;
|
||||||
use crate::gpio::{Drive, Pin, Pull, SlewRate};
|
use crate::gpio::{Drive, Pin, Pull, SlewRate};
|
||||||
use crate::pac::dma::vals::{DataSize, TreqSel};
|
use crate::pac::dma::vals::{DataSize, TreqSel};
|
||||||
use crate::{interrupt, pac, peripherals};
|
use crate::{interrupt, pac, peripherals, RegExt};
|
||||||
|
|
||||||
|
struct Wakers([AtomicWaker; 12]);
|
||||||
|
|
||||||
|
impl Wakers {
|
||||||
|
#[inline(always)]
|
||||||
|
fn fifo_in(&self) -> &[AtomicWaker] {
|
||||||
|
&self.0[0..4]
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
fn fifo_out(&self) -> &[AtomicWaker] {
|
||||||
|
&self.0[4..8]
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
fn irq(&self) -> &[AtomicWaker] {
|
||||||
|
&self.0[8..12]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const PIOS: [&pac::pio::Pio; 2] = [&pac::PIO0, &pac::PIO1];
|
const PIOS: [&pac::pio::Pio; 2] = [&pac::PIO0, &pac::PIO1];
|
||||||
const NEW_AW: AtomicWaker = AtomicWaker::new();
|
const NEW_AW: AtomicWaker = AtomicWaker::new();
|
||||||
const PIO_WAKERS_INIT: [AtomicWaker; 4] = [NEW_AW; 4];
|
const PIO_WAKERS_INIT: Wakers = Wakers([NEW_AW; 12]);
|
||||||
static FIFO_OUT_WAKERS: [[AtomicWaker; 4]; 2] = [PIO_WAKERS_INIT; 2];
|
static WAKERS: [Wakers; 2] = [PIO_WAKERS_INIT; 2];
|
||||||
static FIFO_IN_WAKERS: [[AtomicWaker; 4]; 2] = [PIO_WAKERS_INIT; 2];
|
|
||||||
static IRQ_WAKERS: [[AtomicWaker; 4]; 2] = [PIO_WAKERS_INIT; 2];
|
|
||||||
|
|
||||||
pub enum FifoJoin {
|
pub enum FifoJoin {
|
||||||
/// Both TX and RX fifo is enabled
|
/// Both TX and RX fifo is enabled
|
||||||
@ -40,83 +55,28 @@ const RXNEMPTY_MASK: u32 = 1 << 0;
|
|||||||
const TXNFULL_MASK: u32 = 1 << 4;
|
const TXNFULL_MASK: u32 = 1 << 4;
|
||||||
const SMIRQ_MASK: u32 = 1 << 8;
|
const SMIRQ_MASK: u32 = 1 << 8;
|
||||||
|
|
||||||
#[interrupt]
|
|
||||||
unsafe fn PIO0_IRQ_1() {
|
|
||||||
use crate::pac;
|
|
||||||
let ints = pac::PIO0.irqs(1).ints().read().0;
|
|
||||||
let inte = pac::PIO0.irqs(1).inte();
|
|
||||||
for i in 0..4 {
|
|
||||||
// Check RXNEMPTY
|
|
||||||
if ints & (RXNEMPTY_MASK << i) != 0 {
|
|
||||||
inte.modify(|m| {
|
|
||||||
m.0 &= !(RXNEMPTY_MASK << i);
|
|
||||||
});
|
|
||||||
FIFO_IN_WAKERS[0][i].wake();
|
|
||||||
}
|
|
||||||
// Check IRQ flgs
|
|
||||||
if ints & (SMIRQ_MASK << i) != 0 {
|
|
||||||
inte.modify(|m| {
|
|
||||||
m.0 &= !(SMIRQ_MASK << i);
|
|
||||||
});
|
|
||||||
IRQ_WAKERS[0][i].wake();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[interrupt]
|
|
||||||
unsafe fn PIO1_IRQ_1() {
|
|
||||||
use crate::pac;
|
|
||||||
let ints = pac::PIO1.irqs(1).ints().read().0;
|
|
||||||
let inte = pac::PIO1.irqs(1).inte();
|
|
||||||
for i in 0..4 {
|
|
||||||
// Check all RXNEMPTY
|
|
||||||
if ints & (RXNEMPTY_MASK << i) != 0 {
|
|
||||||
inte.modify(|m| {
|
|
||||||
m.0 &= !(RXNEMPTY_MASK << i);
|
|
||||||
});
|
|
||||||
FIFO_IN_WAKERS[1][i].wake();
|
|
||||||
}
|
|
||||||
// Check IRQ flgs
|
|
||||||
if ints & (SMIRQ_MASK << i) != 0 {
|
|
||||||
inte.modify(|m| {
|
|
||||||
m.0 &= !(SMIRQ_MASK << i);
|
|
||||||
});
|
|
||||||
IRQ_WAKERS[1][i].wake();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
unsafe fn PIO0_IRQ_0() {
|
unsafe fn PIO0_IRQ_0() {
|
||||||
use crate::pac;
|
use crate::pac;
|
||||||
let ints = pac::PIO0.irqs(0).ints().read().0;
|
let ints = pac::PIO0.irqs(0).ints().read().0;
|
||||||
let inte = pac::PIO0.irqs(0).inte();
|
for bit in 0..12 {
|
||||||
//debug!("!{:04x}",ints);
|
if ints & (1 << bit) != 0 {
|
||||||
// Check all TXNFULL
|
WAKERS[0].0[bit].wake();
|
||||||
for i in 0..4 {
|
|
||||||
if ints & (TXNFULL_MASK << i) != 0 {
|
|
||||||
inte.modify(|m| {
|
|
||||||
m.0 &= !(TXNFULL_MASK << i);
|
|
||||||
});
|
|
||||||
FIFO_OUT_WAKERS[0][i].wake();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pac::PIO0.irqs(0).inte().write_clear(|m| m.0 = ints);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
unsafe fn PIO1_IRQ_0() {
|
unsafe fn PIO1_IRQ_0() {
|
||||||
use crate::pac;
|
use crate::pac;
|
||||||
let ints = pac::PIO1.irqs(0).ints().read().0;
|
let ints = pac::PIO1.irqs(0).ints().read().0;
|
||||||
let inte = pac::PIO1.irqs(0).inte();
|
for bit in 0..12 {
|
||||||
// Check all TXNFULL
|
if ints & (1 << bit) != 0 {
|
||||||
for i in 0..4 {
|
WAKERS[1].0[bit].wake();
|
||||||
if ints & (TXNFULL_MASK << i) != 0 {
|
|
||||||
inte.modify(|m| {
|
|
||||||
m.0 &= !(TXNFULL_MASK << i);
|
|
||||||
});
|
|
||||||
FIFO_OUT_WAKERS[1][i].wake();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pac::PIO1.irqs(0).inte().write_clear(|m| m.0 = ints);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Future that waits for TX-FIFO to become writable
|
/// Future that waits for TX-FIFO to become writable
|
||||||
@ -131,7 +91,7 @@ impl<'a, PIO: PioInstance, SM: PioStateMachine + Unpin> FifoOutFuture<'a, PIO, S
|
|||||||
pub fn new(sm: &'a mut SM, value: u32) -> Self {
|
pub fn new(sm: &'a mut SM, value: u32) -> Self {
|
||||||
unsafe {
|
unsafe {
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
let irq = PIO::IrqOut::steal();
|
let irq = PIO::Irq::steal();
|
||||||
irq.set_priority(interrupt::Priority::P3);
|
irq.set_priority(interrupt::Priority::P3);
|
||||||
|
|
||||||
irq.enable();
|
irq.enable();
|
||||||
@ -153,9 +113,9 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Future for FifoOutFuture
|
|||||||
if self.get_mut().sm.try_push_tx(value) {
|
if self.get_mut().sm.try_push_tx(value) {
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
} else {
|
} else {
|
||||||
FIFO_OUT_WAKERS[PIO::PIO_NO as usize][SM::Sm::SM_NO as usize].register(cx.waker());
|
WAKERS[PIO::PIO_NO as usize].fifo_out()[SM::Sm::SM_NO as usize].register(cx.waker());
|
||||||
unsafe {
|
unsafe {
|
||||||
let irq = PIO::IrqOut::steal();
|
let irq = PIO::Irq::steal();
|
||||||
irq.disable();
|
irq.disable();
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| {
|
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> {
|
|||||||
pub fn new(sm: &'a mut SM) -> Self {
|
pub fn new(sm: &'a mut SM) -> Self {
|
||||||
unsafe {
|
unsafe {
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
let irq = PIO::IrqIn::steal();
|
let irq = PIO::Irq::steal();
|
||||||
irq.set_priority(interrupt::Priority::P3);
|
irq.set_priority(interrupt::Priority::P3);
|
||||||
|
|
||||||
irq.enable();
|
irq.enable();
|
||||||
@ -213,12 +173,12 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Future for FifoInFuture<'d, PIO,
|
|||||||
if let Some(v) = self.sm.try_pull_rx() {
|
if let Some(v) = self.sm.try_pull_rx() {
|
||||||
Poll::Ready(v)
|
Poll::Ready(v)
|
||||||
} else {
|
} else {
|
||||||
FIFO_IN_WAKERS[PIO::PIO_NO as usize][SM::Sm::SM_NO as usize].register(cx.waker());
|
WAKERS[PIO::PIO_NO as usize].fifo_in()[SM::Sm::SM_NO as usize].register(cx.waker());
|
||||||
unsafe {
|
unsafe {
|
||||||
let irq = PIO::IrqIn::steal();
|
let irq = PIO::Irq::steal();
|
||||||
irq.disable();
|
irq.disable();
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
PIOS[PIO::PIO_NO as usize].irqs(1).inte().modify(|m| {
|
PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| {
|
||||||
m.0 |= RXNEMPTY_MASK << SM::Sm::SM_NO;
|
m.0 |= RXNEMPTY_MASK << SM::Sm::SM_NO;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -234,7 +194,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Drop for FifoInFuture<'d, PIO, S
|
|||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
PIOS[PIO::PIO_NO as usize].irqs(1).inte().modify(|m| {
|
PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| {
|
||||||
m.0 &= !(RXNEMPTY_MASK << SM::Sm::SM_NO);
|
m.0 &= !(RXNEMPTY_MASK << SM::Sm::SM_NO);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -253,7 +213,7 @@ impl<'a, PIO: PioInstance> IrqFuture<PIO> {
|
|||||||
pub fn new(irq_no: u8) -> Self {
|
pub fn new(irq_no: u8) -> Self {
|
||||||
unsafe {
|
unsafe {
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
let irq = PIO::IrqSm::steal();
|
let irq = PIO::Irq::steal();
|
||||||
irq.set_priority(interrupt::Priority::P3);
|
irq.set_priority(interrupt::Priority::P3);
|
||||||
|
|
||||||
irq.enable();
|
irq.enable();
|
||||||
@ -286,12 +246,12 @@ impl<'d, PIO: PioInstance> Future for IrqFuture<PIO> {
|
|||||||
return Poll::Ready(());
|
return Poll::Ready(());
|
||||||
}
|
}
|
||||||
|
|
||||||
IRQ_WAKERS[PIO::PIO_NO as usize][self.irq_no as usize].register(cx.waker());
|
WAKERS[PIO::PIO_NO as usize].irq()[self.irq_no as usize].register(cx.waker());
|
||||||
unsafe {
|
unsafe {
|
||||||
let irq = PIO::IrqSm::steal();
|
let irq = PIO::Irq::steal();
|
||||||
irq.disable();
|
irq.disable();
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
PIOS[PIO::PIO_NO as usize].irqs(1).inte().modify(|m| {
|
PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| {
|
||||||
m.0 |= SMIRQ_MASK << self.irq_no;
|
m.0 |= SMIRQ_MASK << self.irq_no;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -305,7 +265,7 @@ impl<'d, PIO: PioInstance> Drop for IrqFuture<PIO> {
|
|||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
PIOS[PIO::PIO_NO as usize].irqs(1).inte().modify(|m| {
|
PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| {
|
||||||
m.0 &= !(SMIRQ_MASK << self.irq_no);
|
m.0 &= !(SMIRQ_MASK << self.irq_no);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -1223,23 +1183,17 @@ pub struct PioInstanceBase<const PIO_NO: u8> {}
|
|||||||
|
|
||||||
pub trait PioInstance: Unpin {
|
pub trait PioInstance: Unpin {
|
||||||
const PIO_NO: u8;
|
const PIO_NO: u8;
|
||||||
type IrqOut: Interrupt;
|
type Irq: Interrupt;
|
||||||
type IrqIn: Interrupt;
|
|
||||||
type IrqSm: Interrupt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PioInstance for PioInstanceBase<0> {
|
impl PioInstance for PioInstanceBase<0> {
|
||||||
const PIO_NO: u8 = 0;
|
const PIO_NO: u8 = 0;
|
||||||
type IrqOut = interrupt::PIO0_IRQ_0;
|
type Irq = interrupt::PIO0_IRQ_0;
|
||||||
type IrqIn = interrupt::PIO0_IRQ_1;
|
|
||||||
type IrqSm = interrupt::PIO0_IRQ_1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PioInstance for PioInstanceBase<1> {
|
impl PioInstance for PioInstanceBase<1> {
|
||||||
const PIO_NO: u8 = 1;
|
const PIO_NO: u8 = 1;
|
||||||
type IrqOut = interrupt::PIO1_IRQ_0;
|
type Irq = interrupt::PIO1_IRQ_0;
|
||||||
type IrqIn = interrupt::PIO1_IRQ_1;
|
|
||||||
type IrqSm = interrupt::PIO1_IRQ_1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Pio0 = PioInstanceBase<0>;
|
pub type Pio0 = PioInstanceBase<0>;
|
||||||
|
Loading…
Reference in New Issue
Block a user