Refactored parts of the GPIO implementation
This commit is contained in:
parent
9181e61e70
commit
9020fc92d0
@ -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"]
|
240
src/gpio.rs
240
src/gpio.rs
@ -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 {
|
|
||||||
let reg = &(*IOCONFIG::ptr());
|
|
||||||
if enable {
|
if enable {
|
||||||
reg.$portx[$i].modify(|_, w| w.invinp().set_bit());
|
iocfg.$portx[$i].modify(|_, w| w.invinp().set_bit());
|
||||||
} else {
|
} else {
|
||||||
reg.$portx[$i].modify(|_, w| w.invinp().clear_bit());
|
iocfg.$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 {
|
|
||||||
let reg = &(*IOCONFIG::ptr());
|
|
||||||
if enable {
|
if enable {
|
||||||
reg.$portx[$i].modify(|_, w| w.invout().set_bit());
|
iocfg.$portx[$i].modify(|_, w| w.invout().set_bit());
|
||||||
} else {
|
} else {
|
||||||
reg.$portx[$i].modify(|_, w| w.invout().clear_bit());
|
iocfg.$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 {
|
|
||||||
let reg = &(*IOCONFIG::ptr());
|
|
||||||
if enable {
|
if enable {
|
||||||
reg.$portx[$i].modify(|_, w| w.iewo().set_bit());
|
iocfg.$portx[$i].modify(|_, w| w.iewo().set_bit());
|
||||||
} else {
|
} else {
|
||||||
reg.$portx[$i].modify(|_, w| w.iewo().clear_bit());
|
iocfg.$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),
|
||||||
|
@ -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
4
src/prelude.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
//! Prelude
|
||||||
|
pub use embedded_hal::prelude::*;
|
||||||
|
|
||||||
|
pub use crate::gpio::GpioExt as _stm32h7xx_hal_gpio_GpioExt;
|
Reference in New Issue
Block a user