Refactored parts of the GPIO implementation

This commit is contained in:
Robin Müller 2021-11-06 16:16:53 +01:00
parent 9181e61e70
commit 9020fc92d0
No known key found for this signature in database
GPG Key ID: 71B58F8A3CDFA9AC
4 changed files with 161 additions and 115 deletions

View File

@ -18,7 +18,7 @@ nb = "1"
embedded-hal = { features = ["unproven"], version = "0.2.6" } embedded-hal = { features = ["unproven"], version = "0.2.6" }
[dependencies.va108xx] [dependencies.va108xx]
version = "0.1.0" version = "0.1"
[features] [features]
rt = ["va108xx/rt"] rt = ["va108xx/rt"]

View File

@ -1,7 +1,8 @@
use crate::pac::SYSCONFIG; use crate::pac::SYSCONFIG;
use core::convert::Infallible; use core::convert::Infallible;
use core::marker::PhantomData; use core::marker::PhantomData;
use embedded_hal::digital::v2::{toggleable, InputPin, OutputPin, StatefulOutputPin}; use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin};
use va108xx::IOCONFIG;
/// Extension trait to split a GPIO peripheral in independent pins and registers /// Extension trait to split a GPIO peripheral in independent pins and registers
pub trait GpioExt { pub trait GpioExt {
@ -9,14 +10,21 @@ pub trait GpioExt {
type Parts; type Parts;
/// Splits the GPIO block into independent pins and registers. /// Splits the GPIO block into independent pins and registers.
fn split(self, syscfg: &mut SYSCONFIG) -> Self::Parts; fn split(&mut self, syscfg: &mut SYSCONFIG) -> Self::Parts;
}
#[derive(Debug, PartialEq)]
pub enum PinModeError {
InputDisabledForOutput,
} }
trait GpioRegExt { trait GpioRegExt {
fn is_low(&self, pos: u8) -> bool; fn is_low(&self, pos: u8) -> bool;
fn is_set_low(&self, pos: u8) -> bool; fn is_set_low(&self, pos: usize, port_id: char) -> Result<bool, PinModeError>;
fn input_enabled_for_output(&self, pos: usize, port_id: char) -> bool;
fn set_high(&self, pos: u8); fn set_high(&self, pos: u8);
fn set_low(&self, pos: u8); fn set_low(&self, pos: u8);
fn toggle(&self, pos: u8);
} }
/// Input mode (type state) /// Input mode (type state)
@ -77,10 +85,10 @@ pub enum FilterClkSel {
/// Fully erased pin /// Fully erased pin
pub struct Pin<MODE> { pub struct Pin<MODE> {
i: u8, i: u8,
port_id: char,
port: *const dyn GpioRegExt, port: *const dyn GpioRegExt,
_mode: PhantomData<MODE>, _mode: PhantomData<MODE>,
} }
unsafe impl<MODE> Sync for Pin<MODE> {}
// NOTE(unsafe) this only enables read access to the same pin from multiple threads // NOTE(unsafe) this only enables read access to the same pin from multiple threads
unsafe impl<MODE> Send for Pin<MODE> {} unsafe impl<MODE> Send for Pin<MODE> {}
impl<MODE> StatefulOutputPin for Pin<Output<MODE>> { impl<MODE> StatefulOutputPin for Pin<Output<MODE>> {
@ -90,11 +98,11 @@ impl<MODE> StatefulOutputPin for Pin<Output<MODE>> {
} }
#[inline(always)] #[inline(always)]
fn is_set_low(&self) -> Result<bool, Self::Error> { fn is_set_low(&self) -> Result<bool, Self::Error> {
Ok(unsafe { (*self.port).is_set_low(self.i) }) unsafe { (*self.port).is_set_low(self.i.into(), self.port_id) }
} }
} }
impl<MODE> OutputPin for Pin<Output<MODE>> { impl<MODE> OutputPin for Pin<Output<MODE>> {
type Error = Infallible; type Error = PinModeError;
#[inline(always)] #[inline(always)]
fn set_high(&mut self) -> Result<(), Self::Error> { fn set_high(&mut self) -> Result<(), Self::Error> {
unsafe { (*self.port).set_high(self.i) }; unsafe { (*self.port).set_high(self.i) };
@ -106,7 +114,16 @@ impl<MODE> OutputPin for Pin<Output<MODE>> {
Ok(()) Ok(())
} }
} }
impl<MODE> toggleable::Default for Pin<Output<MODE>> {}
impl<MODE> ToggleableOutputPin for Pin<Output<MODE>> {
type Error = Infallible;
#[inline(always)]
fn toggle(&mut self) -> Result<(), Self::Error> {
unsafe { (*self.port).toggle(self.i) }
Ok(())
}
}
impl InputPin for Pin<Output<OpenDrain>> { impl InputPin for Pin<Output<OpenDrain>> {
type Error = Infallible; type Error = Infallible;
#[inline(always)] #[inline(always)]
@ -133,36 +150,59 @@ impl<MODE> InputPin for Pin<Input<MODE>> {
// This is only needs to be implemented for PORTA because PORTB is derived // This is only needs to be implemented for PORTA because PORTB is derived
// from PORTA // from PORTA
impl GpioRegExt for crate::pac::porta::RegisterBlock { impl GpioRegExt for crate::pac::porta::RegisterBlock {
#[inline(always)]
fn is_low(&self, pos: u8) -> bool { fn is_low(&self, pos: u8) -> bool {
self.datainraw().read().bits() & (1 << pos) == 0 self.datainraw().read().bits() & (1 << pos) == 0
} }
fn is_set_low(&self, pos: u8) -> bool { #[inline(always)]
// Note that this only works if the IENWO bit is enabled in IOCONFIG fn is_set_low(&self, pos: usize, port_id: char) -> Result<bool, PinModeError> {
// This is done by default for output pins for now if self.input_enabled_for_output(pos, port_id) {
self.datainraw().read().bits() & (1 << pos) == 0 Ok(self.datainraw().read().bits() & (1 << pos) == 0)
} else {
Err(PinModeError::InputDisabledForOutput)
}
} }
#[inline(always)]
fn set_high(&self, pos: u8) { fn set_high(&self, pos: u8) {
unsafe { self.setout().write(|w| w.bits(1 << pos)) } unsafe { self.setout().write(|w| w.bits(1 << pos)) }
} }
#[inline(always)]
fn set_low(&self, pos: u8) { fn set_low(&self, pos: u8) {
unsafe { self.clrout().write(|w| w.bits(1 << pos)) } unsafe { self.clrout().write(|w| w.bits(1 << pos)) }
} }
#[inline(always)]
fn toggle(&self, pos: u8) {
unsafe { self.togout().write(|w| w.bits(1 << pos)) }
}
#[inline(always)]
fn input_enabled_for_output(&self, pos: usize, port_id: char) -> bool {
unsafe {
let iocfg = &(*IOCONFIG::ptr());
match port_id {
'A' => iocfg.porta[pos].read().iewo().bit_is_set(),
'B' => iocfg.portb[pos].read().iewo().bit_is_set(),
_ => iocfg.porta[pos].read().iewo().bit_is_set(),
}
}
}
} }
macro_rules! gpio { macro_rules! gpio {
($PORTX:ident, $portx:ident, [ ($PORTX:ident, $portx:ident, $port_id:expr, [
$($PXi:ident: ($pxi:ident, $i:expr),)+ $($PXi:ident: ($pxi:ident, $i:expr),)+
]) => { ]) => {
pub mod $portx { pub mod $portx {
use core::marker::PhantomData; use core::marker::PhantomData;
use core::convert::Infallible; use core::convert::Infallible;
use cortex_m::interrupt::CriticalSection;
use super::{ use super::{
FUNSEL1, FUNSEL2, FUNSEL3, Floating, Funsel, GpioExt, Input, OpenDrain, FUNSEL1, FUNSEL2, FUNSEL3, Floating, Funsel, GpioExt, Input, OpenDrain,
PullUp, Output, FilterType, FilterClkSel, Pin, GpioRegExt, PushPull PullUp, Output, FilterType, FilterClkSel, Pin, GpioRegExt, PushPull,
PinModeError
}; };
use crate::{pac::$PORTX, pac::SYSCONFIG, pac::IOCONFIG}; use crate::{pac::$PORTX, pac::SYSCONFIG, pac::IOCONFIG};
use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, toggleable}; use embedded_hal::digital::v2::{
InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin
};
pub struct Parts { pub struct Parts {
$( $(
pub $pxi: $PXi<Input<Floating>>, pub $pxi: $PXi<Input<Floating>>,
@ -171,7 +211,7 @@ macro_rules! gpio {
impl GpioExt for $PORTX { impl GpioExt for $PORTX {
type Parts = Parts; type Parts = Parts;
fn split(self, syscfg: &mut SYSCONFIG) -> Parts { fn split(&mut self, syscfg: &mut SYSCONFIG) -> Parts {
syscfg.peripheral_clk_enable.modify(|_, w| { syscfg.peripheral_clk_enable.modify(|_, w| {
w.$portx().set_bit(); w.$portx().set_bit();
w.gpio().set_bit(); w.gpio().set_bit();
@ -186,10 +226,9 @@ macro_rules! gpio {
} }
} }
fn _set_alternate_mode(index: usize, mode: u8) { fn _set_alternate_mode(iocfg: &mut IOCONFIG, index: usize, mode: u8) {
unsafe { unsafe {
let reg = &(*IOCONFIG::ptr()); iocfg.$portx[index].modify(|_, w| {
reg.$portx[index].modify(|_, w| {
w.funsel().bits(mode) w.funsel().bits(mode)
}) })
} }
@ -201,130 +240,120 @@ macro_rules! gpio {
} }
impl<MODE> $PXi<MODE> { impl<MODE> $PXi<MODE> {
pub fn into_funsel_1(self, _cs: &CriticalSection) -> $PXi<Funsel<FUNSEL1>> { pub fn into_funsel_1(self, iocfg: &mut IOCONFIG) -> $PXi<Funsel<FUNSEL1>> {
_set_alternate_mode(0, 1); _set_alternate_mode(iocfg, $i, 1);
$PXi { _mode: PhantomData } $PXi { _mode: PhantomData }
} }
pub fn into_funsel_2(self, _cs: &CriticalSection) -> $PXi<Funsel<FUNSEL2>> { pub fn into_funsel_2(self, iocfg: &mut IOCONFIG) -> $PXi<Funsel<FUNSEL2>> {
_set_alternate_mode(0, 2); _set_alternate_mode(iocfg, $i, 2);
$PXi { _mode: PhantomData } $PXi { _mode: PhantomData }
} }
pub fn into_funsel_3(self, _cs: &CriticalSection) -> $PXi<Funsel<FUNSEL3>> { pub fn into_funsel_3(self, iocfg: &mut IOCONFIG) -> $PXi<Funsel<FUNSEL3>> {
_set_alternate_mode(0, 3); _set_alternate_mode(iocfg, $i, 3);
$PXi { _mode: PhantomData } $PXi { _mode: PhantomData }
} }
pub fn into_floating_input(self, _cs: &CriticalSection) -> $PXi<Input<Floating>> { pub fn into_floating_input(
self, iocfg: &mut IOCONFIG
) -> $PXi<Input<Floating>> {
unsafe { unsafe {
let reg = &(*IOCONFIG::ptr()); iocfg.$portx[$i].modify(|_, w| {
reg.$portx[0].modify(|_, w| {
w.funsel().bits(0); w.funsel().bits(0);
w.pen().clear_bit(); w.pen().clear_bit();
w.opendrn().clear_bit() w.opendrn().clear_bit()
}); });
let port_reg = &(*$PORTX::ptr()); let port_reg = &(*$PORTX::ptr());
port_reg.dir().modify(|r,w| w.bits(r.bits() & !(1 << 0))); port_reg.dir().modify(|r,w| w.bits(r.bits() & !(1 << $i)));
} }
$PXi { _mode: PhantomData } $PXi { _mode: PhantomData }
} }
pub fn into_pull_up_input(self, _cs: &CriticalSection) -> $PXi<Input<PullUp>> { pub fn into_pull_up_input(self, iocfg: &mut IOCONFIG) -> $PXi<Input<PullUp>> {
unsafe { unsafe {
let reg = &(*IOCONFIG::ptr()); iocfg.$portx[$i].modify(|_, w| {
reg.$portx[0].modify(|_, w| {
w.funsel().bits(0); w.funsel().bits(0);
w.pen().set_bit(); w.pen().set_bit();
w.plevel().set_bit(); w.plevel().set_bit();
w.opendrn().clear_bit() w.opendrn().clear_bit()
}); });
let port_reg = &(*$PORTX::ptr()); let port_reg = &(*$PORTX::ptr());
port_reg.dir().modify(|r,w| w.bits(r.bits() & !(1 << 0))); port_reg.dir().modify(|r,w| w.bits(r.bits() & !(1 << $i)));
} }
$PXi { _mode: PhantomData } $PXi { _mode: PhantomData }
} }
pub fn into_pull_down_input(self, _cs: &CriticalSection) -> $PXi<Input<PullUp>> { pub fn into_pull_down_input(
self, iocfg: &mut IOCONFIG, port_reg: &mut $PORTX
) -> $PXi<Input<PullUp>> {
unsafe { unsafe {
let reg = &(*IOCONFIG::ptr()); iocfg.$portx[$i].modify(|_, w| {
reg.$portx[0].modify(|_, w| {
w.funsel().bits(0); w.funsel().bits(0);
w.pen().set_bit(); w.pen().set_bit();
w.plevel().clear_bit(); w.plevel().clear_bit();
w.opendrn().clear_bit() w.opendrn().clear_bit()
}); });
let port_reg = &(*$PORTX::ptr()); port_reg.dir().modify(|r,w| w.bits(r.bits() & !(1 << $i)));
port_reg.dir().modify(|r,w| w.bits(r.bits() & !(1 << 0)));
} }
$PXi { _mode: PhantomData } $PXi { _mode: PhantomData }
} }
pub fn into_open_drain_output(self, _cs: &CriticalSection) -> $PXi<Output<OpenDrain>> { pub fn into_open_drain_output(
self, iocfg: &mut IOCONFIG
) -> $PXi<Output<OpenDrain>> {
unsafe { unsafe {
let reg = &(*IOCONFIG::ptr()); iocfg.$portx[$i].modify(|_, w| {
reg.$portx[$i].modify(|_, w| {
w.funsel().bits(0); w.funsel().bits(0);
w.pen().clear_bit(); w.pen().clear_bit();
w.opendrn().set_bit() w.opendrn().set_bit()
}); });
let port_reg = &(*$PORTX::ptr()); let port_reg = &(*$PORTX::ptr());
port_reg.dir().modify(|r,w| w.bits(r.bits() | (1 << 0))); port_reg.dir().modify(|r,w| w.bits(r.bits() | (1 << $i)));
} }
let $pxi: $PXi<Output<OpenDrain>> = $PXi { _mode: PhantomData }; $PXi { _mode: PhantomData }
// Enable input functionality by default to ensure this is a stateful output pin
let $pxi = $pxi.enable_input(_cs, true);
$pxi
} }
pub fn into_push_pull_output(self, _cs: &CriticalSection) -> $PXi<Output<PushPull>> { pub fn into_push_pull_output(
self, iocfg: &mut IOCONFIG, port_reg: &mut $PORTX
) -> $PXi<Output<PushPull>> {
unsafe { unsafe {
let reg = &(*IOCONFIG::ptr()); iocfg.$portx[$i].modify(|_, w| {
reg.$portx[$i].modify(|_, w| {
w.funsel().bits(0); w.funsel().bits(0);
w.opendrn().clear_bit() w.opendrn().clear_bit()
}); });
let port_reg = &(*$PORTX::ptr()); port_reg.dir().modify(|r,w| w.bits(r.bits() | (1 << $i)));
port_reg.dir().modify(|r,w| w.bits(r.bits() | (1 << 0)));
} }
let $pxi: $PXi<Output<PushPull>> = $PXi { _mode: PhantomData }; $PXi { _mode: PhantomData }
// Enable input functionality by default to ensure this is a stateful output pin
let $pxi = $pxi.enable_input(_cs, true);
$pxi
} }
pub fn filter_type(self, _cs: &CriticalSection, filter: FilterType, clksel: FilterClkSel) -> Self { pub fn filter_type(
self, iocfg: &mut IOCONFIG, filter: FilterType, clksel: FilterClkSel
) -> Self {
unsafe { unsafe {
let reg = &(*IOCONFIG::ptr()); iocfg.$portx[$i].modify(|_, w| {
reg.$portx[$i].modify(|_, w| {
w.flttype().bits(filter as u8); w.flttype().bits(filter as u8);
w.fltclk().bits(clksel as u8) w.fltclk().bits(clksel as u8)
}) });
} }
self self
} }
} }
impl<MODE> $PXi<Input<MODE>> { impl<MODE> $PXi<Input<MODE>> {
pub fn input_inversion(self, _cs: &CriticalSection, enable: bool) -> Self { pub fn input_inversion(self, iocfg: &mut IOCONFIG, enable: bool) -> Self {
unsafe { if enable {
let reg = &(*IOCONFIG::ptr()); iocfg.$portx[$i].modify(|_, w| w.invinp().set_bit());
if enable { } else {
reg.$portx[$i].modify(|_, w| w.invinp().set_bit()); iocfg.$portx[$i].modify(|_, w| w.invinp().clear_bit());
} else {
reg.$portx[$i].modify(|_, w| w.invinp().clear_bit());
}
} }
self self
} }
} }
impl<MODE> $PXi<Output<MODE>> { impl<MODE> $PXi<Output<MODE>> {
pub fn output_inversion(self, _cs: &CriticalSection, enable: bool) -> Self { pub fn output_inversion(self, iocfg: &mut IOCONFIG, enable: bool) -> Self {
unsafe { if enable {
let reg = &(*IOCONFIG::ptr()); iocfg.$portx[$i].modify(|_, w| w.invout().set_bit());
if enable { } else {
reg.$portx[$i].modify(|_, w| w.invout().set_bit()); iocfg.$portx[$i].modify(|_, w| w.invout().clear_bit());
} else {
reg.$portx[$i].modify(|_, w| w.invout().clear_bit());
}
} }
self self
} }
@ -333,52 +362,49 @@ macro_rules! gpio {
/// this mode the input receiver is enabled even /// this mode the input receiver is enabled even
/// if the direction is configured as an output. /// if the direction is configured as an output.
/// This allows monitoring of output values /// This allows monitoring of output values
pub fn enable_input(self, _cs: &CriticalSection, enable: bool) -> Self { pub fn enable_input(self, iocfg: &mut IOCONFIG, enable: bool) -> Self {
unsafe { if enable {
let reg = &(*IOCONFIG::ptr()); iocfg.$portx[$i].modify(|_, w| w.iewo().set_bit());
if enable { } else {
reg.$portx[$i].modify(|_, w| w.iewo().set_bit()); iocfg.$portx[$i].modify(|_, w| w.iewo().clear_bit());
} else {
reg.$portx[$i].modify(|_, w| w.iewo().clear_bit());
}
} }
self self
} }
/// Enable Pull up/down even when output is active. The Default is to disable pull /// Enable Pull up/down even when output is active. The Default is to
/// up/down when output is actively driven. This bit enables the pull up/down all the time. /// disable pull up/down when output is actively driven. This bit enables the
/// pull up/down all the time.
/// ///
/// # Arguments /// # Arguments
/// ///
/// `enable` - Enable the peripheral functionality /// `enable` - Enable the peripheral functionality
/// `enable_pullup` - Enable the pullup itself /// `enable_pullup` - Enable the pullup itself
pub fn enable_pull_up(self, _cs: &CriticalSection, enable: bool, enable_pullup: bool) -> Self { pub fn enable_pull_up(
unsafe { self, iocfg: &mut IOCONFIG, enable: bool, enable_pullup: bool
let reg = &(*IOCONFIG::ptr()); ) -> Self {
reg.$portx[$i].modify(|_, w| { iocfg.$portx[$i].modify(|_, w| {
if enable { w.pwoa().set_bit(); } else { w.pwoa().clear_bit(); } if enable { w.pwoa().set_bit(); } else { w.pwoa().clear_bit(); }
if enable_pullup { w.pen().set_bit(); } else { w.pen().clear_bit(); } if enable_pullup { w.pen().set_bit(); } else { w.pen().clear_bit(); }
w.plevel().set_bit() w.plevel().set_bit()
}); });
}
self self
} }
/// Enable Pull up/down even when output is active. The Default is to disable pull /// Enable Pull up/down even when output is active. The Default is to disable
/// up/down when output is actively driven. This bit enables the pull up/down all the time. /// pull up/down when output is actively driven. This bit enables the
/// pull up/down all the time.
/// ///
/// # Arguments /// # Arguments
/// ///
/// `enable` - Enable the peripheral functionality /// `enable` - Enable the peripheral functionality
/// `enable_pullup` - Enable the pulldown itself /// `enable_pullup` - Enable the pulldown itself
pub fn enable_pull_down(self, _cs: &CriticalSection, enable: bool, enable_pulldown: bool) -> Self { pub fn enable_pull_down(
unsafe { self, iocfg: &mut IOCONFIG, enable: bool, enable_pulldown: bool
let reg = &(*IOCONFIG::ptr()); ) -> Self {
reg.$portx[$i].modify(|_, w| { iocfg.$portx[$i].modify(|_, w| {
if enable { w.pwoa().set_bit(); } else { w.pwoa().clear_bit(); } if enable { w.pwoa().set_bit(); } else { w.pwoa().clear_bit(); }
if enable_pulldown { w.pen().set_bit(); } else { w.pen().clear_bit(); } if enable_pulldown { w.pen().set_bit(); } else { w.pen().clear_bit(); }
w.plevel().clear_bit() w.plevel().clear_bit()
}); });
}
self self
} }
} }
@ -391,6 +417,7 @@ macro_rules! gpio {
pub fn downgrade(self) -> Pin<Output<MODE>> { pub fn downgrade(self) -> Pin<Output<MODE>> {
Pin { Pin {
i: $i, i: $i,
port_id: $port_id,
port: $PORTX::ptr() as *const dyn GpioRegExt, port: $PORTX::ptr() as *const dyn GpioRegExt,
_mode: self._mode, _mode: self._mode,
} }
@ -398,23 +425,35 @@ macro_rules! gpio {
} }
impl<MODE> StatefulOutputPin for $PXi<Output<MODE>> { impl<MODE> StatefulOutputPin for $PXi<Output<MODE>> {
#[inline(always)]
fn is_set_high(&self) -> Result<bool, Self::Error> { fn is_set_high(&self) -> Result<bool, Self::Error> {
self.is_set_low().map(|v| !v) self.is_set_low().map(|v| !v)
} }
#[inline(always)]
fn is_set_low(&self) -> Result<bool, Self::Error> { fn is_set_low(&self) -> Result<bool, Self::Error> {
Ok(unsafe { (*$PORTX::ptr()).is_set_low(0) }) unsafe {
(*$PORTX::ptr()).is_set_low($i, $port_id)
}
} }
} }
impl<MODE> OutputPin for $PXi<Output<MODE>> { impl<MODE> OutputPin for $PXi<Output<MODE>> {
type Error = Infallible; type Error = PinModeError;
#[inline(always)]
fn set_high(&mut self) -> Result<(), Self::Error> { fn set_high(&mut self) -> Result<(), Self::Error> {
Ok(unsafe { (*$PORTX::ptr()).set_high(0) }) Ok(unsafe { (*$PORTX::ptr()).set_high($i) })
} }
#[inline(always)]
fn set_low(&mut self) -> Result<(), Self::Error> { fn set_low(&mut self) -> Result<(), Self::Error> {
Ok(unsafe { (*$PORTX::ptr()).set_low(0) }) Ok(unsafe { (*$PORTX::ptr()).set_low($i) })
}
}
impl<MODE> ToggleableOutputPin for $PXi<Output<MODE>> {
type Error = Infallible;
#[inline(always)]
fn toggle(&mut self) -> Result<(), Self::Error> {
Ok(unsafe { (*$PORTX::ptr()).toggle($i) })
} }
} }
impl<MODE> toggleable::Default for $PXi<Output<MODE>> {}
impl<MODE> $PXi<Input<MODE>> { impl<MODE> $PXi<Input<MODE>> {
/// Erases the pin number from the type /// Erases the pin number from the type
/// ///
@ -423,6 +462,7 @@ macro_rules! gpio {
pub fn downgrade(self) -> Pin<Input<MODE>> { pub fn downgrade(self) -> Pin<Input<MODE>> {
Pin { Pin {
i: $i, i: $i,
port_id: $port_id,
port: $PORTX::ptr() as *const dyn GpioRegExt, port: $PORTX::ptr() as *const dyn GpioRegExt,
_mode: self._mode, _mode: self._mode,
} }
@ -430,11 +470,13 @@ macro_rules! gpio {
} }
impl<MODE> InputPin for $PXi<Input<MODE>> { impl<MODE> InputPin for $PXi<Input<MODE>> {
type Error = Infallible; type Error = Infallible;
#[inline(always)]
fn is_high(&self) -> Result<bool, Self::Error> { fn is_high(&self) -> Result<bool, Self::Error> {
self.is_low().map(|v| !v) self.is_low().map(|v| !v)
} }
#[inline(always)]
fn is_low(&self) -> Result<bool, Self::Error> { fn is_low(&self) -> Result<bool, Self::Error> {
Ok(unsafe { (*$PORTX::ptr()).is_low(0) }) Ok(unsafe { (*$PORTX::ptr()).is_low($i) })
} }
} }
)+ )+
@ -442,7 +484,7 @@ macro_rules! gpio {
} }
} }
gpio!(PORTA, porta, [ gpio!(PORTA, porta, 'A', [
PA0: (pa0, 0), PA0: (pa0, 0),
PA1: (pa1, 1), PA1: (pa1, 1),
PA2: (pa2, 2), PA2: (pa2, 2),
@ -477,7 +519,7 @@ gpio!(PORTA, porta, [
PA31: (pa31, 31), PA31: (pa31, 31),
]); ]);
gpio!(PORTB, portb, [ gpio!(PORTB, portb, 'B', [
PB0: (pb0, 0), PB0: (pb0, 0),
PB1: (pb1, 1), PB1: (pb1, 1),
PB2: (pb2, 2), PB2: (pb2, 2),

View File

@ -3,5 +3,5 @@
pub use va108xx; pub use va108xx;
pub mod gpio; pub mod gpio;
pub mod prelude;
pub use va108xx as pac; pub use va108xx as pac;

4
src/prelude.rs Normal file
View File

@ -0,0 +1,4 @@
//! Prelude
pub use embedded_hal::prelude::*;
pub use crate::gpio::GpioExt as _stm32h7xx_hal_gpio_GpioExt;