rp/pio: move non-sm-specific methods to PioCommon

pin and irq operations affect the entire pio block. with pins this is
not very problematic since pins themselves are resources, but irqs are
not treated like that and can thus interfere across state machines. the
ability to wait for an irq on a state machine is kept to make
synchronization with user code easier, and since we can't inspect loaded
programs at build time we wouldn't gain much from disallowing waits from
state machines anyway.
This commit is contained in:
pennae 2023-04-25 20:16:27 +02:00
parent 4cd5ed81aa
commit 58e727d3b9
3 changed files with 47 additions and 45 deletions

View File

@ -677,26 +677,6 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
} }
} }
fn make_pio_pin(&self, pin: impl Pin) -> PioPin<Self::Pio> {
unsafe {
pin.io().ctrl().write(|w| {
w.set_funcsel(
if Self::Pio::PIO_NO == 1 {
pac::io::vals::Gpio0ctrlFuncsel::PIO1_0
} else {
// PIO == 0
pac::io::vals::Gpio0ctrlFuncsel::PIO0_0
}
.0,
);
});
}
PioPin {
pin_bank: pin.pin_bank(),
pio: PhantomData::default(),
}
}
fn set_sideset_base_pin(&mut self, base_pin: &PioPin<Self::Pio>) { fn set_sideset_base_pin(&mut self, base_pin: &PioPin<Self::Pio>) {
unsafe { unsafe {
Self::Pio::PIO Self::Pio::PIO
@ -815,19 +795,6 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
); );
} }
fn is_irq_set(&self, irq_no: u8) -> bool {
assert!(irq_no < 8);
unsafe {
let irq_flags = Self::Pio::PIO.irq();
irq_flags.read().0 & (1 << irq_no) != 0
}
}
fn clear_irq(&mut self, irq_no: usize) {
assert!(irq_no < 8);
unsafe { Self::Pio::PIO.irq().write(|w| w.set_irq(1 << irq_no)) }
}
fn wait_push<'a>(&'a mut self, value: u32) -> FifoOutFuture<'a, Self::Pio, Self> { fn wait_push<'a>(&'a mut self, value: u32) -> FifoOutFuture<'a, Self::Pio, Self> {
FifoOutFuture::new(self, value) FifoOutFuture::new(self, value)
} }
@ -990,6 +957,14 @@ pub trait PioCommon: sealed::PioCommon + Sized {
write_instr(Self::Pio::PIO, Self::Pio::PIO_NO, start, instrs, MEM_USED_BY_COMMON); write_instr(Self::Pio::PIO, Self::Pio::PIO_NO, start, instrs, MEM_USED_BY_COMMON);
} }
fn is_irq_set(&self, irq_no: u8) -> bool {
assert!(irq_no < 8);
unsafe {
let irq_flags = Self::Pio::PIO.irq();
irq_flags.read().0 & (1 << irq_no) != 0
}
}
fn clear_irq(&mut self, irq_no: usize) { fn clear_irq(&mut self, irq_no: usize) {
assert!(irq_no < 8); assert!(irq_no < 8);
unsafe { Self::Pio::PIO.irq().write(|w| w.set_irq(1 << irq_no)) } unsafe { Self::Pio::PIO.irq().write(|w| w.set_irq(1 << irq_no)) }
@ -1015,6 +990,26 @@ pub trait PioCommon: sealed::PioCommon + Sized {
fn get_input_sync_bypass(&self) -> u32 { fn get_input_sync_bypass(&self) -> u32 {
unsafe { Self::Pio::PIO.input_sync_bypass().read() } unsafe { Self::Pio::PIO.input_sync_bypass().read() }
} }
fn make_pio_pin(&self, pin: impl Pin) -> PioPin<Self::Pio> {
unsafe {
pin.io().ctrl().write(|w| {
w.set_funcsel(
if Self::Pio::PIO_NO == 1 {
pac::io::vals::Gpio0ctrlFuncsel::PIO1_0
} else {
// PIO == 0
pac::io::vals::Gpio0ctrlFuncsel::PIO0_0
}
.0,
);
});
}
PioPin {
pin_bank: pin.pin_bank(),
pio: PhantomData::default(),
}
}
} }
// Identifies a specific state machine inside a PIO device // Identifies a specific state machine inside a PIO device

View File

@ -4,13 +4,15 @@
use defmt::info; use defmt::info;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_rp::gpio::{AnyPin, Pin}; use embassy_rp::gpio::{AnyPin, Pin};
use embassy_rp::pio::{Pio0, PioPeripheral, PioStateMachine, PioStateMachineInstance, ShiftDirection, Sm0, Sm1, Sm2}; use embassy_rp::pio::{
Pio0, PioCommon, PioCommonInstance, PioPeripheral, PioStateMachine, PioStateMachineInstance, ShiftDirection, Sm0,
Sm1, Sm2,
};
use embassy_rp::pio_instr_util; use embassy_rp::pio_instr_util;
use embassy_rp::relocate::RelocatedProgram; use embassy_rp::relocate::RelocatedProgram;
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::task] fn setup_pio_task_sm0(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachineInstance<Pio0, Sm0>, pin: AnyPin) {
async fn pio_task_sm0(mut sm: PioStateMachineInstance<Pio0, Sm0>, pin: AnyPin) {
// Setup sm0 // Setup sm0
// Send data serially to pin // Send data serially to pin
@ -23,11 +25,11 @@ async fn pio_task_sm0(mut sm: PioStateMachineInstance<Pio0, Sm0>, pin: AnyPin) {
); );
let relocated = RelocatedProgram::new(&prg.program); let relocated = RelocatedProgram::new(&prg.program);
let out_pin = sm.make_pio_pin(pin); let out_pin = pio.make_pio_pin(pin);
let pio_pins = [&out_pin]; let pio_pins = [&out_pin];
sm.set_out_pins(&pio_pins); sm.set_out_pins(&pio_pins);
sm.write_instr(relocated.origin() as usize, relocated.code()); sm.write_instr(relocated.origin() as usize, relocated.code());
pio_instr_util::exec_jmp(&mut sm, relocated.origin()); pio_instr_util::exec_jmp(sm, relocated.origin());
sm.set_clkdiv((125e6 / 20.0 / 2e2 * 256.0) as u32); sm.set_clkdiv((125e6 / 20.0 / 2e2 * 256.0) as u32);
sm.set_set_range(0, 1); sm.set_set_range(0, 1);
let pio::Wrap { source, target } = relocated.wrap(); let pio::Wrap { source, target } = relocated.wrap();
@ -35,7 +37,10 @@ async fn pio_task_sm0(mut sm: PioStateMachineInstance<Pio0, Sm0>, pin: AnyPin) {
sm.set_autopull(true); sm.set_autopull(true);
sm.set_out_shift_dir(ShiftDirection::Left); sm.set_out_shift_dir(ShiftDirection::Left);
}
#[embassy_executor::task]
async fn pio_task_sm0(mut sm: PioStateMachineInstance<Pio0, Sm0>) {
sm.set_enable(true); sm.set_enable(true);
let mut v = 0x0f0caffa; let mut v = 0x0f0caffa;
@ -104,9 +109,10 @@ async fn main(spawner: Spawner) {
let p = embassy_rp::init(Default::default()); let p = embassy_rp::init(Default::default());
let pio = p.PIO0; let pio = p.PIO0;
let (_, sm0, sm1, sm2, ..) = pio.split(); let (mut pio0, mut sm0, sm1, sm2, ..) = pio.split();
spawner.spawn(pio_task_sm0(sm0, p.PIN_0.degrade())).unwrap(); setup_pio_task_sm0(&mut pio0, &mut sm0, p.PIN_0.degrade());
spawner.spawn(pio_task_sm0(sm0)).unwrap();
spawner.spawn(pio_task_sm1(sm1)).unwrap(); spawner.spawn(pio_task_sm1(sm1)).unwrap();
spawner.spawn(pio_task_sm2(sm2)).unwrap(); spawner.spawn(pio_task_sm2(sm2)).unwrap();
} }

View File

@ -6,7 +6,8 @@ use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_rp::gpio::{self, Pin}; use embassy_rp::gpio::{self, Pin};
use embassy_rp::pio::{ use embassy_rp::pio::{
FifoJoin, PioInstance, PioPeripheral, PioStateMachine, PioStateMachineInstance, ShiftDirection, SmInstance, FifoJoin, PioCommon, PioCommonInstance, PioInstance, PioPeripheral, PioStateMachine, PioStateMachineInstance,
ShiftDirection, SmInstance,
}; };
use embassy_rp::pio_instr_util; use embassy_rp::pio_instr_util;
use embassy_rp::relocate::RelocatedProgram; use embassy_rp::relocate::RelocatedProgram;
@ -18,7 +19,7 @@ pub struct Ws2812<P: PioInstance, S: SmInstance> {
} }
impl<P: PioInstance, S: SmInstance> Ws2812<P, S> { impl<P: PioInstance, S: SmInstance> Ws2812<P, S> {
pub fn new(mut sm: PioStateMachineInstance<P, S>, pin: gpio::AnyPin) -> Self { pub fn new(pio: PioCommonInstance<P>, mut sm: PioStateMachineInstance<P, S>, pin: gpio::AnyPin) -> Self {
// Setup sm0 // Setup sm0
// prepare the PIO program // prepare the PIO program
@ -53,7 +54,7 @@ impl<P: PioInstance, S: SmInstance> Ws2812<P, S> {
pio_instr_util::exec_jmp(&mut sm, relocated.origin()); pio_instr_util::exec_jmp(&mut sm, relocated.origin());
// Pin config // Pin config
let out_pin = sm.make_pio_pin(pin); let out_pin = pio.make_pio_pin(pin);
sm.set_set_pins(&[&out_pin]); sm.set_set_pins(&[&out_pin]);
sm.set_sideset_base_pin(&out_pin); sm.set_sideset_base_pin(&out_pin);
sm.set_sideset_count(1); sm.set_sideset_count(1);
@ -115,7 +116,7 @@ async fn main(_spawner: Spawner) {
info!("Start"); info!("Start");
let p = embassy_rp::init(Default::default()); let p = embassy_rp::init(Default::default());
let (_pio0, sm0, _sm1, _sm2, _sm3) = p.PIO0.split(); let (pio0, sm0, _sm1, _sm2, _sm3) = p.PIO0.split();
// This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit // This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit
// feather boards for the 2040 both have one built in. // feather boards for the 2040 both have one built in.
@ -124,7 +125,7 @@ async fn main(_spawner: Spawner) {
// For the thing plus, use pin 8 // For the thing plus, use pin 8
// For the feather, use pin 16 // For the feather, use pin 16
let mut ws2812 = Ws2812::new(sm0, p.PIN_8.degrade()); let mut ws2812 = Ws2812::new(pio0, sm0, p.PIN_8.degrade());
// Loop forever making RGB values and pushing them out to the WS2812. // Loop forever making RGB values and pushing them out to the WS2812.
loop { loop {