aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpennae <[email protected]>2023-05-02 12:52:29 +0200
committerpennae <[email protected]>2023-05-03 11:25:28 +0200
commit62841dd5b958fa2458aceb638a17d243e72d987f (patch)
tree1d11fb4edb9c2165bf6ae901002c7a1555514d9d
parent1e8da91defc2b5b328d733dedffc25893c786c1f (diff)
rp/pio: revert pio pin funcsel to null on pio+sms drop
once all sharing owners of pio pins have been dropped we should reset the pin for use by other hal objects. unfortunately this needs an atomic state per pio block because PioCommon and all of the state machines really do share ownership of any wrapped pins. only PioCommon can create them, but all state machines can keep them alive. since state machines can be moved to core1 we can't do reference counting in relaxed mode, but we *can* do relaxed pin accounting (since only common and the final drop can modify this).
-rw-r--r--embassy-rp/src/pio.rs67
1 files changed, 63 insertions, 4 deletions
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs
index 0616f6fc0..32e9be74d 100644
--- a/embassy-rp/src/pio.rs
+++ b/embassy-rp/src/pio.rs
@@ -4,9 +4,11 @@ use core::pin::Pin as FuturePin;
4use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{compiler_fence, Ordering};
5use core::task::{Context, Poll}; 5use core::task::{Context, Poll};
6 6
7use atomic_polyfill::{AtomicU32, AtomicU8};
7use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; 8use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
8use embassy_hal_common::{Peripheral, PeripheralRef}; 9use embassy_hal_common::{Peripheral, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
11use pac::io::vals::Gpio0ctrlFuncsel;
10 12
11use crate::dma::{Channel, Transfer, Word}; 13use crate::dma::{Channel, Transfer, Word};
12use crate::gpio::sealed::Pin as SealedPin; 14use crate::gpio::sealed::Pin as SealedPin;
@@ -320,6 +322,12 @@ pub struct PioStateMachineInstance<'d, PIO: PioInstance, const SM: usize> {
320 pio: PhantomData<&'d PIO>, 322 pio: PhantomData<&'d PIO>,
321} 323}
322 324
325impl<'d, PIO: PioInstance, const SM: usize> Drop for PioStateMachineInstance<'d, PIO, SM> {
326 fn drop(&mut self) {
327 on_pio_drop::<PIO>();
328 }
329}
330
323impl<'d, PIO: PioInstance, const SM: usize> sealed::PioStateMachine for PioStateMachineInstance<'d, PIO, SM> { 331impl<'d, PIO: PioInstance, const SM: usize> sealed::PioStateMachine for PioStateMachineInstance<'d, PIO, SM> {
324 type Pio = PIO; 332 type Pio = PIO;
325 const SM: usize = SM; 333 const SM: usize = SM;
@@ -794,6 +802,12 @@ pub struct PioCommon<'d, PIO: PioInstance> {
794 pio: PhantomData<&'d PIO>, 802 pio: PhantomData<&'d PIO>,
795} 803}
796 804
805impl<'d, PIO: PioInstance> Drop for PioCommon<'d, PIO> {
806 fn drop(&mut self) {
807 on_pio_drop::<PIO>();
808 }
809}
810
797pub struct PioInstanceMemory<'d, PIO: PioInstance> { 811pub struct PioInstanceMemory<'d, PIO: PioInstance> {
798 used_mask: u32, 812 used_mask: u32,
799 pio: PhantomData<&'d PIO>, 813 pio: PhantomData<&'d PIO>,
@@ -870,10 +884,15 @@ impl<'d, PIO: PioInstance> PioCommon<'d, PIO> {
870 unsafe { PIO::PIO.input_sync_bypass().read() } 884 unsafe { PIO::PIO.input_sync_bypass().read() }
871 } 885 }
872 886
873 pub fn make_pio_pin(&self, pin: impl Pin) -> PioPin<PIO> { 887 /// Register a pin for PIO usage. Pins will be released from the PIO block
888 /// (i.e., have their `FUNCSEL` reset to `NULL`) when the [`PioCommon`] *and*
889 /// all [`PioStateMachine`]s for this block have been dropped.
890 pub fn make_pio_pin(&mut self, pin: impl Pin) -> PioPin<PIO> {
874 unsafe { 891 unsafe {
875 pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0)); 892 pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0));
876 } 893 }
894 // we can be relaxed about this because we're &mut here and nothing is cached
895 PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed);
877 PioPin { 896 PioPin {
878 pin_bank: pin.pin_bank(), 897 pin_bank: pin.pin_bank(),
879 pio: PhantomData::default(), 898 pio: PhantomData::default(),
@@ -891,6 +910,8 @@ pub struct Pio<'d, PIO: PioInstance> {
891 910
892impl<'d, PIO: PioInstance> Pio<'d, PIO> { 911impl<'d, PIO: PioInstance> Pio<'d, PIO> {
893 pub fn new(_pio: impl Peripheral<P = PIO> + 'd) -> Self { 912 pub fn new(_pio: impl Peripheral<P = PIO> + 'd) -> Self {
913 PIO::state().users.store(5, Ordering::Release);
914 PIO::state().used_pins.store(0, Ordering::Release);
894 Self { 915 Self {
895 common: PioCommon { 916 common: PioCommon {
896 instructions_used: 0, 917 instructions_used: 0,
@@ -904,13 +925,35 @@ impl<'d, PIO: PioInstance> Pio<'d, PIO> {
904 } 925 }
905} 926}
906 927
907pub trait PioInstance: sealed::PioInstance + Sized + Unpin { 928// we need to keep a record of which pins are assigned to each PIO. make_pio_pin
908 fn pio(&self) -> u8 { 929// notionally takes ownership of the pin it is given, but the wrapped pin cannot
909 Self::PIO_NO 930// be treated as an owned resource since dropping it would have to deconfigure
931// the pin, breaking running state machines in the process. pins are also shared
932// between all state machines, which makes ownership even messier to track any
933// other way.
934pub struct State {
935 users: AtomicU8,
936 used_pins: AtomicU32,
937}
938
939fn on_pio_drop<PIO: PioInstance>() {
940 let state = PIO::state();
941 if state.users.fetch_sub(1, Ordering::AcqRel) == 1 {
942 let used_pins = state.used_pins.load(Ordering::Relaxed);
943 let null = Gpio0ctrlFuncsel::NULL.0;
944 for i in 0..32 {
945 if used_pins & (1 << i) != 0 {
946 unsafe {
947 pac::IO_BANK0.gpio(i).ctrl().write(|w| w.set_funcsel(null));
948 }
949 }
950 }
910 } 951 }
911} 952}
912 953
913mod sealed { 954mod sealed {
955 use super::*;
956
914 pub trait PioStateMachine { 957 pub trait PioStateMachine {
915 type Pio: super::PioInstance; 958 type Pio: super::PioInstance;
916 const SM: usize; 959 const SM: usize;
@@ -925,6 +968,22 @@ mod sealed {
925 const PIO_NO: u8; 968 const PIO_NO: u8;
926 const PIO: &'static crate::pac::pio::Pio; 969 const PIO: &'static crate::pac::pio::Pio;
927 const FUNCSEL: crate::pac::io::vals::Gpio0ctrlFuncsel; 970 const FUNCSEL: crate::pac::io::vals::Gpio0ctrlFuncsel;
971
972 #[inline]
973 fn state() -> &'static State {
974 static STATE: State = State {
975 users: AtomicU8::new(0),
976 used_pins: AtomicU32::new(0),
977 };
978
979 &STATE
980 }
981 }
982}
983
984pub trait PioInstance: sealed::PioInstance + Sized + Unpin {
985 fn pio(&self) -> u8 {
986 Self::PIO_NO
928 } 987 }
929} 988}
930 989