From c4d1eb492e25866f7722f6110731b10b9d09d430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Wed, 17 Apr 2024 18:07:42 +0200 Subject: [PATCH] Address gpio module todos (#1462) * Add `set_state` for GpioPin * `#![warn(missing_docs)]` for GPIO module * CHANGELOG.md --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/gpio/etm.rs | 2 + esp-hal/src/gpio/lp_io.rs | 1 + esp-hal/src/gpio/mod.rs | 115 +++++++++++++++++++++++++++++++++++-- esp-hal/src/gpio/rtc_io.rs | 1 + 5 files changed, 116 insertions(+), 4 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index a66ce451293..78501879aec 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Warn users when attempting to build using the `dev` profile (#1420) - Async uart now reports interrupt errors(overflow, glitch, frame error, parity) back to user of read/write. uart clock decimal part configured for c2,c3,s3 (#1168, #1445) - Add mechanism to configure UART source clock (#1416) +- `GpioPin` got a function `set_state(bool)` (#1462) ### Fixed diff --git a/esp-hal/src/gpio/etm.rs b/esp-hal/src/gpio/etm.rs index 3d5a3a5203e..163a03e302b 100644 --- a/esp-hal/src/gpio/etm.rs +++ b/esp-hal/src/gpio/etm.rs @@ -31,6 +31,7 @@ use crate::peripheral::{Peripheral, PeripheralRef}; /// All the GPIO ETM channels #[non_exhaustive] +#[allow(missing_docs)] pub struct GpioEtmChannels<'d> { _gpio_sd: PeripheralRef<'d, crate::peripherals::GPIO_SD>, pub channel0_task: GpioEtmTaskChannel<0>, @@ -52,6 +53,7 @@ pub struct GpioEtmChannels<'d> { } impl<'d> GpioEtmChannels<'d> { + /// Create a new instance pub fn new(peripheral: impl Peripheral

+ 'd) -> Self { crate::into_ref!(peripheral); diff --git a/esp-hal/src/gpio/lp_io.rs b/esp-hal/src/gpio/lp_io.rs index 4babee98e5f..fff66ecdac7 100644 --- a/esp-hal/src/gpio/lp_io.rs +++ b/esp-hal/src/gpio/lp_io.rs @@ -159,6 +159,7 @@ fn get_pin_reg(pin: u8) -> &'static crate::peripherals::lp_io::GPIO0 { /// Configures a pin for use as a low power pin pub trait IntoLowPowerPin { + /// Converts the pin into a low power pin fn into_low_power(self) -> LowPowerPin; } diff --git a/esp-hal/src/gpio/mod.rs b/esp-hal/src/gpio/mod.rs index abfa4b24524..885188684ec 100644 --- a/esp-hal/src/gpio/mod.rs +++ b/esp-hal/src/gpio/mod.rs @@ -21,6 +21,7 @@ //! ``` //! //! [embedded-hal]: https://docs.rs/embedded-hal/latest/embedded_hal/ +#![warn(missing_docs)] use core::{cell::Cell, marker::PhantomData}; @@ -52,21 +53,30 @@ pub const NO_PIN: Option = None; static USER_INTERRUPT_HANDLER: Mutex>> = Mutex::new(Cell::new(None)); +/// Event used to trigger interrupts. #[derive(Copy, Clone)] pub enum Event { + /// Interrupts trigger on rising pin edge. RisingEdge = 1, + /// Interrupts trigger on falling pin edge. FallingEdge = 2, + /// Interrupts trigger on either rising or falling pin edges. AnyEdge = 3, + /// Interrupts trigger on low level LowLevel = 4, + /// Interrupts trigger on high level HighLevel = 5, } +/// Unknown pin mode pub struct Unknown {} +/// Input pin mode pub struct Input { _mode: PhantomData, } +/// Inverted input pin mode pub struct InvertedInput { _mode: PhantomData, } @@ -89,20 +99,26 @@ impl InputMode for Unknown { const PIN_IS_INVERTED: bool = false; } +/// RTC input pin mode pub struct RTCInput { _mode: PhantomData, } +/// Floating mode pub struct Floating; +/// Pull-down mode pub struct PullDown; +/// Pull-up mode pub struct PullUp; +/// Output pin mode pub struct Output { _mode: PhantomData, } +/// Inverted output pin mode pub struct InvertedOutput { _mode: PhantomData, } @@ -125,16 +141,21 @@ impl OutputMode for Unknown { const PIN_IS_INVERTED: bool = false; } +/// RTC output pin mode pub struct RTCOutput { _mode: PhantomData, } +/// Open-drain mode pub struct OpenDrain; +/// Push-pull mode pub struct PushPull; +/// Analog mode pub struct Analog; +/// Alternate mode pub struct Alternate { _mode: PhantomData, } @@ -148,6 +169,8 @@ pub struct AF1; #[doc(hidden)] pub struct AF2; +/// Drive strength (values are approximates) +#[allow(missing_docs)] pub enum DriveStrength { I5mA = 0, I10mA = 1, @@ -155,7 +178,9 @@ pub enum DriveStrength { I40mA = 3, } +/// Alternate functions #[derive(PartialEq)] +#[allow(missing_docs)] pub enum AlternateFunction { Function0 = 0, Function1 = 1, @@ -165,19 +190,25 @@ pub enum AlternateFunction { Function5 = 5, } +/// RTC function #[derive(PartialEq)] +#[allow(missing_docs)] pub enum RtcFunction { Rtc = 0, Digital = 1, } +/// Trait implemented by RTC pins pub trait RTCPin: Pin { + /// RTC number of the pin #[cfg(xtensa)] fn rtc_number(&self) -> u8; + /// Configure the pin #[cfg(any(xtensa, esp32c6))] fn rtc_set_config(&mut self, input_enable: bool, mux: bool, func: RtcFunction); + /// Enable or disable PAD_HOLD fn rtcio_pad_hold(&mut self, enable: bool); /// # Safety @@ -188,21 +219,32 @@ pub trait RTCPin: Pin { unsafe fn apply_wakeup(&mut self, wakeup: bool, level: u8); } +/// Trait implemented by RTC pins which supporting internal pull-up / pull-down +/// resistors. pub trait RTCPinWithResistors: RTCPin { + /// Enable/disable the internal pull-up resistor fn rtcio_pullup(&mut self, enable: bool); + /// Enable/disable the internal pull-down resistor fn rtcio_pulldown(&mut self, enable: bool); } +/// Marker for RTC pins which support input mode pub trait RTCInputPin: RTCPin {} +/// Marker for RTC pins which support output mode pub trait RTCOutputPin: RTCPin {} +/// Marker for pins which support analog mode pub trait AnalogPin {} +/// Common trait implemented by pins pub trait Pin { + /// GPIO number fn number(&self) -> u8; + /// Enable/disable sleep-mode fn sleep_mode(&mut self, on: bool); + /// Configure the alternate function fn set_alternate_function(&mut self, alternate: AlternateFunction); /// Listen for interrupts @@ -232,17 +274,27 @@ pub trait Pin { fn clear_interrupt(&mut self); } +/// Trait implemented by pins which can be used as inputs pub trait InputPin: Pin { + /// Set the pin to input mode without internal pull-up / pull-down resistors fn set_to_input(&mut self) -> &mut Self; + /// Enable input for the pin fn enable_input(&mut self, on: bool) -> &mut Self; + /// Enable input in sleep mode for the pin fn enable_input_in_sleep_mode(&mut self, on: bool) -> &mut Self; + /// The current state of the input fn is_input_high(&self) -> bool; + /// Connect the pin to a peripheral input signal fn connect_input_to_peripheral(&mut self, signal: InputSignal) -> &mut Self; + /// Connect the pin to a peripheral input signal. + /// + /// Optionally invert the signal. When `force_via_gpio_mux` is true it will + /// won't use the alternate function even if it matches fn connect_input_to_peripheral_with_options( &mut self, signal: InputSignal, @@ -258,31 +310,59 @@ pub trait InputPin: Pin { fn disconnect_input_from_peripheral(&mut self, signal: InputSignal) -> &mut Self; } +/// Trait implemented by pins which can be used as outputs pub trait OutputPin: Pin { + /// Configure open-drain mode fn set_to_open_drain_output(&mut self) -> &mut Self; + /// Configure output mode fn set_to_push_pull_output(&mut self) -> &mut Self; + /// Enable/disable the pin as output fn enable_output(&mut self, on: bool) -> &mut Self; + /// Set the pin's level to high or low fn set_output_high(&mut self, on: bool) -> &mut Self; + /// Configure the [DriveStrength] of the pin fn set_drive_strength(&mut self, strength: DriveStrength) -> &mut Self; + /// Enable/disable open-drain mode fn enable_open_drain(&mut self, on: bool) -> &mut Self; + /// Enable/disable output in sleep mode fn enable_output_in_sleep_mode(&mut self, on: bool) -> &mut Self; + /// Configure internal pull-up resistor in sleep mode fn internal_pull_up_in_sleep_mode(&mut self, on: bool) -> &mut Self; + /// Configure internal pull-down resistor in sleep mode fn internal_pull_down_in_sleep_mode(&mut self, on: bool) -> &mut Self; + /// Enable/disable internal pull-up resistor for normal operation fn internal_pull_up(&mut self, on: bool) -> &mut Self; + /// Enable/disable internal pull-down resistor for normal operation fn internal_pull_down(&mut self, on: bool) -> &mut Self; + /// Connect the pin to a peripheral output signal fn connect_peripheral_to_output(&mut self, signal: OutputSignal) -> &mut Self; + /// Connect the pin to a peripheral output signal. + /// + /// invert: Configures whether or not to invert the output value + /// + /// invert_enable: Configures whether or not to invert the output enable + /// signal + /// + /// enable_from_gpio: Configures to select the source of output enable + /// signal. + /// - false = Use output enable signal from peripheral + /// - true = Force the output enable signal to be sourced from bit n of + /// GPIO_ENABLE_REG + /// + /// force_via_gpio_mux: if true don't use the alternate function even if it + /// matches fn connect_peripheral_to_output_with_options( &mut self, signal: OutputSignal, @@ -479,6 +559,7 @@ impl BankGpioRegisterAccess for Bank1GpioRegisterAccess { } } +/// Connect an always-low signal to the peripheral input signal pub fn connect_low_to_peripheral(signal: InputSignal) { unsafe { &*GPIO::PTR } .func_in_sel_cfg(signal as usize - FUNC_IN_SEL_OFFSET) @@ -492,6 +573,7 @@ pub fn connect_low_to_peripheral(signal: InputSignal) { }); } +/// Connect an always-high signal to the peripheral input signal pub fn connect_high_to_peripheral(signal: InputSignal) { unsafe { &*GPIO::PTR } .func_in_sel_cfg(signal as usize - FUNC_IN_SEL_OFFSET) @@ -545,6 +627,7 @@ impl PinType for InputOnlyAnalogPinType {} impl IsInputPin for InputOnlyAnalogPinType {} impl IsAnalogPin for InputOnlyAnalogPinType {} +/// GPIO pin pub struct GpioPin { _mode: PhantomData, } @@ -884,8 +967,14 @@ where ::Bank::write_output_clear(1 << (GPIONUM % 32)); } - // TODO: add `set_state(PinState)` - // Drives the pin high or low depending on the provided value. + /// Drives the pin high or low depending on the provided value. + #[inline] + pub fn set_state(&mut self, state: bool) { + match state { + true => self.set_high(), + false => self.set_low(), + } + } /// Is the pin in drive high mode? #[inline] @@ -1382,6 +1471,7 @@ where } impl AnyPin { + /// Convert the pin pub fn into_input_type(self) -> AnyPin { AnyPin { inner: self.inner, @@ -1391,6 +1481,7 @@ impl AnyPin { } impl AnyPin { + /// Convert the pin pub fn into_input_type(self) -> AnyPin { AnyPin { inner: self.inner, @@ -1398,6 +1489,7 @@ impl AnyPin { } } + /// Convert the pin pub fn into_input_output_type(self) -> AnyPin { AnyPin { inner: self.inner, @@ -1405,6 +1497,7 @@ impl AnyPin { } } + /// Convert the pin pub fn into_input_only_analog_type(self) -> AnyPin { AnyPin { inner: self.inner, @@ -1414,6 +1507,7 @@ impl AnyPin { } impl AnyPin { + /// Convert the pin pub fn into_input_type(self) -> AnyPin { AnyPin { inner: self.inner, @@ -1720,8 +1814,12 @@ impl AnyPin, TYPE> { handle_gpio_output!(inner, target, { target.set_high() }) } - // TODO: add `set_state(PinState)` - // Drives the pin high or low depending on the provided value. + /// Drives the pin high or low depending on the provided value. + #[inline] + pub fn set_state(&mut self, state: bool) { + let inner = &mut self.inner; + handle_gpio_output!(inner, target, { target.set_state(state) }) + } /// Is the pin in drive high mode? #[inline] @@ -1782,6 +1880,7 @@ impl AnyPin, TYPE> { /// General Purpose Input/Output driver pub struct IO { _io_mux: IO_MUX, + /// The pins available on this chip pub pins: Pins, } @@ -1836,6 +1935,7 @@ extern "C" fn gpio_interrupt_handler() { asynch::handle_gpio_interrupt(); } +#[doc(hidden)] pub trait GpioProperties { type Bank: BankGpioRegisterAccess; type InterruptStatus: InterruptStatusRegisterAccess; @@ -1884,6 +1984,7 @@ macro_rules! gpio { type PinType = $crate::gpio::[<$type PinType>]; } + #[doc(hidden)] pub struct [] {} impl $crate::gpio::GpioSignal for [] { @@ -1914,6 +2015,8 @@ macro_rules! gpio { } )+ + /// Pins available on this chip + #[allow(missing_docs)] pub struct Pins { $( pub [< gpio $gpionum >] : GpioPin, @@ -1921,6 +2024,7 @@ macro_rules! gpio { } $( + #[doc = concat!("Alias for GpioPin")] pub type [] = GpioPin; )+ @@ -1930,6 +2034,9 @@ macro_rules! gpio { )+ } + /// Generic pin + /// + /// This is useful e.g. if you need an array of pins. pub struct AnyPin { pub(crate) inner: ErasedPin, pub(crate) _type: core::marker::PhantomData, diff --git a/esp-hal/src/gpio/rtc_io.rs b/esp-hal/src/gpio/rtc_io.rs index f81fdff9302..c77f449cda9 100644 --- a/esp-hal/src/gpio/rtc_io.rs +++ b/esp-hal/src/gpio/rtc_io.rs @@ -33,6 +33,7 @@ pub struct LowPowerPin { /// Configures a pin for use as a low power pin pub trait IntoLowPowerPin { + /// Convert into low power pin fn into_low_power(self) -> LowPowerPin; }