1429: rp pio, √9 r=Dirbaio a=pennae

another mix of refactoring and soundness issues. most notably pio pins are now checked for being actually accessible to the pio blocks, are constructible from not just the owned peripherals but refs as well, and have their registrations to the pio block reverted once all state machines and the common block has been dropped.

state machines are now also stopped when dropped, and concurrent rx+tx using dma can finally be done in a sound manner. previously it was possible to do, but allowed users to start two concurrent transfers to the same fifo using different dma channels, which obviously would not have the expected results on average.

Co-authored-by: pennae <github@quasiparticle.net>
This commit is contained in:
bors[bot] 2023-05-04 20:04:11 +00:00 committed by GitHub
commit 067f1382e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 480 additions and 374 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,38 +1,38 @@
use pio::{InSource, InstructionOperands, JmpCondition, OutDestination, SetDestination};
use crate::pio::PioStateMachine;
use crate::pio::{PioInstance, PioStateMachine};
pub fn set_x<SM: PioStateMachine>(sm: &mut SM, value: u32) {
pub fn set_x<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, value: u32) {
const OUT: u16 = InstructionOperands::OUT {
destination: OutDestination::X,
bit_count: 32,
}
.encode();
sm.push_tx(value);
sm.tx().push(value);
sm.exec_instr(OUT);
}
pub fn get_x<SM: PioStateMachine>(sm: &mut SM) -> u32 {
pub fn get_x<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>) -> u32 {
const IN: u16 = InstructionOperands::IN {
source: InSource::X,
bit_count: 32,
}
.encode();
sm.exec_instr(IN);
sm.pull_rx()
sm.rx().pull()
}
pub fn set_y<SM: PioStateMachine>(sm: &mut SM, value: u32) {
pub fn set_y<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, value: u32) {
const OUT: u16 = InstructionOperands::OUT {
destination: OutDestination::Y,
bit_count: 32,
}
.encode();
sm.push_tx(value);
sm.tx().push(value);
sm.exec_instr(OUT);
}
pub fn get_y<SM: PioStateMachine>(sm: &mut SM) -> u32 {
pub fn get_y<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>) -> u32 {
const IN: u16 = InstructionOperands::IN {
source: InSource::Y,
bit_count: 32,
@ -40,10 +40,10 @@ pub fn get_y<SM: PioStateMachine>(sm: &mut SM) -> u32 {
.encode();
sm.exec_instr(IN);
sm.pull_rx()
sm.rx().pull()
}
pub fn set_pindir<SM: PioStateMachine>(sm: &mut SM, data: u8) {
pub fn set_pindir<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, data: u8) {
let set: u16 = InstructionOperands::SET {
destination: SetDestination::PINDIRS,
data,
@ -52,7 +52,7 @@ pub fn set_pindir<SM: PioStateMachine>(sm: &mut SM, data: u8) {
sm.exec_instr(set);
}
pub fn set_pin<SM: PioStateMachine>(sm: &mut SM, data: u8) {
pub fn set_pin<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, data: u8) {
let set: u16 = InstructionOperands::SET {
destination: SetDestination::PINS,
data,
@ -61,26 +61,26 @@ pub fn set_pin<SM: PioStateMachine>(sm: &mut SM, data: u8) {
sm.exec_instr(set);
}
pub fn set_out_pin<SM: PioStateMachine>(sm: &mut SM, data: u32) {
pub fn set_out_pin<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, data: u32) {
const OUT: u16 = InstructionOperands::OUT {
destination: OutDestination::PINS,
bit_count: 32,
}
.encode();
sm.push_tx(data);
sm.tx().push(data);
sm.exec_instr(OUT);
}
pub fn set_out_pindir<SM: PioStateMachine>(sm: &mut SM, data: u32) {
pub fn set_out_pindir<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, data: u32) {
const OUT: u16 = InstructionOperands::OUT {
destination: OutDestination::PINDIRS,
bit_count: 32,
}
.encode();
sm.push_tx(data);
sm.tx().push(data);
sm.exec_instr(OUT);
}
pub fn exec_jmp<SM: PioStateMachine>(sm: &mut SM, to_addr: u8) {
pub fn exec_jmp<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, to_addr: u8) {
let jmp: u16 = InstructionOperands::JMP {
address: to_addr,
condition: JmpCondition::Always,

View file

@ -3,14 +3,13 @@
#![feature(type_alias_impl_trait)]
use defmt::info;
use embassy_executor::Spawner;
use embassy_rp::gpio::{AnyPin, Pin};
use embassy_rp::peripherals::PIO0;
use embassy_rp::pio::{Pio, PioCommon, PioStateMachine, PioStateMachineInstance, ShiftDirection};
use embassy_rp::pio::{Pio, PioCommon, PioIrq, PioPin, PioStateMachine, ShiftDirection};
use embassy_rp::pio_instr_util;
use embassy_rp::relocate::RelocatedProgram;
use {defmt_rtt as _, panic_probe as _};
fn setup_pio_task_sm0(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachineInstance<PIO0, 0>, pin: AnyPin) {
fn setup_pio_task_sm0(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachine<PIO0, 0>, pin: impl PioPin) {
// Setup sm0
// Send data serially to pin
@ -38,18 +37,18 @@ fn setup_pio_task_sm0(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachineInstanc
}
#[embassy_executor::task]
async fn pio_task_sm0(mut sm: PioStateMachineInstance<'static, PIO0, 0>) {
async fn pio_task_sm0(mut sm: PioStateMachine<'static, PIO0, 0>) {
sm.set_enable(true);
let mut v = 0x0f0caffa;
loop {
sm.wait_push(v).await;
sm.tx().wait_push(v).await;
v ^= 0xffff;
info!("Pushed {:032b} to FIFO", v);
}
}
fn setup_pio_task_sm1(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachineInstance<PIO0, 1>) {
fn setup_pio_task_sm1(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachine<PIO0, 1>) {
// Setupm sm1
// Read 0b10101 repeatedly until ISR is full
@ -68,15 +67,15 @@ fn setup_pio_task_sm1(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachineInstanc
}
#[embassy_executor::task]
async fn pio_task_sm1(mut sm: PioStateMachineInstance<'static, PIO0, 1>) {
async fn pio_task_sm1(mut sm: PioStateMachine<'static, PIO0, 1>) {
sm.set_enable(true);
loop {
let rx = sm.wait_pull().await;
let rx = sm.rx().wait_pull().await;
info!("Pulled {:032b} from FIFO", rx);
}
}
fn setup_pio_task_sm2(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachineInstance<PIO0, 2>) {
fn setup_pio_task_sm2(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachine<PIO0, 2>) {
// Setup sm2
// Repeatedly trigger IRQ 3
@ -100,10 +99,10 @@ fn setup_pio_task_sm2(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachineInstanc
}
#[embassy_executor::task]
async fn pio_task_sm2(mut sm: PioStateMachineInstance<'static, PIO0, 2>) {
async fn pio_task_sm2(mut irq: PioIrq<'static, PIO0, 3>, mut sm: PioStateMachine<'static, PIO0, 2>) {
sm.set_enable(true);
loop {
sm.wait_irq(3).await;
irq.wait().await;
info!("IRQ trigged");
}
}
@ -115,16 +114,17 @@ async fn main(spawner: Spawner) {
let Pio {
mut common,
irq3,
mut sm0,
mut sm1,
mut sm2,
..
} = Pio::new(pio);
setup_pio_task_sm0(&mut common, &mut sm0, p.PIN_0.degrade());
setup_pio_task_sm0(&mut common, &mut sm0, p.PIN_0);
setup_pio_task_sm1(&mut common, &mut sm1);
setup_pio_task_sm2(&mut common, &mut sm2);
spawner.spawn(pio_task_sm0(sm0)).unwrap();
spawner.spawn(pio_task_sm1(sm1)).unwrap();
spawner.spawn(pio_task_sm2(sm2)).unwrap();
spawner.spawn(pio_task_sm2(irq3, sm2)).unwrap();
}

View file

@ -4,7 +4,7 @@
use defmt::info;
use embassy_executor::Spawner;
use embassy_futures::join::join;
use embassy_rp::pio::{Pio, PioStateMachine, ShiftDirection};
use embassy_rp::pio::{Pio, ShiftDirection};
use embassy_rp::relocate::RelocatedProgram;
use embassy_rp::{pio_instr_util, Peripheral};
use {defmt_rtt as _, panic_probe as _};
@ -60,9 +60,10 @@ async fn main(_spawner: Spawner) {
}
let mut din = [0u32; 29];
loop {
let (rx, tx) = sm.rx_tx();
join(
sm.dma_push(dma_out_ref.reborrow(), &dout),
sm.dma_pull(dma_in_ref.reborrow(), &mut din),
tx.dma_push(dma_out_ref.reborrow(), &dout),
rx.dma_pull(dma_in_ref.reborrow(), &mut din),
)
.await;
for i in 0..din.len() {

View file

@ -6,9 +6,8 @@ use core::fmt::Write;
use embassy_executor::Spawner;
use embassy_rp::dma::{AnyChannel, Channel};
use embassy_rp::gpio::Pin;
use embassy_rp::peripherals::PIO0;
use embassy_rp::pio::{FifoJoin, Pio, PioStateMachine, PioStateMachineInstance, ShiftDirection};
use embassy_rp::pio::{FifoJoin, Pio, PioPin, PioStateMachine, ShiftDirection};
use embassy_rp::pwm::{Config, Pwm};
use embassy_rp::relocate::RelocatedProgram;
use embassy_rp::{into_ref, Peripheral, PeripheralRef};
@ -65,7 +64,7 @@ async fn main(_spawner: Spawner) {
pub struct HD44780<'l> {
dma: PeripheralRef<'l, AnyChannel>,
sm: PioStateMachineInstance<'l, PIO0, 0>,
sm: PioStateMachine<'l, PIO0, 0>,
buf: [u8; 40],
}
@ -74,19 +73,22 @@ impl<'l> HD44780<'l> {
pub async fn new(
pio: impl Peripheral<P = PIO0> + 'l,
dma: impl Peripheral<P = impl Channel> + 'l,
rs: impl Pin,
rw: impl Pin,
e: impl Pin,
db4: impl Pin,
db5: impl Pin,
db6: impl Pin,
db7: impl Pin,
rs: impl PioPin,
rw: impl PioPin,
e: impl PioPin,
db4: impl PioPin,
db5: impl PioPin,
db6: impl PioPin,
db7: impl PioPin,
) -> HD44780<'l> {
into_ref!(dma);
let db7pin = db7.pin();
let Pio {
mut common, mut sm0, ..
mut common,
mut irq0,
mut sm0,
..
} = Pio::new(pio);
// takes command words (<wait:24> <command:4> <0:4>)
@ -137,16 +139,16 @@ impl<'l> HD44780<'l> {
sm0.set_enable(true);
// init to 8 bit thrice
sm0.push_tx((50000 << 8) | 0x30);
sm0.push_tx((5000 << 8) | 0x30);
sm0.push_tx((200 << 8) | 0x30);
sm0.tx().push((50000 << 8) | 0x30);
sm0.tx().push((5000 << 8) | 0x30);
sm0.tx().push((200 << 8) | 0x30);
// init 4 bit
sm0.push_tx((200 << 8) | 0x20);
sm0.tx().push((200 << 8) | 0x20);
// set font and lines
sm0.push_tx((50 << 8) | 0x20);
sm0.push_tx(0b1100_0000);
sm0.tx().push((50 << 8) | 0x20);
sm0.tx().push(0b1100_0000);
sm0.wait_irq(0).await;
irq0.wait().await;
sm0.set_enable(false);
// takes command sequences (<rs:1> <count:7>, data...)
@ -214,7 +216,7 @@ impl<'l> HD44780<'l> {
sm0.set_enable(true);
// display on and cursor on and blinking, reset display
sm0.dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1]).await;
sm0.tx().dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1]).await;
Self {
dma: dma.map_into(),
@ -238,6 +240,6 @@ impl<'l> HD44780<'l> {
// set cursor to 1:15
self.buf[38..].copy_from_slice(&[0x80, 0xcf]);
self.sm.dma_push(self.dma.reborrow(), &self.buf).await;
self.sm.tx().dma_push(self.dma.reborrow(), &self.buf).await;
}
}

View file

@ -4,21 +4,18 @@
use defmt::*;
use embassy_executor::Spawner;
use embassy_rp::gpio::{self, Pin};
use embassy_rp::pio::{
FifoJoin, Pio, PioCommon, PioInstance, PioStateMachine, PioStateMachineInstance, ShiftDirection,
};
use embassy_rp::pio::{FifoJoin, Pio, PioCommon, PioInstance, PioPin, PioStateMachine, ShiftDirection};
use embassy_rp::pio_instr_util;
use embassy_rp::relocate::RelocatedProgram;
use embassy_time::{Duration, Timer};
use smart_leds::RGB8;
use {defmt_rtt as _, panic_probe as _};
pub struct Ws2812<'d, P: PioInstance, const S: usize> {
sm: PioStateMachineInstance<'d, P, S>,
sm: PioStateMachine<'d, P, S>,
}
impl<'d, P: PioInstance, const S: usize> Ws2812<'d, P, S> {
pub fn new(mut pio: PioCommon<'d, P>, mut sm: PioStateMachineInstance<'d, P, S>, pin: gpio::AnyPin) -> Self {
pub fn new(mut pio: PioCommon<'d, P>, mut sm: PioStateMachine<'d, P, S>, pin: impl PioPin) -> Self {
// Setup sm0
// prepare the PIO program
@ -90,7 +87,7 @@ impl<'d, P: PioInstance, const S: usize> Ws2812<'d, P, S> {
pub async fn write(&mut self, colors: &[RGB8]) {
for color in colors {
let word = (u32::from(color.g) << 24) | (u32::from(color.r) << 16) | (u32::from(color.b) << 8);
self.sm.wait_push(word).await;
self.sm.tx().wait_push(word).await;
}
}
}
@ -124,7 +121,7 @@ async fn main(_spawner: Spawner) {
// For the thing plus, use pin 8
// For the feather, use pin 16
let mut ws2812 = Ws2812::new(common, sm0, p.PIN_8.degrade());
let mut ws2812 = Ws2812::new(common, sm0, p.PIN_8);
// Loop forever making RGB values and pushing them out to the WS2812.
loop {