, S::Iterator<'a>>
@@ -1350,10 +1396,10 @@ pub mod continuous {
/// Initialize ADC continuous driver with configuration and channels.
#[cfg(esp32)]
pub fn new(
- adc: impl Peripheral + 'd,
- _i2s: impl Peripheral
+ 'd,
+ adc: super::ADC1<'d>,
+ _i2s: crate::i2s::I2S0<'d>,
config: &config::Config,
- channels: impl AdcChannels + 'd,
+ channels: impl AdcChannels + 'd,
) -> Result {
Self::internal_new(adc, config, channels)
}
@@ -1361,28 +1407,28 @@ pub mod continuous {
/// Initialize ADC continuous driver with configuration and channels
#[cfg(esp32s2)]
pub fn new(
- adc: impl Peripheral + 'd,
- _spi: impl Peripheral
+ 'd,
+ adc: super::ADC1<'d>,
+ _spi: crate::spi::SPI3<'d>,
config: &config::Config,
- channels: impl AdcChannels + 'd,
+ channels: impl AdcChannels + 'd,
) -> Result {
Self::internal_new(adc, config, channels)
}
/// Initialize ADC continuous driver with configuration and channels.
#[cfg(not(any(esp32, esp32s2)))]
- pub fn new(
- adc: impl Peripheral + 'd,
+ pub fn new(
+ adc: A,
config: &config::Config,
- channels: impl AdcChannels + 'd,
+ channels: impl AdcChannels + 'd,
) -> Result {
Self::internal_new(adc, config, channels)
}
- fn internal_new(
- _adc: impl Peripheral + 'd,
+ fn internal_new(
+ _adc: A,
config: &config::Config,
- channels: impl AdcChannels + 'd,
+ channels: impl AdcChannels + 'd,
) -> Result {
let mut patterns = [adc_digi_pattern_config_t::default(); 32];
diff --git a/src/can.rs b/src/can.rs
index 61e2bf9d1..5c105c297 100644
--- a/src/can.rs
+++ b/src/can.rs
@@ -44,7 +44,6 @@ use esp_idf_sys::*;
use crate::cpu::Core;
use crate::delay::{self, BLOCK, NON_BLOCK};
use crate::interrupt::InterruptType;
-use crate::peripheral::{Peripheral, PeripheralRef};
use crate::task::asynch::Notification;
use crate::{gpio::*, task};
@@ -384,22 +383,20 @@ pub enum Alert {
}
/// CAN abstraction
-pub struct CanDriver<'d>(PeripheralRef<'d, CAN>, EnumSet, bool);
+pub struct CanDriver<'d>(PhantomData<&'d mut ()>, EnumSet, bool);
impl<'d> CanDriver<'d> {
pub fn new(
- can: impl Peripheral + 'd,
- tx: impl Peripheral
+ 'd,
- rx: impl Peripheral
+ 'd,
+ _can: CAN<'d>,
+ tx: impl OutputPin + 'd,
+ rx: impl InputPin + 'd,
config: &config::Config,
) -> Result {
- crate::into_ref!(can, tx, rx);
-
#[allow(clippy::needless_update)]
let general_config = twai_general_config_t {
mode: config.mode.into(),
- tx_io: tx.pin(),
- rx_io: rx.pin(),
+ tx_io: tx.pin() as _,
+ rx_io: rx.pin() as _,
clkout_io: -1,
bus_off_io: -1,
tx_queue_len: config.tx_queue_len,
@@ -438,7 +435,7 @@ impl<'d> CanDriver<'d> {
esp!(unsafe { twai_driver_install(&general_config, &timing_config, &filter_config) })?;
- Ok(Self(can, config.alerts, config.tx_queue_len > 0))
+ Ok(Self(PhantomData, config.alerts, config.tx_queue_len > 0))
}
pub fn start(&mut self) -> Result<(), EspError> {
@@ -571,9 +568,9 @@ where
impl<'d> AsyncCanDriver<'d, CanDriver<'d>> {
pub fn new(
- can: impl Peripheral + 'd,
- tx: impl Peripheral
+ 'd,
- rx: impl Peripheral
+ 'd,
+ can: CAN<'d>,
+ tx: impl OutputPin + 'd,
+ rx: impl InputPin + 'd,
config: &config::Config,
) -> Result {
Self::wrap(CanDriver::new(can, tx, rx, config)?)
diff --git a/src/gpio.rs b/src/gpio.rs
index 9830206a5..aa0a9f379 100644
--- a/src/gpio.rs
+++ b/src/gpio.rs
@@ -7,61 +7,55 @@ extern crate alloc;
use esp_idf_sys::*;
-use crate::adc::Adc;
-use crate::peripheral::{Peripheral, PeripheralRef};
+use crate::adc::AdcChannel;
pub use chip::*;
+pub type PinId = u8;
+
/// A trait implemented by every pin instance
-pub trait Pin: Peripheral + Sized + Send + 'static {
- fn pin(&self) -> i32;
+pub trait Pin: Sized + Send {
+ /// Return the pin ID
+ fn pin(&self) -> PinId;
}
/// A marker trait designating a pin which is capable of
/// operating as an input pin
-pub trait InputPin: Pin + Into {
- fn downgrade_input(self) -> AnyInputPin {
- self.into()
- }
-}
+pub trait InputPin: Pin {}
/// A marker trait designating a pin which is capable of
/// operating as an output pin
-pub trait OutputPin: Pin + Into {
- fn downgrade_output(self) -> AnyOutputPin {
- self.into()
- }
-}
-
-/// A marker trait designating a pin which is capable of
-/// operating as an input and output pin
-pub trait IOPin: InputPin + OutputPin + Into {
- fn downgrade(self) -> AnyIOPin {
- self.into()
- }
-}
+pub trait OutputPin: Pin {}
/// A marker trait designating a pin which is capable of
/// operating as an RTC pin
pub trait RTCPin: Pin {
- fn rtc_pin(&self) -> i32;
-}
-
-pub(crate) mod sealed {
- pub trait ADCPin {
- // NOTE: Will likely disappear in subsequent versions,
- // once ADC support pops up in e-hal1. Hence sealed
- const CHANNEL: super::adc_channel_t;
- }
+ /// Return the RTC pin ID
+ fn rtc_pin(&self) -> PinId;
}
/// A marker trait designating a pin which is capable of
/// operating as an ADC pin
-pub trait ADCPin: sealed::ADCPin + Pin {
- type Adc: Adc;
+pub trait ADCPin: Pin {
+ /// Return the ADC channel for this pin
+ type AdcChannel: AdcChannel;
+}
- fn adc_channel(&self) -> adc_channel_t {
- Self::CHANNEL
+/// A marker trait designating a pin which is capable of
+/// operating as a DAC pin
+#[cfg(any(esp32, esp32s2))]
+pub trait DacChannel: 'static {
+ /// Return the DAC channel for this pin
+ fn dac_channel(&self) -> dac_channel_t;
+}
+
+#[cfg(any(esp32, esp32s2))]
+pub struct DACCH;
+
+#[cfg(any(esp32, esp32s2))]
+impl DacChannel for DACCH {
+ fn dac_channel(&self) -> dac_channel_t {
+ N
}
}
@@ -69,135 +63,114 @@ pub trait ADCPin: sealed::ADCPin + Pin {
/// operating as a DAC pin
#[cfg(any(esp32, esp32s2))]
pub trait DACPin: Pin {
- fn dac_channel(&self) -> dac_channel_t;
+ /// Return the DAC channel for this pin
+ type DacChannel: DacChannel;
+}
+
+/// A marker trait designating a pin which is capable of
+/// operating as a touch pin
+#[cfg(any(esp32, esp32s2, esp32s3))]
+pub trait TouchChannel: 'static {
+ /// Return the touch channel for this pin
+ fn touch_channel(&self) -> touch_pad_t;
+}
+
+#[cfg(any(esp32, esp32s2, esp32s3))]
+pub struct TOUCHCH;
+
+#[cfg(any(esp32, esp32s2, esp32s3))]
+impl TouchChannel for TOUCHCH {
+ fn touch_channel(&self) -> touch_pad_t {
+ N
+ }
}
/// A marker trait designating a pin which is capable of
/// operating as a touch pin
#[cfg(any(esp32, esp32s2, esp32s3))]
pub trait TouchPin: Pin {
- fn touch_channel(&self) -> touch_pad_t;
+ /// Return the touch channel for this pin
+ type TouchChannel: TouchChannel;
}
-/// Generic Gpio input-output pin
-pub struct AnyIOPin {
- pin: i32,
- _p: PhantomData<*const ()>,
-}
-
-impl AnyIOPin {
- /// # Safety
- ///
- /// Care should be taken not to instantiate this Pin, if it is
- /// already instantiated and used elsewhere, or if it is not set
- /// already in the mode of operation which is being instantiated
- pub unsafe fn new(pin: i32) -> Self {
- Self {
- pin,
- _p: PhantomData,
+#[allow(unused_macros)]
+macro_rules! impl_any {
+ ($name:ident) => {
+ pub struct $name<'a> {
+ pin: PinId,
+ _t: ::core::marker::PhantomData<&'a mut ()>,
}
- }
- /// Creates an `Option::None` for pins that are
- /// optional in APIs.
- pub const fn none() -> Option {
- None
- }
-}
+ impl $name<'_> {
+ /// Unsafely create an instance of this peripheral out of thin air.
+ ///
+ /// # Safety
+ ///
+ /// You must ensure that you're only using one instance of this type at a time.
+ #[inline(always)]
+ pub unsafe fn steal(pin: PinId) -> Self {
+ Self {
+ pin,
+ _t: ::core::marker::PhantomData,
+ }
+ }
-crate::impl_peripheral_trait!(AnyIOPin);
+ /// Creates a new peripheral reference with a shorter lifetime.
+ ///
+ /// Use this method if you would like to keep working with the peripheral after
+ /// you dropped the driver that consumes this.
+ ///
+ /// # Safety
+ ///
+ /// You must ensure that you are not using reborrowed peripherals in drivers which are
+ /// forgotten via `core::mem::forget`.
+ #[inline]
+ #[allow(dead_code)]
+ pub unsafe fn reborrow(&mut self) -> $name<'_> {
+ $name {
+ pin: self.pin,
+ _t: ::core::marker::PhantomData,
+ }
+ }
-impl Pin for AnyIOPin {
- fn pin(&self) -> i32 {
- self.pin
- }
-}
-
-impl InputPin for AnyIOPin {}
-impl OutputPin for AnyIOPin {}
-impl IOPin for AnyIOPin {}
-
-/// Generic Gpio input pin
-pub struct AnyInputPin {
- pin: i32,
- _p: PhantomData<*const ()>,
-}
-
-impl AnyInputPin {
- /// # Safety
- ///
- /// Care should be taken not to instantiate this Pin, if it is
- /// already instantiated and used elsewhere, or if it is not set
- /// already in the mode of operation which is being instantiated
- pub unsafe fn new(pin: i32) -> Self {
- Self {
- pin,
- _p: PhantomData,
+ /// Return `Option::None` for an unconfigured instance of that pin
+ pub const fn none() -> Option {
+ None
+ }
}
- }
- /// Creates an `Option::None` for pins that are
- /// optional in APIs.
- pub const fn none() -> Option {
- None
- }
-}
+ unsafe impl Send for $name<'_> {}
-crate::impl_peripheral_trait!(AnyInputPin);
-
-impl Pin for AnyInputPin {
- fn pin(&self) -> i32 {
- self.pin
- }
-}
-
-impl InputPin for AnyInputPin {}
-
-impl From for AnyInputPin {
- fn from(pin: AnyIOPin) -> Self {
- unsafe { Self::new(pin.pin()) }
- }
-}
-
-/// Generic Gpio output pin
-pub struct AnyOutputPin {
- pin: i32,
- _p: PhantomData<*const ()>,
-}
-
-impl AnyOutputPin {
- /// # Safety
- ///
- /// Care should be taken not to instantiate this Pin, if it is
- /// already instantiated and used elsewhere, or if it is not set
- /// already in the mode of operation which is being instantiated
- pub unsafe fn new(pin: i32) -> Self {
- Self {
- pin,
- _p: PhantomData,
+ impl Pin for $name<'_> {
+ fn pin(&self) -> PinId {
+ self.pin as _
+ }
}
- }
+ };
+}
- /// Creates an `Option::None` for pins that are
- /// optional in APIs.
- pub const fn none() -> Option {
- None
+impl_any!(AnyIOPin);
+
+impl InputPin for AnyIOPin<'_> {}
+impl OutputPin for AnyIOPin<'_> {}
+
+impl_any!(AnyInputPin);
+
+impl InputPin for AnyInputPin<'_> {}
+
+impl<'a> From> for AnyInputPin<'a> {
+ fn from(pin: AnyIOPin<'a>) -> Self {
+ unsafe { Self::steal(pin.pin()) }
}
}
-crate::impl_peripheral_trait!(AnyOutputPin);
+impl_any!(AnyOutputPin);
-impl Pin for AnyOutputPin {
- fn pin(&self) -> i32 {
- self.pin
- }
-}
+impl OutputPin for AnyOutputPin<'_> {}
-impl OutputPin for AnyOutputPin {}
-
-impl From for AnyOutputPin {
- fn from(pin: AnyIOPin) -> Self {
- unsafe { Self::new(pin.pin()) }
+impl<'a> From> for AnyOutputPin<'a> {
+ fn from(pin: AnyIOPin<'a>) -> Self {
+ unsafe { Self::steal(pin.pin()) }
}
}
@@ -382,15 +355,17 @@ pub struct RtcOutput;
#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
pub struct RtcInputOutput;
+impl GPIOMode for Disabled {}
+
+impl GPIOMode for Input {}
+
impl InputMode for Input {
const RTC: bool = false;
}
-impl InputMode for InputOutput {
- const RTC: bool = false;
-}
+impl GPIOMode for InputOutput {}
-impl OutputMode for Output {
+impl InputMode for InputOutput {
const RTC: bool = false;
}
@@ -398,29 +373,10 @@ impl OutputMode for InputOutput {
const RTC: bool = false;
}
-impl GPIOMode for Disabled {}
-impl GPIOMode for Input {}
-impl GPIOMode for InputOutput {}
impl GPIOMode for Output {}
-#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
-impl InputMode for RtcInput {
- const RTC: bool = true;
-}
-
-#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
-impl InputMode for RtcInputOutput {
- const RTC: bool = true;
-}
-
-#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
-impl OutputMode for RtcOutput {
- const RTC: bool = true;
-}
-
-#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
-impl OutputMode for RtcInputOutput {
- const RTC: bool = true;
+impl OutputMode for Output {
+ const RTC: bool = false;
}
#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
@@ -429,12 +385,32 @@ impl RTCMode for RtcDisabled {}
#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
impl RTCMode for RtcInput {}
+#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
+impl InputMode for RtcInput {
+ const RTC: bool = true;
+}
+
#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
impl RTCMode for RtcInputOutput {}
+#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
+impl InputMode for RtcInputOutput {
+ const RTC: bool = true;
+}
+
+#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
+impl OutputMode for RtcInputOutput {
+ const RTC: bool = true;
+}
+
#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
impl RTCMode for RtcOutput {}
+#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
+impl OutputMode for RtcOutput {
+ const RTC: bool = true;
+}
+
/// A driver for a GPIO pin.
///
/// The driver can set the pin as a disconnected/disabled one, input, or output pin, or both or analog.
@@ -443,354 +419,283 @@ impl RTCMode for RtcOutput {}
///
/// The mode-setting depends on the capabilities of the pin as well, i.e. input-only pins cannot be set
/// into output or input-output mode.
-pub struct PinDriver<'d, T: Pin, MODE> {
- pin: PeripheralRef<'d, T>,
+pub struct PinDriver<'d, MODE> {
+ pin: PinId,
_mode: PhantomData,
+ _t: PhantomData<&'d mut ()>,
}
-impl<'d, T: Pin> PinDriver<'d, T, Disabled> {
- /// Creates the driver for a pin in disabled state.
+impl<'d, MODE> PinDriver<'d, MODE> {
+ /// Try to convert the pin driver into a disabled pin driver.
+ ///
+ /// Return an error if the pin cannot be disabled.
#[inline]
- pub fn disabled(pin: impl Peripheral + 'd) -> Result {
- crate::into_ref!(pin);
+ pub fn try_into_disabled(self) -> Result, EspError> {
+ PinDriver::new_gpio(self.pin as _, gpio_mode_t_GPIO_MODE_DISABLE)
+ }
- Self {
- pin,
- _mode: PhantomData,
- }
- .into_disabled()
+ /// Try to convert the pin driver into an input pin driver.
+ ///
+ /// Return an error if the pin cannot be set as input.
+ #[inline]
+ pub fn try_into_input(self, pull: Pull) -> Result, EspError> {
+ let mut pin = PinDriver::new_gpio(self.pin as _, gpio_mode_t_GPIO_MODE_INPUT)?;
+
+ pin.set_pull(pull)?;
+
+ Ok(pin)
+ }
+
+ /// Try to convert the pin driver into an output pin driver.
+ ///
+ /// Return an error if the pin cannot be set as output.
+ #[inline]
+ pub fn try_into_output(self) -> Result, EspError> {
+ PinDriver::new_gpio(self.pin as _, gpio_mode_t_GPIO_MODE_OUTPUT)
+ }
+
+ /// Try to convert the pin driver into an input-output pin driver.
+ ///
+ /// Return an error if the pin cannot be set as input-output.
+ #[inline]
+ pub fn try_into_input_output(self, pull: Pull) -> Result, EspError> {
+ let mut pin = PinDriver::new_gpio(self.pin as _, gpio_mode_t_GPIO_MODE_INPUT_OUTPUT)?;
+
+ pin.set_pull(pull)?;
+
+ Ok(pin)
+ }
+
+ /// Try to convert the pin driver into an output open-drain pin driver.
+ ///
+ /// Return an error if the pin cannot be set as output open-drain.
+ #[inline]
+ pub fn try_into_output_od(self) -> Result, EspError> {
+ PinDriver::new_gpio(self.pin as _, gpio_mode_t_GPIO_MODE_OUTPUT_OD)
+ }
+
+ /// Try to convert the pin driver into an input-output open-drain pin driver.
+ ///
+ /// Return an error if the pin cannot be set as input-output open-drain.
+ #[inline]
+ pub fn try_into_input_output_od(
+ self,
+ pull: Pull,
+ ) -> Result, EspError> {
+ let mut pin = PinDriver::new_gpio(self.pin as _, gpio_mode_t_GPIO_MODE_INPUT_OUTPUT_OD)?;
+
+ pin.set_pull(pull)?;
+
+ Ok(pin)
+ }
+
+ /// Try to convert the pin driver into an RTC disabled pin driver.
+ ///
+ /// Return an error if the pin cannot be disabled.
+ #[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
+ #[inline]
+ pub fn try_into_rtc_disabled(self) -> Result, EspError> {
+ PinDriver::new_rtc(self.pin as _, rtc_gpio_mode_t_RTC_GPIO_MODE_DISABLED)
+ }
+
+ /// Try to convert the pin driver into an RTC input pin driver.
+ ///
+ /// Return an error if the pin cannot be set as RTC input.
+ #[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
+ #[inline]
+ pub fn try_into_rtc_input(self, pull: Pull) -> Result, EspError> {
+ let mut pin = PinDriver::new_rtc(self.pin as _, rtc_gpio_mode_t_RTC_GPIO_MODE_INPUT_ONLY)?;
+
+ pin.set_pull(pull)?;
+
+ Ok(pin)
+ }
+
+ /// Try to convert the pin driver into an RTC output pin driver.
+ ///
+ /// Return an error if the pin cannot be set as RTC output.
+ #[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
+ #[inline]
+ pub fn try_into_rtc_output(self) -> Result, EspError> {
+ PinDriver::new_rtc(self.pin as _, rtc_gpio_mode_t_RTC_GPIO_MODE_OUTPUT_ONLY)
+ }
+
+ /// Try to convert the pin driver into an RTC output open-drain pin driver.
+ ///
+ /// Return an error if the pin cannot be set as RTC output open-drain.
+ #[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
+ #[inline]
+ pub fn try_into_rtc_output_od(self) -> Result, EspError> {
+ PinDriver::new_rtc(self.pin as _, rtc_gpio_mode_t_RTC_GPIO_MODE_OUTPUT_OD)
+ }
+
+ /// Try to convert the pin driver into an RTC input-output pin driver.
+ ///
+ /// Return an error if the pin cannot be set as RTC input-output.
+ #[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
+ #[inline]
+ pub fn try_into_rtc_input_output(
+ self,
+ pull: Pull,
+ ) -> Result, EspError> {
+ let mut pin =
+ PinDriver::new_rtc(self.pin as _, rtc_gpio_mode_t_RTC_GPIO_MODE_INPUT_OUTPUT)?;
+
+ pin.set_pull(pull)?;
+
+ Ok(pin)
+ }
+
+ /// Try to convert the pin driver into an RTC input-output open-drain pin driver.
+ ///
+ /// Return an error if the pin cannot be set as RTC input-output open-drain.
+ #[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
+ #[inline]
+ pub fn try_into_rtc_input_output_od(
+ self,
+ pull: Pull,
+ ) -> Result, EspError> {
+ let mut pin =
+ PinDriver::new_rtc(self.pin as _, rtc_gpio_mode_t_RTC_GPIO_MODE_INPUT_OUTPUT_OD)?;
+
+ pin.set_pull(pull)?;
+
+ Ok(pin)
}
}
-impl<'d, T: InputPin> PinDriver<'d, T, Input> {
+impl<'d> PinDriver<'d, Disabled> {
+ /// Creates the driver for a pin in disabled state.
+ #[inline]
+ pub fn disabled(pin: T) -> Result {
+ Self::new_gpio(pin.pin(), gpio_mode_t_GPIO_MODE_DISABLE)
+ }
+}
+
+impl<'d> PinDriver<'d, Input> {
/// Creates the driver for a pin in input state.
#[inline]
- pub fn input(pin: impl Peripheral + 'd) -> Result {
- crate::into_ref!(pin);
+ pub fn input(pin: T, pull: Pull) -> Result {
+ let mut pin = Self::new_gpio(pin.pin(), gpio_mode_t_GPIO_MODE_INPUT)?;
- Self {
- pin,
- _mode: PhantomData,
- }
- .into_input()
+ pin.set_pull(pull)?;
+
+ Ok(pin)
}
}
-impl<'d, T: InputPin + OutputPin> PinDriver<'d, T, InputOutput> {
+impl<'d> PinDriver<'d, InputOutput> {
/// Creates the driver for a pin in input-output state.
#[inline]
- pub fn input_output(pin: impl Peripheral + 'd) -> Result {
- crate::into_ref!(pin);
+ pub fn input_output(
+ pin: T,
+ pull: Pull,
+ ) -> Result {
+ let mut pin = Self::new_gpio(pin.pin(), gpio_mode_t_GPIO_MODE_INPUT_OUTPUT)?;
- Self {
- pin,
- _mode: PhantomData,
- }
- .into_input_output()
+ pin.set_pull(pull)?;
+
+ Ok(pin)
}
-}
-impl<'d, T: InputPin + OutputPin> PinDriver<'d, T, InputOutput> {
/// Creates the driver for a pin in input-output open-drain state.
#[inline]
- pub fn input_output_od(pin: impl Peripheral + 'd) -> Result {
- crate::into_ref!(pin);
+ pub fn input_output_od(
+ pin: T,
+ pull: Pull,
+ ) -> Result {
+ let mut pin = Self::new_gpio(pin.pin(), gpio_mode_t_GPIO_MODE_INPUT_OUTPUT_OD)?;
- Self {
- pin,
- _mode: PhantomData,
- }
- .into_input_output_od()
+ pin.set_pull(pull)?;
+
+ Ok(pin)
}
}
-impl<'d, T: OutputPin> PinDriver<'d, T, Output> {
+impl<'d> PinDriver<'d, Output> {
/// Creates the driver for a pin in output state.
#[inline]
- pub fn output(pin: impl Peripheral + 'd) -> Result {
- crate::into_ref!(pin);
-
- Self {
- pin,
- _mode: PhantomData,
- }
- .into_output()
+ pub fn output(pin: T) -> Result {
+ Self::new_gpio(pin.pin(), gpio_mode_t_GPIO_MODE_OUTPUT)
}
-}
-impl<'d, T: OutputPin> PinDriver<'d, T, Output> {
/// Creates the driver for a pin in output open-drain state.
#[inline]
- pub fn output_od(pin: impl Peripheral + 'd) -> Result {
- crate::into_ref!(pin);
-
- Self {
- pin,
- _mode: PhantomData,
- }
- .into_output_od()
+ pub fn output_od(pin: T) -> Result {
+ Self::new_gpio(pin.pin(), gpio_mode_t_GPIO_MODE_OUTPUT_OD)
}
}
#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
-impl<'d, T: Pin + RTCPin> PinDriver<'d, T, RtcDisabled> {
+impl<'d> PinDriver<'d, RtcDisabled> {
/// Creates the driver for a pin in disabled state.
#[inline]
- pub fn rtc_disabled(pin: impl Peripheral + 'd) -> Result {
- crate::into_ref!(pin);
-
- Self {
- pin,
- _mode: PhantomData,
- }
- .into_rtc_disabled()
+ pub fn rtc_disabled(pin: T) -> Result {
+ Self::new_rtc(pin.pin(), rtc_gpio_mode_t_RTC_GPIO_MODE_DISABLED)
}
}
#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
-impl<'d, T: InputPin + RTCPin> PinDriver<'d, T, RtcInput> {
+impl<'d> PinDriver<'d, RtcInput> {
/// Creates the driver for a pin in RTC input state.
#[inline]
- pub fn rtc_input(pin: impl Peripheral + 'd) -> Result {
- crate::into_ref!(pin);
+ pub fn rtc_input(pin: T, pull: Pull) -> Result {
+ let mut pin = Self::new_rtc(pin.pin(), rtc_gpio_mode_t_RTC_GPIO_MODE_INPUT_ONLY)?;
- Self {
- pin,
- _mode: PhantomData,
- }
- .into_rtc_input()
+ pin.set_pull(pull)?;
+
+ Ok(pin)
}
}
#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
-impl<'d, T: InputPin + OutputPin + RTCPin> PinDriver<'d, T, RtcInputOutput> {
+impl<'d> PinDriver<'d, RtcInputOutput> {
/// Creates the driver for a pin in RTC input-output state.
#[inline]
- pub fn rtc_input_output(pin: impl Peripheral + 'd) -> Result {
- crate::into_ref!(pin);
+ pub fn rtc_input_output(
+ pin: T,
+ pull: Pull,
+ ) -> Result {
+ let mut pin = Self::new_rtc(pin.pin(), rtc_gpio_mode_t_RTC_GPIO_MODE_INPUT_OUTPUT)?;
- Self {
- pin,
- _mode: PhantomData,
- }
- .into_rtc_input_output()
+ pin.set_pull(pull)?;
+
+ Ok(pin)
}
-}
-#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
-impl<'d, T: InputPin + OutputPin + RTCPin> PinDriver<'d, T, RtcInputOutput> {
/// Creates the driver for a pin in RTC input-output open-drain state.
#[inline]
- pub fn rtc_input_output_od(pin: impl Peripheral + 'd) -> Result {
- crate::into_ref!(pin);
+ pub fn rtc_input_output_od(
+ pin: T,
+ pull: Pull,
+ ) -> Result {
+ let mut pin = Self::new_rtc(pin.pin(), rtc_gpio_mode_t_RTC_GPIO_MODE_INPUT_OUTPUT_OD)?;
- Self {
- pin,
- _mode: PhantomData,
- }
- .into_rtc_input_output_od()
+ pin.set_pull(pull)?;
+
+ Ok(pin)
}
}
#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
-impl<'d, T: OutputPin + RTCPin> PinDriver<'d, T, RtcOutput> {
+impl<'d> PinDriver<'d, RtcOutput> {
/// Creates the driver for a pin in RTC output state.
#[inline]
- pub fn rtc_output(pin: impl Peripheral + 'd) -> Result {
- crate::into_ref!(pin);
-
- Self {
- pin,
- _mode: PhantomData,
- }
- .into_rtc_output()
+ pub fn rtc_output(pin: T) -> Result {
+ Self::new_rtc(pin.pin(), rtc_gpio_mode_t_RTC_GPIO_MODE_OUTPUT_ONLY)
}
-}
-#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
-impl<'d, T: OutputPin + RTCPin> PinDriver<'d, T, RtcOutput> {
/// Creates the driver for a pin in RTC output open-drain state.
#[inline]
- pub fn rtc_output_od(pin: impl Peripheral + 'd) -> Result {
- crate::into_ref!(pin);
-
- Self {
- pin,
- _mode: PhantomData,
- }
- .into_rtc_output_od()
+ pub fn rtc_output_od(pin: T) -> Result {
+ Self::new_rtc(pin.pin(), rtc_gpio_mode_t_RTC_GPIO_MODE_OUTPUT_OD)
}
}
-impl<'d, T: Pin, MODE> PinDriver<'d, T, MODE> {
+impl<'d, MODE> PinDriver<'d, MODE> {
/// Returns the pin number.
- pub fn pin(&self) -> i32 {
- self.pin.pin()
- }
-
- /// Put the pin into disabled mode.
- pub fn into_disabled(self) -> Result, EspError> {
- self.into_mode(gpio_mode_t_GPIO_MODE_DISABLE)
- }
-
- /// Put the pin into input mode.
- #[inline]
- pub fn into_input(self) -> Result, EspError>
- where
- T: InputPin,
- {
- self.into_mode(gpio_mode_t_GPIO_MODE_INPUT)
- }
-
- /// Put the pin into input + output mode.
- #[inline]
- pub fn into_input_output(self) -> Result, EspError>
- where
- T: InputPin + OutputPin,
- {
- self.into_mode(gpio_mode_t_GPIO_MODE_INPUT_OUTPUT)
- }
-
- /// Put the pin into input + output Open Drain mode.
- ///
- /// This is commonly used for "open drain" mode.
- /// the hardware will drive the line low if you set it to low, and will leave it floating if you set
- /// it to high, in which case you can read the input to figure out whether another device
- /// is driving the line low.
- #[inline]
- pub fn into_input_output_od(self) -> Result, EspError>
- where
- T: InputPin + OutputPin,
- {
- self.into_mode(gpio_mode_t_GPIO_MODE_INPUT_OUTPUT_OD)
- }
-
- /// Put the pin into output mode.
- #[inline]
- pub fn into_output(self) -> Result, EspError>
- where
- T: OutputPin,
- {
- self.into_mode(gpio_mode_t_GPIO_MODE_OUTPUT)
- }
-
- /// Put the pin into output Open Drain mode.
- #[inline]
- pub fn into_output_od(self) -> Result, EspError>
- where
- T: OutputPin,
- {
- self.into_mode(gpio_mode_t_GPIO_MODE_OUTPUT_OD)
- }
-
- /// Put the pin into RTC disabled mode.
- #[inline]
- #[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
- pub fn into_rtc_disabled(self) -> Result, EspError>
- where
- T: RTCPin,
- {
- self.into_rtc_mode(rtc_gpio_mode_t_RTC_GPIO_MODE_DISABLED)
- }
-
- /// Put the pin into RTC input mode.
- #[inline]
- #[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
- pub fn into_rtc_input(self) -> Result, EspError>
- where
- T: InputPin + RTCPin,
- {
- self.into_rtc_mode(rtc_gpio_mode_t_RTC_GPIO_MODE_INPUT_ONLY)
- }
-
- /// Put the pin into RTC input + output mode.
- ///
- /// This is commonly used for "open drain" mode.
- /// the hardware will drive the line low if you set it to low, and will leave it floating if you set
- /// it to high, in which case you can read the input to figure out whether another device
- /// is driving the line low.
- #[inline]
- #[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
- pub fn into_rtc_input_output(self) -> Result, EspError>
- where
- T: InputPin + OutputPin + RTCPin,
- {
- self.into_rtc_mode(rtc_gpio_mode_t_RTC_GPIO_MODE_INPUT_OUTPUT)
- }
-
- /// Put the pin into RTC input + output Open Drain mode.
- ///
- /// This is commonly used for "open drain" mode.
- /// the hardware will drive the line low if you set it to low, and will leave it floating if you set
- /// it to high, in which case you can read the input to figure out whether another device
- /// is driving the line low.
- #[inline]
- #[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
- pub fn into_rtc_input_output_od(self) -> Result, EspError>
- where
- T: InputPin + OutputPin + RTCPin,
- {
- self.into_rtc_mode(rtc_gpio_mode_t_RTC_GPIO_MODE_INPUT_OUTPUT_OD)
- }
-
- /// Put the pin into RTC output mode.
- #[inline]
- #[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
- pub fn into_rtc_output(self) -> Result, EspError>
- where
- T: OutputPin + RTCPin,
- {
- self.into_rtc_mode(rtc_gpio_mode_t_RTC_GPIO_MODE_OUTPUT_ONLY)
- }
-
- /// Put the pin into RTC output Open Drain mode.
- #[inline]
- #[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
- pub fn into_rtc_output_od(self) -> Result, EspError>
- where
- T: OutputPin + RTCPin,
- {
- self.into_rtc_mode(rtc_gpio_mode_t_RTC_GPIO_MODE_OUTPUT_OD)
- }
-
- #[inline]
- fn into_mode(mut self, mode: gpio_mode_t) -> Result, EspError>
- where
- T: Pin,
- {
- let pin = unsafe { self.pin.clone_unchecked() };
- drop(self);
-
- if mode != gpio_mode_t_GPIO_MODE_DISABLE {
- esp!(unsafe { gpio_set_direction(pin.pin(), mode) })?;
- }
-
- Ok(PinDriver {
- pin,
- _mode: PhantomData,
- })
- }
-
- #[inline]
- #[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
- fn into_rtc_mode(mut self, mode: rtc_gpio_mode_t) -> Result, EspError>
- where
- T: RTCPin,
- {
- let pin = unsafe { self.pin.clone_unchecked() };
-
- drop(self);
-
- #[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
- {
- esp!(unsafe { rtc_gpio_init(pin.pin()) })?;
- esp!(unsafe { rtc_gpio_set_direction(pin.pin(), mode) })?;
- }
-
- Ok(PinDriver {
- pin,
- _mode: PhantomData,
- })
+ pub fn pin(&self) -> PinId {
+ self.pin
}
#[inline]
@@ -802,12 +707,12 @@ impl<'d, T: Pin, MODE> PinDriver<'d, T, MODE> {
if MODE::RTC {
#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
- esp!(unsafe { rtc_gpio_get_drive_capability(self.pin.pin(), &mut cap) })?;
+ esp!(unsafe { rtc_gpio_get_drive_capability(self.pin as _, &mut cap) })?;
#[cfg(any(esp32c3, esp32c2, esp32h2, esp32c5))]
unreachable!();
} else {
- esp!(unsafe { gpio_get_drive_capability(self.pin.pin(), &mut cap) })?;
+ esp!(unsafe { gpio_get_drive_capability(self.pin as _, &mut cap) })?;
}
Ok(cap.into())
@@ -820,12 +725,12 @@ impl<'d, T: Pin, MODE> PinDriver<'d, T, MODE> {
{
if MODE::RTC {
#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
- esp!(unsafe { rtc_gpio_set_drive_capability(self.pin.pin(), strength.into()) })?;
+ esp!(unsafe { rtc_gpio_set_drive_capability(self.pin as _, strength.into()) })?;
#[cfg(any(esp32c3, esp32c2, esp32h2, esp32c5))]
unreachable!();
} else {
- esp!(unsafe { gpio_set_drive_capability(self.pin.pin(), strength.into()) })?;
+ esp!(unsafe { gpio_set_drive_capability(self.pin as _, strength.into()) })?;
}
Ok(())
@@ -857,7 +762,7 @@ impl<'d, T: Pin, MODE> PinDriver<'d, T, MODE> {
if MODE::RTC {
#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
{
- res = if unsafe { rtc_gpio_get_level(self.pin.pin()) } != 0 {
+ res = if unsafe { rtc_gpio_get_level(self.pin as _) } != 0 {
Level::High
} else {
Level::Low
@@ -866,7 +771,7 @@ impl<'d, T: Pin, MODE> PinDriver<'d, T, MODE> {
#[cfg(any(esp32c3, esp32c2, esp32h2, esp32c5))]
unreachable!();
- } else if unsafe { gpio_get_level(self.pin.pin()) } != 0 {
+ } else if unsafe { gpio_get_level(self.pin as _) } != 0 {
res = Level::High;
} else {
res = Level::Low;
@@ -900,7 +805,7 @@ impl<'d, T: Pin, MODE> PinDriver<'d, T, MODE> {
{
// TODO: Implement for RTC mode
- let pin = self.pin.pin() as u32;
+ let pin = self.pin as u32;
#[cfg(any(esp32c3, esp32c2, esp32h2, esp32c5))]
let is_set_high = unsafe { (*(GPIO_OUT_REG as *const u32) >> pin) & 0x01 != 0 };
@@ -949,12 +854,12 @@ impl<'d, T: Pin, MODE> PinDriver<'d, T, MODE> {
if MODE::RTC {
#[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
- esp!(unsafe { rtc_gpio_set_level(self.pin.pin(), on) })?;
+ esp!(unsafe { rtc_gpio_set_level(self.pin as _, on) })?;
#[cfg(any(esp32c3, esp32c2, esp32h2, esp32c5))]
unreachable!();
} else {
- esp!(unsafe { gpio_set_level(self.pin.pin(), on) })?;
+ esp!(unsafe { gpio_set_level(self.pin as _, on) })?;
}
Ok(())
@@ -973,9 +878,8 @@ impl<'d, T: Pin, MODE> PinDriver<'d, T, MODE> {
}
}
- pub fn set_pull(&mut self, pull: Pull) -> Result<(), EspError>
+ fn set_pull(&mut self, pull: Pull) -> Result<(), EspError>
where
- T: InputPin + OutputPin,
MODE: InputMode,
{
if MODE::RTC {
@@ -983,20 +887,20 @@ impl<'d, T: Pin, MODE> PinDriver<'d, T, MODE> {
unsafe {
match pull {
Pull::Down => {
- esp!(rtc_gpio_pulldown_en(self.pin.pin()))?;
- esp!(rtc_gpio_pullup_dis(self.pin.pin()))?;
+ esp!(rtc_gpio_pulldown_en(self.pin as _))?;
+ esp!(rtc_gpio_pullup_dis(self.pin as _))?;
}
Pull::Up => {
- esp!(rtc_gpio_pulldown_dis(self.pin.pin()))?;
- esp!(rtc_gpio_pullup_en(self.pin.pin()))?;
+ esp!(rtc_gpio_pulldown_dis(self.pin as _))?;
+ esp!(rtc_gpio_pullup_en(self.pin as _))?;
}
Pull::UpDown => {
- esp!(rtc_gpio_pulldown_en(self.pin.pin()))?;
- esp!(rtc_gpio_pullup_en(self.pin.pin()))?;
+ esp!(rtc_gpio_pulldown_en(self.pin as _))?;
+ esp!(rtc_gpio_pullup_en(self.pin as _))?;
}
Pull::Floating => {
- esp!(rtc_gpio_pulldown_dis(self.pin.pin()))?;
- esp!(rtc_gpio_pullup_dis(self.pin.pin()))?;
+ esp!(rtc_gpio_pulldown_dis(self.pin as _))?;
+ esp!(rtc_gpio_pullup_dis(self.pin as _))?;
}
}
}
@@ -1004,7 +908,7 @@ impl<'d, T: Pin, MODE> PinDriver<'d, T, MODE> {
#[cfg(any(esp32c3, esp32c2, esp32h2, esp32c5))]
unreachable!();
} else {
- esp!(unsafe { gpio_set_pull_mode(self.pin.pin(), pull.into()) })?;
+ esp!(unsafe { gpio_set_pull_mode(self.pin as _, pull.into()) })?;
}
Ok(())
@@ -1089,7 +993,7 @@ impl<'d, T: Pin, MODE> PinDriver<'d, T, MODE> {
let callback: alloc::boxed::Box = alloc::boxed::Box::new(callback);
unsafe {
- chip::PIN_ISR_HANDLER[self.pin.pin() as usize] = Some(core::mem::transmute::<
+ chip::PIN_ISR_HANDLER[self.pin as usize] = Some(core::mem::transmute::<
alloc::boxed::Box,
alloc::boxed::Box,
>(callback));
@@ -1103,7 +1007,7 @@ impl<'d, T: Pin, MODE> PinDriver<'d, T, MODE> {
MODE: InputMode,
{
unsafe {
- unsubscribe_pin(self.pin.pin())?;
+ unsubscribe_pin(self.pin as _)?;
}
Ok(())
@@ -1125,9 +1029,9 @@ impl<'d, T: Pin, MODE> PinDriver<'d, T, MODE> {
unsafe {
esp!(gpio_isr_handler_add(
- self.pin.pin(),
+ self.pin as _,
Some(Self::handle_isr),
- self.pin.pin() as u32 as *mut core::ffi::c_void,
+ self.pin as u32 as *mut core::ffi::c_void,
))
}
}
@@ -1139,7 +1043,7 @@ impl<'d, T: Pin, MODE> PinDriver<'d, T, MODE> {
use core::sync::atomic::Ordering;
if ISR_SERVICE_ENABLED.load(Ordering::SeqCst) {
- esp!(unsafe { gpio_isr_handler_remove(self.pin.pin()) })?;
+ esp!(unsafe { gpio_isr_handler_remove(self.pin as _) })?;
}
Ok(())
@@ -1149,11 +1053,43 @@ impl<'d, T: Pin, MODE> PinDriver<'d, T, MODE> {
where
MODE: InputMode,
{
- esp!(unsafe { gpio_set_intr_type(self.pin.pin(), interrupt_type.into()) })?;
+ esp!(unsafe { gpio_set_intr_type(self.pin as _, interrupt_type.into()) })?;
Ok(())
}
+ #[inline]
+ fn new_gpio(pin: PinId, mode: gpio_mode_t) -> Result
+ where
+ MODE: GPIOMode,
+ {
+ if mode != gpio_mode_t_GPIO_MODE_DISABLE {
+ esp!(unsafe { gpio_set_direction(pin as _, mode) })?;
+ }
+
+ Ok(Self {
+ pin,
+ _mode: PhantomData,
+ _t: PhantomData,
+ })
+ }
+
+ #[inline]
+ #[cfg(not(any(esp32c3, esp32c2, esp32h2, esp32c5)))]
+ fn new_rtc(pin: PinId, mode: rtc_gpio_mode_t) -> Result
+ where
+ MODE: RTCMode,
+ {
+ esp!(unsafe { rtc_gpio_init(pin as _) })?;
+ esp!(unsafe { rtc_gpio_set_direction(pin as _, mode) })?;
+
+ Ok(PinDriver {
+ pin,
+ _mode: PhantomData,
+ _t: PhantomData,
+ })
+ }
+
unsafe extern "C" fn handle_isr(user_ctx: *mut core::ffi::c_void) {
let pin = user_ctx as u32;
@@ -1173,11 +1109,11 @@ impl<'d, T: Pin, MODE> PinDriver<'d, T, MODE> {
}
}
-impl PinDriver<'_, T, MODE> {
+impl PinDriver<'_, MODE> {
pub async fn wait_for(&mut self, interrupt_type: InterruptType) -> Result<(), EspError> {
self.disable_interrupt()?;
- let notif = &chip::PIN_NOTIF[self.pin.pin() as usize];
+ let notif = &chip::PIN_NOTIF[self.pin as usize];
notif.reset();
@@ -1224,15 +1160,15 @@ impl PinDriver<'_, T, MODE> {
}
}
-impl Drop for PinDriver<'_, T, MODE> {
+impl Drop for PinDriver<'_, MODE> {
fn drop(&mut self) {
- gpio_reset_without_pull(self.pin.pin()).unwrap();
+ gpio_reset_without_pull(self.pin as _).unwrap();
}
}
-unsafe impl Send for PinDriver<'_, T, MODE> {}
+unsafe impl Send for PinDriver<'_, MODE> {}
-impl embedded_hal_0_2::digital::v2::InputPin for PinDriver<'_, T, MODE>
+impl