From 207f5aebdbca7fe77823281cd5d8ac01f8f9badf Mon Sep 17 00:00:00 2001 From: Mathias Gottschlag Date: Thu, 30 Sep 2021 09:07:15 +0200 Subject: [PATCH] pio: Split RX and TX FIFO functions into different types. We need separate types for any blocking or DMA operations - otherwise, it would not be possible to perform both RX and TX transfers at the same time. --- rp2040-hal/examples/pio_blink.rs | 2 +- rp2040-hal/examples/pio_proc_blink.rs | 2 +- rp2040-hal/src/pio.rs | 118 ++++++++++++++++---------- 3 files changed, 74 insertions(+), 48 deletions(-) diff --git a/rp2040-hal/examples/pio_blink.rs b/rp2040-hal/examples/pio_blink.rs index 7e7d14b..6e2b38d 100644 --- a/rp2040-hal/examples/pio_blink.rs +++ b/rp2040-hal/examples/pio_blink.rs @@ -57,7 +57,7 @@ fn main() -> ! { let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); let installed = pio.install(&program).unwrap(); let div = 0f32; // as slow as possible (0 is interpreted as 65536) - let sm = rp2040_hal::pio::PIOBuilder::from_program(installed) + let (sm, _, _) = rp2040_hal::pio::PIOBuilder::from_program(installed) .set_pins(led_pin_id, 1) .clock_divisor(div) .build(sm0); diff --git a/rp2040-hal/examples/pio_proc_blink.rs b/rp2040-hal/examples/pio_proc_blink.rs index 73942ba..7086e50 100644 --- a/rp2040-hal/examples/pio_proc_blink.rs +++ b/rp2040-hal/examples/pio_proc_blink.rs @@ -48,7 +48,7 @@ fn main() -> ! { let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); let installed = pio.install(&program.program).unwrap(); let div = 0f32; // as slow as possible (0 is interpreted as 65536) - let mut sm = rp2040_hal::pio::PIOBuilder::from_program(installed) + let (mut sm, _, _) = rp2040_hal::pio::PIOBuilder::from_program(installed) .set_pins(led_pin_id, 1) .clock_divisor(div) .build(sm0); diff --git a/rp2040-hal/src/pio.rs b/rp2040-hal/src/pio.rs index 9a8d3a7..498b1fe 100644 --- a/rp2040-hal/src/pio.rs +++ b/rp2040-hal/src/pio.rs @@ -225,9 +225,9 @@ impl PIO

{ /// // Install a program in instruction memory. /// let installed = pio.install(&program).unwrap(); /// // Configure a state machine to use the program. -/// let sm = rp2040_hal::pio::PIOBuilder::from_program(installed).build(sm0); +/// let (sm, rx, tx) = rp2040_hal::pio::PIOBuilder::from_program(installed).build(sm0); /// // Uninitialize the state machine again, freeing the program. -/// let (sm, installed) = sm.uninit(); +/// let (sm, installed) = sm.uninit(rx, tx); /// // Uninstall the program to free instruction memory. /// pio.uninstall(installed); /// ``` @@ -451,7 +451,11 @@ impl StateMachine { /// /// The program can be uninstalled to free space once it is no longer used by any state /// machine. - pub fn uninit(mut self) -> (UninitStateMachine, InstalledProgram) { + pub fn uninit( + mut self, + _rx: Rx, + _tx: Tx, + ) -> (UninitStateMachine, InstalledProgram) { self.sm.set_enabled(false); (self.sm, self.program) } @@ -471,44 +475,6 @@ impl StateMachine { pub fn stalled(&self) -> bool { self.sm.sm().sm_execctrl.read().exec_stalled().bits() } - - /// Get the next element from RX FIFO. - /// - /// Returns `None` if the FIFO is empty. - pub fn read_rx(&mut self) -> Option { - // Safety: The register is never written by software. - let is_empty = - unsafe { &*self.sm.block }.fstat.read().rxempty().bits() & (1 << SM::id()) != 0; - - if is_empty { - return None; - } - - // Safety: The register is unique to this state machine. - Some( - unsafe { &*self.sm.block }.rxf[SM::id() as usize] - .read() - .bits(), - ) - } - - /// Write an element to TX FIFO. - /// - /// Returns `true` if the value was written to FIFO, `false` otherwise. - pub fn write_tx(&mut self, value: u32) -> bool { - // Safety: The register is never written by software. - let is_full = - unsafe { &*self.sm.block }.fstat.read().txfull().bits() & (1 << SM::id()) != 0; - - if is_full { - return false; - } - - // Safety: The register is unique to this state machine. - unsafe { &*self.sm.block }.txf[SM::id()].write(|w| unsafe { w.bits(value) }); - - true - } } impl StateMachine { @@ -650,6 +616,54 @@ impl StateMachine { } } +/// PIO RX FIFO handle. +pub struct Rx { + block: *const rp2040_pac::pio0::RegisterBlock, + _phantom: core::marker::PhantomData, +} + +impl Rx { + /// Get the next element from RX FIFO. + /// + /// Returns `None` if the FIFO is empty. + pub fn read_rx(&mut self) -> Option { + // Safety: The register is never written by software. + let is_empty = unsafe { &*self.block }.fstat.read().rxempty().bits() & (1 << SM::id()) != 0; + + if is_empty { + return None; + } + + // Safety: The register is unique to this Rx instance. + Some(unsafe { &*self.block }.rxf[SM::id() as usize].read().bits()) + } +} + +/// PIO TX FIFO handle. +pub struct Tx { + block: *const rp2040_pac::pio0::RegisterBlock, + _phantom: core::marker::PhantomData, +} + +impl Tx { + /// Write an element to TX FIFO. + /// + /// Returns `true` if the value was written to FIFO, `false` otherwise. + pub fn write_tx(&mut self, value: u32) -> bool { + // Safety: The register is never written by software. + let is_full = unsafe { &*self.block }.fstat.read().txfull().bits() & (1 << SM::id()) != 0; + + if is_full { + return false; + } + + // Safety: The register is unique to this Tx instance. + unsafe { &*self.block }.txf[SM::id()].write(|w| unsafe { w.bits(value) }); + + true + } +} + /// PIO Interrupt controller. #[derive(Debug)] pub struct Interrupt { @@ -1140,7 +1154,7 @@ impl PIOBuilder

{ pub fn build( self, mut sm: UninitStateMachine<(P, SM)>, - ) -> StateMachine<(P, SM), Stopped> { + ) -> (StateMachine<(P, SM), Stopped>, Rx<(P, SM)>, Tx<(P, SM)>) { let offset = self.program.offset; // Stop the SM @@ -1244,10 +1258,22 @@ impl PIOBuilder

{ .encode(), ); - StateMachine { - sm: sm, - program: self.program, + let rx = Rx { + block: sm.block, _phantom: core::marker::PhantomData, - } + }; + let tx = Tx { + block: sm.block, + _phantom: core::marker::PhantomData, + }; + ( + StateMachine { + sm: sm, + program: self.program, + _phantom: core::marker::PhantomData, + }, + rx, + tx, + ) } }