Support inverted pins (#912)

* Support inverted pins

* CHANGELOG.md entry

* Improve docs

* Provide `From`/`Into` for inverted pins
This commit is contained in:
Björn Quentin 2023-11-09 08:45:13 +01:00 committed by GitHub
parent 594bc65793
commit 0659928930
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 182 additions and 19 deletions

View File

@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- ESP32-C6: LP core clock is configurable (#907)
- Derive `Clone` and `Copy` for `EspTwaiFrame` (#914)
- A way to configure inverted pins (#912)
### Changed

View File

@ -51,6 +51,28 @@ pub struct Input<MODE> {
_mode: PhantomData<MODE>,
}
pub struct InvertedInput<MODE> {
_mode: PhantomData<MODE>,
}
/// Used to decide if the pin is inverted or not when the pin gets connected to
/// a peripheral
trait InputMode {
const PIN_IS_INVERTED: bool;
}
impl<MODE> InputMode for Input<MODE> {
const PIN_IS_INVERTED: bool = false;
}
impl<MODE> InputMode for InvertedInput<MODE> {
const PIN_IS_INVERTED: bool = true;
}
impl InputMode for Unknown {
const PIN_IS_INVERTED: bool = false;
}
pub struct RTCInput<MODE> {
_mode: PhantomData<MODE>,
}
@ -65,6 +87,28 @@ pub struct Output<MODE> {
_mode: PhantomData<MODE>,
}
pub struct InvertedOutput<MODE> {
_mode: PhantomData<MODE>,
}
/// Used to decide if the pin is inverted or not when the pin gets connected to
/// a peripheral
trait OutputMode {
const PIN_IS_INVERTED: bool;
}
impl<MODE> OutputMode for Output<MODE> {
const PIN_IS_INVERTED: bool = false;
}
impl<MODE> OutputMode for InvertedOutput<MODE> {
const PIN_IS_INVERTED: bool = true;
}
impl OutputMode for Unknown {
const PIN_IS_INVERTED: bool = false;
}
pub struct RTCOutput<MODE> {
_mode: PhantomData<MODE>,
}
@ -170,9 +214,7 @@ pub trait InputPin: Pin {
fn is_input_high(&self) -> bool;
fn connect_input_to_peripheral(&mut self, signal: InputSignal) -> &mut Self {
self.connect_input_to_peripheral_with_options(signal, false, false)
}
fn connect_input_to_peripheral(&mut self, signal: InputSignal) -> &mut Self;
fn connect_input_to_peripheral_with_options(
&mut self,
@ -208,9 +250,11 @@ pub trait OutputPin: Pin {
fn internal_pull_down_in_sleep_mode(&mut self, on: bool) -> &mut Self;
fn connect_peripheral_to_output(&mut self, signal: OutputSignal) -> &mut Self {
self.connect_peripheral_to_output_with_options(signal, false, false, false, false)
}
fn internal_pull_up(&mut self, on: bool) -> &mut Self;
fn internal_pull_down(&mut self, on: bool) -> &mut Self;
fn connect_peripheral_to_output(&mut self, signal: OutputSignal) -> &mut Self;
fn connect_peripheral_to_output_with_options(
&mut self,
@ -227,10 +271,6 @@ pub trait OutputPin: Pin {
/// pin with a previously connected [signal](`InputSignal`). Any other
/// outputs connected to the signal remain intact.
fn disconnect_peripheral_from_output(&mut self) -> &mut Self;
fn internal_pull_up(&mut self, on: bool) -> &mut Self;
fn internal_pull_down(&mut self, on: bool) -> &mut Self;
}
#[doc(hidden)]
@ -578,25 +618,50 @@ where
});
}
/// Configures the pin to operate as a floating input pin
pub fn into_floating_input(self) -> GpioPin<Input<Floating>, GPIONUM> {
self.init_input(false, false);
GpioPin { _mode: PhantomData }
}
/// Configures the pin to operate as a pulled up input pin
pub fn into_pull_up_input(self) -> GpioPin<Input<PullUp>, GPIONUM> {
self.init_input(false, true);
GpioPin { _mode: PhantomData }
}
/// Configures the pin to operate as a pulled down input pin
pub fn into_pull_down_input(self) -> GpioPin<Input<PullDown>, GPIONUM> {
self.init_input(true, false);
GpioPin { _mode: PhantomData }
}
/// Configures the pin to operate as an inverted floating input pin.
/// Only suitable to be passed into a peripheral driver.
pub fn into_inverted_floating_input(self) -> GpioPin<InvertedInput<Floating>, GPIONUM> {
self.init_input(false, false);
GpioPin { _mode: PhantomData }
}
/// Configures the pin to operate as an inverted pulled up input pin.
/// Only suitable to be passed into a peripheral driver.
pub fn into_inverted_pull_up_input(self) -> GpioPin<InvertedInput<PullUp>, GPIONUM> {
self.init_input(false, true);
GpioPin { _mode: PhantomData }
}
/// Configures the pin to operate as an inverted pulled down input pin.
/// Only suitable to be passed into a peripheral driver.
pub fn into_inverted_pull_down_input(self) -> GpioPin<InvertedInput<PullDown>, GPIONUM> {
self.init_input(true, false);
GpioPin { _mode: PhantomData }
}
}
impl<MODE, const GPIONUM: u8> InputPin for GpioPin<MODE, GPIONUM>
where
Self: GpioProperties,
MODE: InputMode,
{
fn set_to_input(&mut self) -> &mut Self {
self.init_input(false, false);
@ -613,6 +678,15 @@ where
fn is_input_high(&self) -> bool {
<Self as GpioProperties>::Bank::read_input() & (1 << (GPIONUM % 32)) != 0
}
fn connect_input_to_peripheral(&mut self, signal: InputSignal) -> &mut Self {
self.connect_input_to_peripheral_with_options(
signal,
MODE::PIN_IS_INVERTED,
MODE::PIN_IS_INVERTED,
)
}
fn connect_input_to_peripheral_with_options(
&mut self,
signal: InputSignal,
@ -864,6 +938,18 @@ where
}
}
impl<const GPIONUM: u8> From<GpioPin<Unknown, GPIONUM>>
for GpioPin<InvertedInput<Floating>, GPIONUM>
where
Self: GpioProperties,
<Self as GpioProperties>::PinType: IsInputPin,
GpioPin<Unknown, GPIONUM>: GpioProperties,
{
fn from(pin: GpioPin<Unknown, GPIONUM>) -> Self {
pin.into_inverted_floating_input()
}
}
impl<const GPIONUM: u8> From<GpioPin<Unknown, GPIONUM>> for GpioPin<Input<PullUp>, GPIONUM>
where
Self: GpioProperties,
@ -875,6 +961,17 @@ where
}
}
impl<const GPIONUM: u8> From<GpioPin<Unknown, GPIONUM>> for GpioPin<InvertedInput<PullUp>, GPIONUM>
where
Self: GpioProperties,
<Self as GpioProperties>::PinType: IsOutputPin,
GpioPin<Unknown, GPIONUM>: GpioProperties,
{
fn from(pin: GpioPin<Unknown, GPIONUM>) -> Self {
pin.into_inverted_pull_up_input()
}
}
impl<const GPIONUM: u8> From<GpioPin<Unknown, GPIONUM>> for GpioPin<Input<PullDown>, GPIONUM>
where
Self: GpioProperties,
@ -886,6 +983,18 @@ where
}
}
impl<const GPIONUM: u8> From<GpioPin<Unknown, GPIONUM>>
for GpioPin<InvertedInput<PullDown>, GPIONUM>
where
Self: GpioProperties,
<Self as GpioProperties>::PinType: IsInputPin,
GpioPin<Unknown, GPIONUM>: GpioProperties,
{
fn from(pin: GpioPin<Unknown, GPIONUM>) -> Self {
pin.into_inverted_pull_down_input()
}
}
impl<const GPIONUM: u8> From<GpioPin<Unknown, GPIONUM>> for GpioPin<Output<PushPull>, GPIONUM>
where
Self: GpioProperties,
@ -898,6 +1007,19 @@ where
}
}
impl<const GPIONUM: u8> From<GpioPin<Unknown, GPIONUM>>
for GpioPin<InvertedOutput<PushPull>, GPIONUM>
where
Self: GpioProperties,
<Self as GpioProperties>::PinType: IsOutputPin,
GpioPin<Unknown, GPIONUM>: GpioProperties,
<GpioPin<Unknown, GPIONUM> as GpioProperties>::PinType: IsOutputPin,
{
fn from(pin: GpioPin<Unknown, GPIONUM>) -> Self {
pin.into_inverted_push_pull_output()
}
}
impl<const GPIONUM: u8> From<GpioPin<Unknown, GPIONUM>> for GpioPin<Analog, GPIONUM>
where
Self: GpioProperties,
@ -922,6 +1044,19 @@ where
}
}
impl<const GPIONUM: u8> From<GpioPin<Unknown, GPIONUM>>
for GpioPin<InvertedOutput<OpenDrain>, GPIONUM>
where
Self: GpioProperties,
<Self as GpioProperties>::PinType: IsOutputPin,
GpioPin<Unknown, GPIONUM>: GpioProperties,
<GpioPin<Unknown, GPIONUM> as GpioProperties>::PinType: IsOutputPin,
{
fn from(pin: GpioPin<Unknown, GPIONUM>) -> Self {
pin.into_inverted_open_drain_output()
}
}
impl<const GPIONUM: u8> From<GpioPin<Unknown, GPIONUM>> for GpioPin<Alternate<AF1>, GPIONUM>
where
Self: GpioProperties,
@ -993,16 +1128,32 @@ where
});
}
/// Configures the pin to operate as an push pull output pin
pub fn into_push_pull_output(self) -> GpioPin<Output<PushPull>, GPIONUM> {
self.init_output(GPIO_FUNCTION, false);
GpioPin { _mode: PhantomData }
}
/// Configures the pin to operate as an open drain output pin
pub fn into_open_drain_output(self) -> GpioPin<Output<OpenDrain>, GPIONUM> {
self.init_output(GPIO_FUNCTION, true);
GpioPin { _mode: PhantomData }
}
/// Configures the pin to operate as an inverted push pull output pin.
/// Only suitable to be passed into an peripheral driver
pub fn into_inverted_push_pull_output(self) -> GpioPin<InvertedOutput<PushPull>, GPIONUM> {
self.init_output(GPIO_FUNCTION, false);
GpioPin { _mode: PhantomData }
}
/// Configures the pin to operate as an open drain output pin.
/// Only suitable to be passed into an peripheral driver
pub fn into_inverted_open_drain_output(self) -> GpioPin<InvertedOutput<OpenDrain>, GPIONUM> {
self.init_output(GPIO_FUNCTION, true);
GpioPin { _mode: PhantomData }
}
pub fn into_alternate_1(self) -> GpioPin<Alternate<AF1>, GPIONUM> {
self.init_output(AlternateFunction::Function1, false);
GpioPin { _mode: PhantomData }
@ -1018,6 +1169,7 @@ impl<MODE, const GPIONUM: u8> OutputPin for GpioPin<MODE, GPIONUM>
where
Self: GpioProperties,
<Self as GpioProperties>::PinType: IsOutputPin,
MODE: OutputMode,
{
fn set_to_open_drain_output(&mut self) -> &mut Self {
self.init_output(GPIO_FUNCTION, true);
@ -1071,6 +1223,25 @@ where
self
}
fn internal_pull_up(&mut self, on: bool) -> &mut Self {
get_io_mux_reg(GPIONUM).modify(|_, w| w.fun_wpu().bit(on));
self
}
fn internal_pull_down(&mut self, on: bool) -> &mut Self {
get_io_mux_reg(GPIONUM).modify(|_, w| w.fun_wpd().bit(on));
self
}
fn connect_peripheral_to_output(&mut self, signal: OutputSignal) -> &mut Self {
self.connect_peripheral_to_output_with_options(
signal,
MODE::PIN_IS_INVERTED,
false,
false,
MODE::PIN_IS_INVERTED,
)
}
fn connect_peripheral_to_output_with_options(
&mut self,
signal: OutputSignal,
@ -1132,15 +1303,6 @@ where
.modify(|_, w| unsafe { w.out_sel().bits(OutputSignal::GPIO as OutputSignalType) });
self
}
fn internal_pull_up(&mut self, on: bool) -> &mut Self {
get_io_mux_reg(GPIONUM).modify(|_, w| w.fun_wpu().bit(on));
self
}
fn internal_pull_down(&mut self, on: bool) -> &mut Self {
get_io_mux_reg(GPIONUM).modify(|_, w| w.fun_wpd().bit(on));
self
}
}
impl<MODE, const GPIONUM: u8> GpioPin<MODE, GPIONUM>