mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-10-02 14:44:42 +00:00
Refactor GPIO module to make traits accessible in esp-hal-common crate (#9)
* Extract all of the enums/structs/traits that we easily can from gpio! * Pull the remaining traits (which we're able to) out of gpio!
This commit is contained in:
parent
70109ffe36
commit
ef5d1ac7f4
@ -6,247 +6,179 @@
|
|||||||
//!
|
//!
|
||||||
//! [embedded-hal]: https://docs.rs/embedded-hal/latest/embedded_hal/
|
//! [embedded-hal]: https://docs.rs/embedded-hal/latest/embedded_hal/
|
||||||
|
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
pub use paste::paste;
|
pub use paste::paste;
|
||||||
|
|
||||||
#[macro_export]
|
#[derive(Copy, Clone)]
|
||||||
macro_rules! impl_output {
|
pub enum Event {
|
||||||
(
|
RisingEdge = 1,
|
||||||
$gpio_function:ident,
|
FallingEdge = 2,
|
||||||
$pxi:ident:
|
AnyEdge = 3,
|
||||||
(
|
LowLevel = 4,
|
||||||
$pin_num:expr, $iomux_reg:expr, $bit:expr, $out_en_set:ident,
|
HighLevel = 5,
|
||||||
$out_en_clear:ident, $out_set:ident, $out_clear:ident, $out_reg:ident
|
}
|
||||||
)
|
|
||||||
$( ,( $( $af_signal:ident: $af:ident ),* ))?
|
|
||||||
) => {
|
|
||||||
impl<MODE> embedded_hal::digital::v2::OutputPin for $pxi<Output<MODE>> {
|
|
||||||
type Error = Infallible;
|
|
||||||
|
|
||||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
pub struct Unknown {}
|
||||||
unsafe { (*GPIO::ptr()).$out_set.write(|w| w.bits(1 << $bit)) };
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_low(&mut self) -> Result<(), Self::Error> {
|
pub struct Input<MODE> {
|
||||||
unsafe { (*GPIO::ptr()).$out_clear.write(|w| w.bits(1 << $bit)) };
|
_mode: PhantomData<MODE>,
|
||||||
Ok(())
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<MODE> embedded_hal::digital::v2::StatefulOutputPin for $pxi<Output<MODE>> {
|
pub struct RTCInput<MODE> {
|
||||||
fn is_set_high(&self) -> Result<bool, Self::Error> {
|
_mode: PhantomData<MODE>,
|
||||||
unsafe { Ok((*GPIO::ptr()).$out_reg.read().bits() & (1 << $bit) != 0) }
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn is_set_low(&self) -> Result<bool, Self::Error> {
|
pub struct Floating;
|
||||||
Ok(!self.is_set_high()?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<MODE> embedded_hal::digital::v2::ToggleableOutputPin for $pxi<Output<MODE>> {
|
pub struct PullDown;
|
||||||
type Error = Infallible;
|
|
||||||
|
|
||||||
fn toggle(&mut self) -> Result<(), Self::Error> {
|
pub struct PullUp;
|
||||||
if self.is_set_high()? {
|
|
||||||
Ok(self.set_low()?)
|
|
||||||
} else {
|
|
||||||
Ok(self.set_high()?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<MODE> $pxi<MODE> {
|
pub struct Output<MODE> {
|
||||||
pub fn into_pull_up_input(self) -> $pxi<Input<PullUp>> {
|
_mode: PhantomData<MODE>,
|
||||||
self.init_input(false, false);
|
}
|
||||||
$pxi { _mode: PhantomData }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_pull_down_input(self) -> $pxi<Input<PullDown>> {
|
pub struct RTCOutput<MODE> {
|
||||||
self.init_input(true, false);
|
_mode: PhantomData<MODE>,
|
||||||
$pxi { _mode: PhantomData }
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn init_output(&self, alternate: AlternateFunction, open_drain: bool) {
|
pub struct OpenDrain;
|
||||||
let gpio = unsafe { &*GPIO::ptr() };
|
|
||||||
let iomux = unsafe { &*IO_MUX::ptr() };
|
|
||||||
|
|
||||||
gpio.$out_en_set.write(|w| unsafe { w.bits(1 << $bit) });
|
pub struct PushPull;
|
||||||
gpio.pin[$pin_num].modify(|_, w| w.pin_pad_driver().bit(open_drain));
|
|
||||||
gpio.func_out_sel_cfg[$pin_num]
|
|
||||||
.modify(|_, w| unsafe { w.out_sel().bits(OutputSignal::GPIO as OutputSignalType) });
|
|
||||||
|
|
||||||
paste! {
|
pub struct Analog;
|
||||||
iomux.$iomux_reg.modify(|_, w| unsafe {
|
|
||||||
w.mcu_sel()
|
|
||||||
.bits(alternate as u8)
|
|
||||||
.fun_ie()
|
|
||||||
.clear_bit()
|
|
||||||
.fun_wpd()
|
|
||||||
.clear_bit()
|
|
||||||
.fun_wpu()
|
|
||||||
.clear_bit()
|
|
||||||
.fun_drv()
|
|
||||||
.bits(DriveStrength::I20mA as u8)
|
|
||||||
.slp_sel()
|
|
||||||
.clear_bit()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_push_pull_output(self) -> $pxi<Output<PushPull>> {
|
pub struct Alternate<MODE> {
|
||||||
self.init_output(AlternateFunction::$gpio_function, false);
|
_mode: PhantomData<MODE>,
|
||||||
$pxi { _mode: PhantomData }
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_open_drain_output(self) -> $pxi<Output<OpenDrain>> {
|
pub struct AF0;
|
||||||
self.init_output(AlternateFunction::$gpio_function, true);
|
|
||||||
$pxi { _mode: PhantomData }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_alternate_1(self) -> $pxi<Alternate<AF1>> {
|
pub struct AF1;
|
||||||
self.init_output(AlternateFunction::Function1, false);
|
|
||||||
$pxi { _mode: PhantomData }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_alternate_2(self) -> $pxi<Alternate<AF2>> {
|
pub struct AF2;
|
||||||
self.init_output(AlternateFunction::Function2, false);
|
|
||||||
$pxi { _mode: PhantomData }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<MODE> OutputPin for $pxi<MODE> {
|
pub enum DriveStrength {
|
||||||
fn set_to_open_drain_output(&mut self) -> &mut Self {
|
I5mA = 0,
|
||||||
self.init_output(AlternateFunction::$gpio_function, true);
|
I10mA = 1,
|
||||||
self
|
I20mA = 2,
|
||||||
}
|
I40mA = 3,
|
||||||
|
}
|
||||||
|
|
||||||
fn set_to_push_pull_output(&mut self) -> &mut Self {
|
#[derive(PartialEq)]
|
||||||
self.init_output(AlternateFunction::$gpio_function, false);
|
pub enum AlternateFunction {
|
||||||
self
|
Function0 = 0,
|
||||||
}
|
Function1 = 1,
|
||||||
|
Function2 = 2,
|
||||||
|
Function3 = 3,
|
||||||
|
Function4 = 4,
|
||||||
|
Function5 = 5,
|
||||||
|
}
|
||||||
|
|
||||||
fn enable_output(&mut self, on: bool) -> &mut Self {
|
pub trait RTCPin {}
|
||||||
if on {
|
|
||||||
unsafe { &*GPIO::ptr() }
|
|
||||||
.$out_en_set
|
|
||||||
.write(|w| unsafe { w.bits(1 << $bit) });
|
|
||||||
} else {
|
|
||||||
unsafe { &*GPIO::ptr() }
|
|
||||||
.$out_en_clear
|
|
||||||
.write(|w| unsafe { w.bits(1 << $bit) });
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_output_high(&mut self, high: bool) -> &mut Self {
|
pub trait AnalogPin {}
|
||||||
if high {
|
|
||||||
unsafe { (*GPIO::ptr()).$out_set.write(|w| w.bits(1 << $bit)) };
|
|
||||||
} else {
|
|
||||||
unsafe { (*GPIO::ptr()).$out_clear.write(|w| w.bits(1 << $bit)) };
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_drive_strength(&mut self, strength: DriveStrength) -> &mut Self {
|
pub trait Pin {
|
||||||
paste! {
|
fn sleep_mode(&mut self, on: bool) -> &mut Self;
|
||||||
unsafe { &*IO_MUX::ptr() }
|
|
||||||
.$iomux_reg
|
|
||||||
.modify(|_, w| unsafe { w.fun_drv().bits(strength as u8) });
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enable_open_drain(&mut self, on: bool) -> &mut Self {
|
fn set_alternate_function(&mut self, alternate: AlternateFunction) -> &mut Self;
|
||||||
unsafe { &*GPIO::ptr() }.pin[$pin_num].modify(|_, w| w.pin_pad_driver().bit(on));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn internal_pull_up_in_sleep_mode(&mut self, on: bool) -> &mut Self {
|
fn listen(&mut self, event: Event) {
|
||||||
paste! {
|
self.listen_with_options(event, true, false, false)
|
||||||
unsafe { &*IO_MUX::ptr() }
|
}
|
||||||
.$iomux_reg
|
|
||||||
.modify(|_, w| w.mcu_wpu().bit(on));
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn internal_pull_down_in_sleep_mode(&mut self, on: bool) -> &mut Self {
|
fn listen_with_options(
|
||||||
paste!{
|
&mut self,
|
||||||
unsafe { &*IO_MUX::ptr() }
|
event: Event,
|
||||||
.$iomux_reg
|
int_enable: bool,
|
||||||
.modify(|_, w| w.mcu_wpd().bit(on));
|
nmi_enable: bool,
|
||||||
}
|
wake_up_from_light_sleep: bool,
|
||||||
self
|
);
|
||||||
}
|
|
||||||
|
|
||||||
fn enable_output_in_sleep_mode(&mut self, on: bool) -> &mut Self {
|
fn unlisten(&mut self);
|
||||||
paste! {
|
|
||||||
unsafe { &*IO_MUX::ptr() }
|
|
||||||
.$iomux_reg
|
|
||||||
.modify(|_, w| w.mcu_oe().bit(on));
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn connect_peripheral_to_output_with_options(
|
fn clear_interrupt(&mut self);
|
||||||
&mut self,
|
|
||||||
signal: OutputSignal,
|
|
||||||
invert: bool,
|
|
||||||
invert_enable: bool,
|
|
||||||
enable_from_gpio: bool,
|
|
||||||
force_via_gpio_mux: bool,
|
|
||||||
) -> &mut Self {
|
|
||||||
let af = if force_via_gpio_mux {
|
|
||||||
AlternateFunction::$gpio_function
|
|
||||||
} else {
|
|
||||||
match signal {
|
|
||||||
$( $(
|
|
||||||
OutputSignal::$af_signal => AlternateFunction::$af,
|
|
||||||
)* )?
|
|
||||||
_ => AlternateFunction::$gpio_function
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if af == AlternateFunction::$gpio_function && signal as usize > OUTPUT_SIGNAL_MAX as usize {
|
fn is_pcore_interrupt_set(&mut self) -> bool;
|
||||||
panic!("Cannot connect this peripheral to GPIO");
|
|
||||||
}
|
|
||||||
|
|
||||||
self.set_alternate_function(af);
|
fn is_pcore_non_maskable_interrupt_set(&mut self) -> bool;
|
||||||
|
|
||||||
let clipped_signal = if signal as usize <= OUTPUT_SIGNAL_MAX as usize { signal as OutputSignalType } else { OUTPUT_SIGNAL_MAX };
|
fn is_acore_interrupt_set(&mut self) -> bool;
|
||||||
|
|
||||||
unsafe { &*GPIO::ptr() }.func_out_sel_cfg[$pin_num].modify(|_, w| unsafe {
|
fn is_acore_non_maskable_interrupt_set(&mut self) -> bool;
|
||||||
w
|
|
||||||
.out_sel().bits(clipped_signal)
|
|
||||||
.inv_sel().bit(invert)
|
|
||||||
.oen_sel().bit(enable_from_gpio)
|
|
||||||
.oen_inv_sel().bit(invert_enable)
|
|
||||||
});
|
|
||||||
|
|
||||||
self
|
fn enable_hold(&mut self, on: bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn internal_pull_up(&mut self, on: bool) -> &mut Self {
|
pub trait InputPin: Pin {
|
||||||
paste!{
|
type InputSignal;
|
||||||
unsafe { &*IO_MUX::ptr() }.$iomux_reg.modify(|_, w| w.fun_wpu().bit(on));
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn internal_pull_down(&mut self, on: bool) -> &mut Self {
|
fn set_to_input(&mut self) -> &mut Self;
|
||||||
paste! {
|
|
||||||
unsafe { &*IO_MUX::ptr() }.$iomux_reg.modify(|_, w| w.fun_wpd().bit(on));
|
fn enable_input(&mut self, on: bool) -> &mut Self;
|
||||||
}
|
|
||||||
self
|
fn enable_input_in_sleep_mode(&mut self, on: bool) -> &mut Self;
|
||||||
}
|
|
||||||
}
|
fn is_input_high(&mut self) -> bool;
|
||||||
};
|
|
||||||
|
fn connect_input_to_peripheral(&mut self, signal: Self::InputSignal) -> &mut Self {
|
||||||
|
self.connect_input_to_peripheral_with_options(signal, false, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn connect_input_to_peripheral_with_options(
|
||||||
|
&mut self,
|
||||||
|
signal: Self::InputSignal,
|
||||||
|
invert: bool,
|
||||||
|
force_via_gpio_mux: bool,
|
||||||
|
) -> &mut Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait OutputPin: Pin {
|
||||||
|
type OutputSignal;
|
||||||
|
|
||||||
|
fn set_to_open_drain_output(&mut self) -> &mut Self;
|
||||||
|
|
||||||
|
fn set_to_push_pull_output(&mut self) -> &mut Self;
|
||||||
|
|
||||||
|
fn enable_output(&mut self, on: bool) -> &mut Self;
|
||||||
|
|
||||||
|
fn set_output_high(&mut self, on: bool) -> &mut Self;
|
||||||
|
|
||||||
|
fn set_drive_strength(&mut self, strength: DriveStrength) -> &mut Self;
|
||||||
|
|
||||||
|
fn enable_open_drain(&mut self, on: bool) -> &mut Self;
|
||||||
|
|
||||||
|
fn enable_output_in_sleep_mode(&mut self, on: bool) -> &mut Self;
|
||||||
|
|
||||||
|
fn internal_pull_up_in_sleep_mode(&mut self, on: bool) -> &mut Self;
|
||||||
|
|
||||||
|
fn internal_pull_down_in_sleep_mode(&mut self, on: bool) -> &mut Self;
|
||||||
|
|
||||||
|
fn connect_peripheral_to_output(&mut self, signal: Self::OutputSignal) -> &mut Self {
|
||||||
|
self.connect_peripheral_to_output_with_options(signal, false, false, false, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn connect_peripheral_to_output_with_options(
|
||||||
|
&mut self,
|
||||||
|
signal: Self::OutputSignal,
|
||||||
|
invert: bool,
|
||||||
|
invert_enable: bool,
|
||||||
|
enable_from_gpio: bool,
|
||||||
|
force_via_gpio_mux: bool,
|
||||||
|
) -> &mut Self;
|
||||||
|
|
||||||
|
fn internal_pull_up(&mut self, on: bool) -> &mut Self;
|
||||||
|
|
||||||
|
fn internal_pull_down(&mut self, on: bool) -> &mut Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! impl_input {
|
macro_rules! impl_input {
|
||||||
(
|
(
|
||||||
$gpio_function:ident,
|
$gpio_function:ident,
|
||||||
|
$input_signal:ty,
|
||||||
$pxi:ident:
|
$pxi:ident:
|
||||||
(
|
(
|
||||||
$pin_num:expr, $iomux_reg:expr, $bit:expr, $out_en_clear:ident,
|
$pin_num:expr, $iomux_reg:expr, $bit:expr, $out_en_clear:ident,
|
||||||
@ -301,6 +233,8 @@ macro_rules! impl_input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<MODE> InputPin for $pxi<MODE> {
|
impl<MODE> InputPin for $pxi<MODE> {
|
||||||
|
type InputSignal = $input_signal;
|
||||||
|
|
||||||
fn set_to_input(&mut self) -> &mut Self {
|
fn set_to_input(&mut self) -> &mut Self {
|
||||||
self.init_input(false, false);
|
self.init_input(false, false);
|
||||||
self
|
self
|
||||||
@ -330,17 +264,16 @@ macro_rules! impl_input {
|
|||||||
|
|
||||||
fn connect_input_to_peripheral_with_options(
|
fn connect_input_to_peripheral_with_options(
|
||||||
&mut self,
|
&mut self,
|
||||||
signal: InputSignal,
|
signal: Self::InputSignal,
|
||||||
invert: bool,
|
invert: bool,
|
||||||
force_via_gpio_mux: bool,
|
force_via_gpio_mux: bool,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
|
|
||||||
let af = if force_via_gpio_mux {
|
let af = if force_via_gpio_mux {
|
||||||
AlternateFunction::$gpio_function
|
AlternateFunction::$gpio_function
|
||||||
} else {
|
} else {
|
||||||
match signal {
|
match signal {
|
||||||
$( $(
|
$( $(
|
||||||
InputSignal::$af_signal => AlternateFunction::$af,
|
Self::InputSignal::$af_signal => AlternateFunction::$af,
|
||||||
)* )?
|
)* )?
|
||||||
_ => AlternateFunction::$gpio_function
|
_ => AlternateFunction::$gpio_function
|
||||||
}
|
}
|
||||||
@ -444,11 +377,13 @@ macro_rules! impl_input {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! impl_input_wrap {
|
macro_rules! impl_input_wrap {
|
||||||
(
|
(
|
||||||
$gpio_function:ident, $pxi:ident, $pin_num:expr, $iomux_reg:expr, $type:ident, Bank0, SingleCore
|
$gpio_function:ident,
|
||||||
|
$pxi:ident, $pin_num:expr, $iomux_reg:expr, $type:ident, Bank0, SingleCore
|
||||||
$( ,( $( $af_input_signal:ident : $af_input:ident ),* ) )?
|
$( ,( $( $af_input_signal:ident : $af_input:ident ),* ) )?
|
||||||
) => {
|
) => {
|
||||||
impl_input!(
|
impl_input!(
|
||||||
$gpio_function,
|
$gpio_function,
|
||||||
|
InputSignal,
|
||||||
$pxi:
|
$pxi:
|
||||||
(
|
(
|
||||||
$pin_num, $iomux_reg, $pin_num % 32, enable_w1tc, in_, data_next,
|
$pin_num, $iomux_reg, $pin_num % 32, enable_w1tc, in_, data_next,
|
||||||
@ -459,11 +394,13 @@ macro_rules! impl_input_wrap {
|
|||||||
};
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
$gpio_function:ident, $pxi:ident, $pin_num:expr, $iomux_reg:expr, $type:ident, Bank1, SingleCore
|
$gpio_function:ident,
|
||||||
|
$pxi:ident, $pin_num:expr, $iomux_reg:expr, $type:ident, Bank1, SingleCore
|
||||||
$( ,( $( $af_input_signal:ident : $af_input:ident ),* ) )?
|
$( ,( $( $af_input_signal:ident : $af_input:ident ),* ) )?
|
||||||
) => {
|
) => {
|
||||||
impl_input!(
|
impl_input!(
|
||||||
$gpio_function,
|
$gpio_function,
|
||||||
|
InputSignal,
|
||||||
$pxi:
|
$pxi:
|
||||||
(
|
(
|
||||||
$pin_num, $iomux_reg, $pin_num % 32, enable1_w1tc, in1, data_next,
|
$pin_num, $iomux_reg, $pin_num % 32, enable1_w1tc, in1, data_next,
|
||||||
@ -474,11 +411,13 @@ macro_rules! impl_input_wrap {
|
|||||||
};
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
$gpio_function:ident, $pxi:ident, $pin_num:expr, $iomux_reg:expr, $type:ident, Bank0, DualCore
|
$gpio_function:ident,
|
||||||
|
$pxi:ident, $pin_num:expr, $iomux_reg:expr, $type:ident, Bank0, DualCore
|
||||||
$( ,( $( $af_input_signal:ident : $af_input:ident ),* ) )?
|
$( ,( $( $af_input_signal:ident : $af_input:ident ),* ) )?
|
||||||
) => {
|
) => {
|
||||||
impl_input!(
|
impl_input!(
|
||||||
$gpio_function,
|
$gpio_function,
|
||||||
|
InputSignal,
|
||||||
$pxi:
|
$pxi:
|
||||||
(
|
(
|
||||||
$pin_num, $iomux_reg, $pin_num % 32, enable_w1tc, in_, data_next,
|
$pin_num, $iomux_reg, $pin_num % 32, enable_w1tc, in_, data_next,
|
||||||
@ -489,11 +428,13 @@ macro_rules! impl_input_wrap {
|
|||||||
};
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
$gpio_function:ident, $pxi:ident, $pin_num:expr, $iomux_reg:expr, $type:ident, Bank1, DualCore
|
$gpio_function:ident,
|
||||||
|
$pxi:ident, $pin_num:expr, $iomux_reg:expr, $type:ident, Bank1, DualCore
|
||||||
$( ,( $( $af_input_signal:ident : $af_input:ident ),* ) )?
|
$( ,( $( $af_input_signal:ident : $af_input:ident ),* ) )?
|
||||||
) => {
|
) => {
|
||||||
impl_input!(
|
impl_input!(
|
||||||
$gpio_function,
|
$gpio_function,
|
||||||
|
InputSignal,
|
||||||
$pxi:
|
$pxi:
|
||||||
(
|
(
|
||||||
$pin_num, $iomux_reg, $pin_num % 32, enable1_w1tc, in1, data_next,
|
$pin_num, $iomux_reg, $pin_num % 32, enable1_w1tc, in1, data_next,
|
||||||
@ -504,14 +445,255 @@ macro_rules! impl_input_wrap {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! impl_output {
|
||||||
|
(
|
||||||
|
$gpio_function:ident,
|
||||||
|
$output_signal:ty,
|
||||||
|
$pxi:ident:
|
||||||
|
(
|
||||||
|
$pin_num:expr, $iomux_reg:expr, $bit:expr, $out_en_set:ident,
|
||||||
|
$out_en_clear:ident, $out_set:ident, $out_clear:ident, $out_reg:ident
|
||||||
|
)
|
||||||
|
$( ,( $( $af_signal:ident: $af:ident ),* ))?
|
||||||
|
) => {
|
||||||
|
impl<MODE> embedded_hal::digital::v2::OutputPin for $pxi<Output<MODE>> {
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||||
|
unsafe { (*GPIO::ptr()).$out_set.write(|w| w.bits(1 << $bit)) };
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||||
|
unsafe { (*GPIO::ptr()).$out_clear.write(|w| w.bits(1 << $bit)) };
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<MODE> embedded_hal::digital::v2::StatefulOutputPin for $pxi<Output<MODE>> {
|
||||||
|
fn is_set_high(&self) -> Result<bool, Self::Error> {
|
||||||
|
unsafe { Ok((*GPIO::ptr()).$out_reg.read().bits() & (1 << $bit) != 0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_set_low(&self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(!self.is_set_high()?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<MODE> embedded_hal::digital::v2::ToggleableOutputPin for $pxi<Output<MODE>> {
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
fn toggle(&mut self) -> Result<(), Self::Error> {
|
||||||
|
if self.is_set_high()? {
|
||||||
|
Ok(self.set_low()?)
|
||||||
|
} else {
|
||||||
|
Ok(self.set_high()?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<MODE> $pxi<MODE> {
|
||||||
|
pub fn into_pull_up_input(self) -> $pxi<Input<PullUp>> {
|
||||||
|
self.init_input(false, false);
|
||||||
|
$pxi { _mode: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_pull_down_input(self) -> $pxi<Input<PullDown>> {
|
||||||
|
self.init_input(true, false);
|
||||||
|
$pxi { _mode: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_output(&self, alternate: AlternateFunction, open_drain: bool) {
|
||||||
|
let gpio = unsafe { &*GPIO::ptr() };
|
||||||
|
let iomux = unsafe { &*IO_MUX::ptr() };
|
||||||
|
|
||||||
|
gpio.$out_en_set.write(|w| unsafe { w.bits(1 << $bit) });
|
||||||
|
gpio.pin[$pin_num].modify(|_, w| w.pin_pad_driver().bit(open_drain));
|
||||||
|
|
||||||
|
gpio.func_out_sel_cfg[$pin_num]
|
||||||
|
.modify(|_, w| unsafe { w.out_sel().bits(OutputSignal::GPIO as OutputSignalType) });
|
||||||
|
|
||||||
|
paste! {
|
||||||
|
iomux.$iomux_reg.modify(|_, w| unsafe {
|
||||||
|
w.mcu_sel()
|
||||||
|
.bits(alternate as u8)
|
||||||
|
.fun_ie()
|
||||||
|
.clear_bit()
|
||||||
|
.fun_wpd()
|
||||||
|
.clear_bit()
|
||||||
|
.fun_wpu()
|
||||||
|
.clear_bit()
|
||||||
|
.fun_drv()
|
||||||
|
.bits(DriveStrength::I20mA as u8)
|
||||||
|
.slp_sel()
|
||||||
|
.clear_bit()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_push_pull_output(self) -> $pxi<Output<PushPull>> {
|
||||||
|
self.init_output(AlternateFunction::$gpio_function, false);
|
||||||
|
$pxi { _mode: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_open_drain_output(self) -> $pxi<Output<OpenDrain>> {
|
||||||
|
self.init_output(AlternateFunction::$gpio_function, true);
|
||||||
|
$pxi { _mode: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_alternate_1(self) -> $pxi<Alternate<AF1>> {
|
||||||
|
self.init_output(AlternateFunction::Function1, false);
|
||||||
|
$pxi { _mode: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_alternate_2(self) -> $pxi<Alternate<AF2>> {
|
||||||
|
self.init_output(AlternateFunction::Function2, false);
|
||||||
|
$pxi { _mode: PhantomData }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<MODE> OutputPin for $pxi<MODE> {
|
||||||
|
type OutputSignal = $output_signal;
|
||||||
|
|
||||||
|
fn set_to_open_drain_output(&mut self) -> &mut Self {
|
||||||
|
self.init_output(AlternateFunction::$gpio_function, true);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_to_push_pull_output(&mut self) -> &mut Self {
|
||||||
|
self.init_output(AlternateFunction::$gpio_function, false);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enable_output(&mut self, on: bool) -> &mut Self {
|
||||||
|
if on {
|
||||||
|
unsafe { &*GPIO::ptr() }
|
||||||
|
.$out_en_set
|
||||||
|
.write(|w| unsafe { w.bits(1 << $bit) });
|
||||||
|
} else {
|
||||||
|
unsafe { &*GPIO::ptr() }
|
||||||
|
.$out_en_clear
|
||||||
|
.write(|w| unsafe { w.bits(1 << $bit) });
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_output_high(&mut self, high: bool) -> &mut Self {
|
||||||
|
if high {
|
||||||
|
unsafe { (*GPIO::ptr()).$out_set.write(|w| w.bits(1 << $bit)) };
|
||||||
|
} else {
|
||||||
|
unsafe { (*GPIO::ptr()).$out_clear.write(|w| w.bits(1 << $bit)) };
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_drive_strength(&mut self, strength: DriveStrength) -> &mut Self {
|
||||||
|
paste! {
|
||||||
|
unsafe { &*IO_MUX::ptr() }
|
||||||
|
.$iomux_reg
|
||||||
|
.modify(|_, w| unsafe { w.fun_drv().bits(strength as u8) });
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enable_open_drain(&mut self, on: bool) -> &mut Self {
|
||||||
|
unsafe { &*GPIO::ptr() }.pin[$pin_num].modify(|_, w| w.pin_pad_driver().bit(on));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn internal_pull_up_in_sleep_mode(&mut self, on: bool) -> &mut Self {
|
||||||
|
paste! {
|
||||||
|
unsafe { &*IO_MUX::ptr() }
|
||||||
|
.$iomux_reg
|
||||||
|
.modify(|_, w| w.mcu_wpu().bit(on));
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn internal_pull_down_in_sleep_mode(&mut self, on: bool) -> &mut Self {
|
||||||
|
paste!{
|
||||||
|
unsafe { &*IO_MUX::ptr() }
|
||||||
|
.$iomux_reg
|
||||||
|
.modify(|_, w| w.mcu_wpd().bit(on));
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enable_output_in_sleep_mode(&mut self, on: bool) -> &mut Self {
|
||||||
|
paste! {
|
||||||
|
unsafe { &*IO_MUX::ptr() }
|
||||||
|
.$iomux_reg
|
||||||
|
.modify(|_, w| w.mcu_oe().bit(on));
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn connect_peripheral_to_output_with_options(
|
||||||
|
&mut self,
|
||||||
|
signal: Self::OutputSignal,
|
||||||
|
invert: bool,
|
||||||
|
invert_enable: bool,
|
||||||
|
enable_from_gpio: bool,
|
||||||
|
force_via_gpio_mux: bool,
|
||||||
|
) -> &mut Self {
|
||||||
|
let af = if force_via_gpio_mux {
|
||||||
|
AlternateFunction::$gpio_function
|
||||||
|
} else {
|
||||||
|
match signal {
|
||||||
|
$( $(
|
||||||
|
Self::OutputSignal::$af_signal => AlternateFunction::$af,
|
||||||
|
)* )?
|
||||||
|
_ => AlternateFunction::$gpio_function
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if af == AlternateFunction::$gpio_function && signal as usize > OUTPUT_SIGNAL_MAX as usize {
|
||||||
|
panic!("Cannot connect this peripheral to GPIO");
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set_alternate_function(af);
|
||||||
|
|
||||||
|
let clipped_signal = if signal as usize <= OUTPUT_SIGNAL_MAX as usize { signal as OutputSignalType } else { OUTPUT_SIGNAL_MAX };
|
||||||
|
|
||||||
|
unsafe { &*GPIO::ptr() }.func_out_sel_cfg[$pin_num].modify(|_, w| unsafe {
|
||||||
|
w
|
||||||
|
.out_sel().bits(clipped_signal)
|
||||||
|
.inv_sel().bit(invert)
|
||||||
|
.oen_sel().bit(enable_from_gpio)
|
||||||
|
.oen_inv_sel().bit(invert_enable)
|
||||||
|
});
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn internal_pull_up(&mut self, on: bool) -> &mut Self {
|
||||||
|
paste!{
|
||||||
|
unsafe { &*IO_MUX::ptr() }.$iomux_reg.modify(|_, w| w.fun_wpu().bit(on));
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn internal_pull_down(&mut self, on: bool) -> &mut Self {
|
||||||
|
paste! {
|
||||||
|
unsafe { &*IO_MUX::ptr() }.$iomux_reg.modify(|_, w| w.fun_wpd().bit(on));
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! impl_output_wrap {
|
macro_rules! impl_output_wrap {
|
||||||
(
|
(
|
||||||
$gpio_function:ident, $pxi:ident, $pin_num:expr, $iomux_reg:expr, IO, Bank0
|
$gpio_function:ident,
|
||||||
|
$pxi:ident, $pin_num:expr, $iomux_reg:expr, IO, Bank0
|
||||||
$( ,( $( $af_output_signal:ident : $af_output:ident ),* ))?
|
$( ,( $( $af_output_signal:ident : $af_output:ident ),* ))?
|
||||||
) => {
|
) => {
|
||||||
impl_output!(
|
impl_output!(
|
||||||
$gpio_function,
|
$gpio_function,
|
||||||
|
OutputSignal,
|
||||||
$pxi:
|
$pxi:
|
||||||
(
|
(
|
||||||
$pin_num, $iomux_reg, $pin_num % 32, enable_w1ts, enable_w1tc,
|
$pin_num, $iomux_reg, $pin_num % 32, enable_w1ts, enable_w1tc,
|
||||||
@ -522,11 +704,13 @@ macro_rules! impl_output_wrap {
|
|||||||
};
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
$gpio_function:ident, $pxi:ident, $pin_num:expr, $iomux_reg:expr, IO, Bank1
|
$gpio_function:ident,
|
||||||
|
$pxi:ident, $pin_num:expr, $iomux_reg:expr, IO, Bank1
|
||||||
$( ,( $( $af_output_signal:ident : $af_output:ident ),* ))?
|
$( ,( $( $af_output_signal:ident : $af_output:ident ),* ))?
|
||||||
) => {
|
) => {
|
||||||
impl_output!(
|
impl_output!(
|
||||||
$gpio_function,
|
$gpio_function,
|
||||||
|
OutputSignal,
|
||||||
$pxi:
|
$pxi:
|
||||||
(
|
(
|
||||||
$pin_num, $iomux_reg, $pin_num % 32, enable1_w1ts, enable1_w1tc,
|
$pin_num, $iomux_reg, $pin_num % 32, enable1_w1ts, enable1_w1tc,
|
||||||
@ -537,7 +721,8 @@ macro_rules! impl_output_wrap {
|
|||||||
};
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
$gpio_function:ident, $pxi:ident, $pin_num:expr, $iomux_reg:expr, $type:ident, $bank:ident
|
$gpio_function:ident,
|
||||||
|
$pxi:ident, $pin_num:expr, $iomux_reg:expr, $type:ident, $bank:ident
|
||||||
$( ,( $( $af_output_signal:ident : $af_output:ident ),* ))?
|
$( ,( $( $af_output_signal:ident : $af_output:ident ),* ))?
|
||||||
) => {};
|
) => {};
|
||||||
}
|
}
|
||||||
@ -583,164 +768,16 @@ macro_rules! gpio {
|
|||||||
fn split(self) -> Self::Parts;
|
fn split(self) -> Self::Parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Pin {
|
impl GpioExt for GPIO {
|
||||||
fn sleep_mode(&mut self, on: bool) -> &mut Self;
|
type Parts = Pins;
|
||||||
|
|
||||||
fn set_alternate_function(&mut self, alternate: AlternateFunction) -> &mut Self;
|
fn split(self) -> Self::Parts {
|
||||||
|
Pins {
|
||||||
fn listen(&mut self, event: Event) {
|
$(
|
||||||
self.listen_with_options(event, true, false, false)
|
$pname: $pxi { _mode: PhantomData },
|
||||||
|
)+
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn listen_with_options(
|
|
||||||
&mut self,
|
|
||||||
event: Event,
|
|
||||||
int_enable: bool,
|
|
||||||
nmi_enable: bool,
|
|
||||||
wake_up_from_light_sleep: bool,
|
|
||||||
);
|
|
||||||
|
|
||||||
fn unlisten(&mut self);
|
|
||||||
|
|
||||||
fn clear_interrupt(&mut self);
|
|
||||||
|
|
||||||
fn is_pcore_interrupt_set(&mut self) -> bool;
|
|
||||||
|
|
||||||
fn is_pcore_non_maskable_interrupt_set(&mut self) -> bool;
|
|
||||||
|
|
||||||
fn is_acore_interrupt_set(&mut self) -> bool;
|
|
||||||
|
|
||||||
fn is_acore_non_maskable_interrupt_set(&mut self) -> bool;
|
|
||||||
|
|
||||||
fn enable_hold(&mut self, on: bool);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait InputPin: Pin {
|
|
||||||
fn set_to_input(&mut self) -> &mut Self;
|
|
||||||
|
|
||||||
fn enable_input(&mut self, on: bool) -> &mut Self;
|
|
||||||
|
|
||||||
fn enable_input_in_sleep_mode(&mut self, on: bool) -> &mut Self;
|
|
||||||
|
|
||||||
fn is_input_high(&mut 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_with_options(
|
|
||||||
&mut self,
|
|
||||||
signal: InputSignal,
|
|
||||||
invert: bool,
|
|
||||||
force_via_gpio_mux: bool,
|
|
||||||
) -> &mut Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait OutputPin: Pin {
|
|
||||||
fn set_to_open_drain_output(&mut self) -> &mut Self;
|
|
||||||
|
|
||||||
fn set_to_push_pull_output(&mut self) -> &mut Self;
|
|
||||||
|
|
||||||
fn enable_output(&mut self, on: bool) -> &mut Self;
|
|
||||||
|
|
||||||
fn set_output_high(&mut self, on: bool) -> &mut Self;
|
|
||||||
|
|
||||||
fn set_drive_strength(&mut self, strength: DriveStrength) -> &mut Self;
|
|
||||||
|
|
||||||
fn enable_open_drain(&mut self, on: bool) -> &mut Self;
|
|
||||||
|
|
||||||
fn enable_output_in_sleep_mode(&mut self, on: bool) -> &mut Self;
|
|
||||||
|
|
||||||
fn internal_pull_up_in_sleep_mode(&mut self, on: bool) -> &mut Self;
|
|
||||||
|
|
||||||
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 connect_peripheral_to_output_with_options(
|
|
||||||
&mut self,
|
|
||||||
signal: OutputSignal,
|
|
||||||
invert: bool,
|
|
||||||
invert_enable: bool,
|
|
||||||
enable_from_gpio: bool,
|
|
||||||
force_via_gpio_mux: bool,
|
|
||||||
) -> &mut Self;
|
|
||||||
|
|
||||||
fn internal_pull_up(&mut self, on: bool) -> &mut Self;
|
|
||||||
|
|
||||||
fn internal_pull_down(&mut self, on: bool) -> &mut Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait RTCPin {}
|
|
||||||
|
|
||||||
pub trait AnalogPin {}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub enum Event {
|
|
||||||
RisingEdge = 1,
|
|
||||||
FallingEdge = 2,
|
|
||||||
AnyEdge = 3,
|
|
||||||
LowLevel = 4,
|
|
||||||
HighLevel = 5,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Unknown {}
|
|
||||||
|
|
||||||
pub struct Input<MODE> {
|
|
||||||
_mode: PhantomData<MODE>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RTCInput<MODE> {
|
|
||||||
_mode: PhantomData<MODE>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Floating;
|
|
||||||
|
|
||||||
pub struct PullDown;
|
|
||||||
|
|
||||||
pub struct PullUp;
|
|
||||||
|
|
||||||
pub struct Output<MODE> {
|
|
||||||
_mode: PhantomData<MODE>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RTCOutput<MODE> {
|
|
||||||
_mode: PhantomData<MODE>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct OpenDrain;
|
|
||||||
|
|
||||||
pub struct PushPull;
|
|
||||||
|
|
||||||
pub struct Analog;
|
|
||||||
|
|
||||||
pub struct Alternate<MODE> {
|
|
||||||
_mode: PhantomData<MODE>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AF0;
|
|
||||||
|
|
||||||
pub struct AF1;
|
|
||||||
|
|
||||||
pub struct AF2;
|
|
||||||
|
|
||||||
pub enum DriveStrength {
|
|
||||||
I5mA = 0,
|
|
||||||
I10mA = 1,
|
|
||||||
I20mA = 2,
|
|
||||||
I40mA = 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
|
||||||
pub enum AlternateFunction {
|
|
||||||
Function0 = 0,
|
|
||||||
Function1 = 1,
|
|
||||||
Function2 = 2,
|
|
||||||
Function3 = 3,
|
|
||||||
Function4 = 4,
|
|
||||||
Function5 = 5,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connect_low_to_peripheral(signal: InputSignal) {
|
pub fn connect_low_to_peripheral(signal: InputSignal) {
|
||||||
@ -765,18 +802,6 @@ macro_rules! gpio {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GpioExt for GPIO {
|
|
||||||
type Parts = Pins;
|
|
||||||
|
|
||||||
fn split(self) -> Self::Parts {
|
|
||||||
Pins {
|
|
||||||
$(
|
|
||||||
$pname: $pxi { _mode: PhantomData },
|
|
||||||
)+
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Pins {
|
pub struct Pins {
|
||||||
$(
|
$(
|
||||||
pub $pname: $pxi<Unknown>,
|
pub $pname: $pxi<Unknown>,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user