diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index f835fc8d..8d054790 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -13,7 +13,7 @@ use pio::{SideSet, Wrap}; use crate::dma::{Channel, Transfer, Word}; use crate::gpio::sealed::Pin as SealedPin; -use crate::gpio::{self, AnyPin, Drive, Pull, SlewRate}; +use crate::gpio::{self, AnyPin, Drive, Level, Pull, SlewRate}; use crate::pac::dma::vals::TreqSel; use crate::relocate::RelocatedProgram; use crate::{interrupt, pac, peripherals, pio_instr_util, RegExt}; @@ -54,6 +54,14 @@ pub enum ShiftDirection { Left = 0, } +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] +pub enum Direction { + In = 0, + Out = 1, +} + const RXNEMPTY_MASK: u32 = 1 << 0; const TXNFULL_MASK: u32 = 1 << 4; const SMIRQ_MASK: u32 = 1 << 8; @@ -533,6 +541,56 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { } } + fn with_paused(&mut self, f: impl FnOnce(&mut Self)) { + let enabled = self.is_enabled(); + self.set_enable(false); + let pincfg = unsafe { Self::this_sm().pinctrl().read() }; + let execcfg = unsafe { Self::this_sm().execctrl().read() }; + unsafe { + Self::this_sm().execctrl().write_clear(|w| w.set_out_sticky(true)); + } + f(self); + unsafe { + Self::this_sm().pinctrl().write_value(pincfg); + Self::this_sm().execctrl().write_value(execcfg); + } + self.set_enable(enabled); + } + + /// Sets pin directions. This pauses the current state machine to run `SET` commands + /// and temporarily unsets the `OUT_STICKY` bit. + pub fn set_pin_dirs(&mut self, dir: Direction, pins: &[&Pin<'d, PIO>]) { + self.with_paused(|sm| { + for pin in pins { + unsafe { + Self::this_sm().pinctrl().write(|w| { + w.set_set_base(pin.pin()); + w.set_set_count(1); + }); + // SET PINDIRS, (dir) + sm.exec_instr(0b111_00000_100_00000 | dir as u16); + } + } + }); + } + + /// Sets pin output values. This pauses the current state machine to run + /// `SET` commands and temporarily unsets the `OUT_STICKY` bit. + pub fn set_pins(&mut self, level: Level, pins: &[&Pin<'d, PIO>]) { + self.with_paused(|sm| { + for pin in pins { + unsafe { + Self::this_sm().pinctrl().write(|w| { + w.set_set_base(pin.pin()); + w.set_set_count(1); + }); + // SET PINS, (dir) + sm.exec_instr(0b111_00000_000_00000 | level as u16); + } + } + }); + } + pub fn set_jmp_pin(&mut self, pin: u8) { unsafe { Self::this_sm().execctrl().modify(|w| w.set_jmp_pin(pin)); diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs index c3466b55..40dee1c4 100644 --- a/examples/rp/src/bin/pio_hd44780.rs +++ b/examples/rp/src/bin/pio_hd44780.rs @@ -7,7 +7,7 @@ use core::fmt::Write; use embassy_executor::Spawner; use embassy_rp::dma::{AnyChannel, Channel}; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{FifoJoin, Pio, PioPin, ShiftDirection, StateMachine}; +use embassy_rp::pio::{Direction, FifoJoin, Pio, PioPin, ShiftDirection, StateMachine}; use embassy_rp::pwm::{Config, Pwm}; use embassy_rp::relocate::RelocatedProgram; use embassy_rp::{into_ref, Peripheral, PeripheralRef}; @@ -115,12 +115,7 @@ impl<'l> HD44780<'l> { let db6 = common.make_pio_pin(db6); let db7 = common.make_pio_pin(db7); - sm0.set_set_pins(&[&rs, &rw]); - embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b11); - sm0.set_set_pins(&[&e]); - embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b1); - sm0.set_set_pins(&[&db4, &db5, &db6, &db7]); - embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b11111); + sm0.set_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]); let relocated = RelocatedProgram::new(&prg.program); sm0.use_program(&common.load_program(&relocated), &[&e]);