From 9181e61e700896d5f5a8966deb4b92dfbfe64178 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sat, 6 Nov 2021 01:27:04 +0100 Subject: [PATCH 1/6] Added first GPIO implementation - First GPIO implementation based on the stm32f0xx amd stm32f1xx HAL implementations for the HAL module --- .gitignore | 4 - Cargo.toml | 20 ++- src/gpio.rs | 505 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 7 + src/main.rs | 3 - 5 files changed, 530 insertions(+), 9 deletions(-) create mode 100644 src/gpio.rs create mode 100644 src/lib.rs delete mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore index 088ba6b..f2e972d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,9 +2,5 @@ # will have compiled files and executables /target/ -# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries -# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -Cargo.lock - # These are backup files generated by rustfmt **/*.rs.bk diff --git a/Cargo.toml b/Cargo.toml index 0db13d4..d93dbf1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,24 @@ [package] name = "va108xx-hal" version = "0.1.0" +authors = ["Robin Mueller "] edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +description = "HAL for the Vorago VA108xx family of microcontrollers" +homepage = "https://github.com/robamu/va108xx-hal-rs" +repository = "https://github.com/robamu/va108xx-hal-rs" +license = "MIT OR Apache-2.0" +keywords = ["no-std", "hal", "cortex-m", "vorago", "va108xx"] +categories = ["embedded", "no-std", "hardware-support"] [dependencies] + +cortex-m = "0.7.3" +cortex-m-rt = "0.7.0" +nb = "1" +embedded-hal = { features = ["unproven"], version = "0.2.6" } + +[dependencies.va108xx] +version = "0.1.0" + +[features] +rt = ["va108xx/rt"] \ No newline at end of file diff --git a/src/gpio.rs b/src/gpio.rs new file mode 100644 index 0000000..7174f53 --- /dev/null +++ b/src/gpio.rs @@ -0,0 +1,505 @@ +use crate::pac::SYSCONFIG; +use core::convert::Infallible; +use core::marker::PhantomData; +use embedded_hal::digital::v2::{toggleable, InputPin, OutputPin, StatefulOutputPin}; + +/// Extension trait to split a GPIO peripheral in independent pins and registers +pub trait GpioExt { + /// The parts to split the GPIO into. + type Parts; + + /// Splits the GPIO block into independent pins and registers. + fn split(self, syscfg: &mut SYSCONFIG) -> Self::Parts; +} + +trait GpioRegExt { + fn is_low(&self, pos: u8) -> bool; + fn is_set_low(&self, pos: u8) -> bool; + fn set_high(&self, pos: u8); + fn set_low(&self, pos: u8); +} + +/// Input mode (type state) +pub struct Input { + _mode: PhantomData, +} + +/// Output mode (type state) +pub struct Output { + _mode: PhantomData, +} + +/// Floating input (type state) +pub struct Floating; +/// Pulled down input (type state) +pub struct PullDown; +/// Pulled up input (type state) +pub struct PullUp; +/// Open drain output (type state) +pub struct OpenDrain; +// Push-pull output (type state) +pub struct PushPull; + +pub struct OutputInverted; + +pub struct InputInverted; + +// FUNSEL0 is the regular GPIO port configuration +pub struct FUNSEL1; +pub struct FUNSEL2; +pub struct FUNSEL3; + +/// Function select (type state) +pub struct Funsel { + _mode: PhantomData, +} + +pub enum FilterType { + SystemClock = 0, + DirectInputWithSynchronization = 1, + FilterOneClockCycle = 2, + FilterTwoClockCycles = 3, + FilterThreeClockCycles = 4, + FilterFourClockCycles = 5, +} + +pub enum FilterClkSel { + SysClk = 0, + Clk1 = 1, + Clk2 = 2, + Clk3 = 3, + Clk4 = 4, + Clk5 = 5, + Clk6 = 6, + Clk7 = 7, +} + +/// Fully erased pin +pub struct Pin { + i: u8, + port: *const dyn GpioRegExt, + _mode: PhantomData, +} +unsafe impl Sync for Pin {} +// NOTE(unsafe) this only enables read access to the same pin from multiple threads +unsafe impl Send for Pin {} +impl StatefulOutputPin for Pin> { + #[inline(always)] + fn is_set_high(&self) -> Result { + self.is_set_low().map(|v| !v) + } + #[inline(always)] + fn is_set_low(&self) -> Result { + Ok(unsafe { (*self.port).is_set_low(self.i) }) + } +} +impl OutputPin for Pin> { + type Error = Infallible; + #[inline(always)] + fn set_high(&mut self) -> Result<(), Self::Error> { + unsafe { (*self.port).set_high(self.i) }; + Ok(()) + } + #[inline(always)] + fn set_low(&mut self) -> Result<(), Self::Error> { + unsafe { (*self.port).set_low(self.i) } + Ok(()) + } +} +impl toggleable::Default for Pin> {} +impl InputPin for Pin> { + type Error = Infallible; + #[inline(always)] + fn is_high(&self) -> Result { + self.is_low().map(|v| !v) + } + #[inline(always)] + fn is_low(&self) -> Result { + Ok(unsafe { (*self.port).is_low(self.i) }) + } +} +impl InputPin for Pin> { + type Error = Infallible; + #[inline(always)] + fn is_high(&self) -> Result { + self.is_low().map(|v| !v) + } + #[inline(always)] + fn is_low(&self) -> Result { + Ok(unsafe { (*self.port).is_low(self.i) }) + } +} + +// This is only needs to be implemented for PORTA because PORTB is derived +// from PORTA +impl GpioRegExt for crate::pac::porta::RegisterBlock { + fn is_low(&self, pos: u8) -> bool { + self.datainraw().read().bits() & (1 << pos) == 0 + } + fn is_set_low(&self, pos: u8) -> bool { + // Note that this only works if the IENWO bit is enabled in IOCONFIG + // This is done by default for output pins for now + self.datainraw().read().bits() & (1 << pos) == 0 + } + fn set_high(&self, pos: u8) { + unsafe { self.setout().write(|w| w.bits(1 << pos)) } + } + fn set_low(&self, pos: u8) { + unsafe { self.clrout().write(|w| w.bits(1 << pos)) } + } +} + +macro_rules! gpio { + ($PORTX:ident, $portx:ident, [ + $($PXi:ident: ($pxi:ident, $i:expr),)+ + ]) => { + pub mod $portx { + use core::marker::PhantomData; + use core::convert::Infallible; + use cortex_m::interrupt::CriticalSection; + use super::{ + FUNSEL1, FUNSEL2, FUNSEL3, Floating, Funsel, GpioExt, Input, OpenDrain, + PullUp, Output, FilterType, FilterClkSel, Pin, GpioRegExt, PushPull + }; + use crate::{pac::$PORTX, pac::SYSCONFIG, pac::IOCONFIG}; + use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, toggleable}; + pub struct Parts { + $( + pub $pxi: $PXi>, + )+ + } + + impl GpioExt for $PORTX { + type Parts = Parts; + fn split(self, syscfg: &mut SYSCONFIG) -> Parts { + syscfg.peripheral_clk_enable.modify(|_, w| { + w.$portx().set_bit(); + w.gpio().set_bit(); + w.ioconfig().set_bit(); + w + }); + Parts { + $( + $pxi: $PXi { _mode : PhantomData }, + )+ + } + } + } + + fn _set_alternate_mode(index: usize, mode: u8) { + unsafe { + let reg = &(*IOCONFIG::ptr()); + reg.$portx[index].modify(|_, w| { + w.funsel().bits(mode) + }) + } + } + + $( + pub struct $PXi { + _mode: PhantomData, + } + + impl $PXi { + pub fn into_funsel_1(self, _cs: &CriticalSection) -> $PXi> { + _set_alternate_mode(0, 1); + $PXi { _mode: PhantomData } + } + pub fn into_funsel_2(self, _cs: &CriticalSection) -> $PXi> { + _set_alternate_mode(0, 2); + $PXi { _mode: PhantomData } + } + pub fn into_funsel_3(self, _cs: &CriticalSection) -> $PXi> { + _set_alternate_mode(0, 3); + $PXi { _mode: PhantomData } + } + pub fn into_floating_input(self, _cs: &CriticalSection) -> $PXi> { + unsafe { + let reg = &(*IOCONFIG::ptr()); + reg.$portx[0].modify(|_, w| { + w.funsel().bits(0); + w.pen().clear_bit(); + w.opendrn().clear_bit() + }); + let port_reg = &(*$PORTX::ptr()); + port_reg.dir().modify(|r,w| w.bits(r.bits() & !(1 << 0))); + } + $PXi { _mode: PhantomData } + } + + pub fn into_pull_up_input(self, _cs: &CriticalSection) -> $PXi> { + unsafe { + let reg = &(*IOCONFIG::ptr()); + reg.$portx[0].modify(|_, w| { + w.funsel().bits(0); + w.pen().set_bit(); + w.plevel().set_bit(); + w.opendrn().clear_bit() + }); + let port_reg = &(*$PORTX::ptr()); + port_reg.dir().modify(|r,w| w.bits(r.bits() & !(1 << 0))); + } + $PXi { _mode: PhantomData } + } + + pub fn into_pull_down_input(self, _cs: &CriticalSection) -> $PXi> { + unsafe { + let reg = &(*IOCONFIG::ptr()); + reg.$portx[0].modify(|_, w| { + w.funsel().bits(0); + w.pen().set_bit(); + w.plevel().clear_bit(); + w.opendrn().clear_bit() + }); + let port_reg = &(*$PORTX::ptr()); + port_reg.dir().modify(|r,w| w.bits(r.bits() & !(1 << 0))); + } + $PXi { _mode: PhantomData } + } + + pub fn into_open_drain_output(self, _cs: &CriticalSection) -> $PXi> { + unsafe { + let reg = &(*IOCONFIG::ptr()); + reg.$portx[$i].modify(|_, w| { + w.funsel().bits(0); + w.pen().clear_bit(); + w.opendrn().set_bit() + }); + let port_reg = &(*$PORTX::ptr()); + port_reg.dir().modify(|r,w| w.bits(r.bits() | (1 << 0))); + } + let $pxi: $PXi> = $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> { + unsafe { + let reg = &(*IOCONFIG::ptr()); + reg.$portx[$i].modify(|_, w| { + w.funsel().bits(0); + w.opendrn().clear_bit() + }); + let port_reg = &(*$PORTX::ptr()); + port_reg.dir().modify(|r,w| w.bits(r.bits() | (1 << 0))); + } + let $pxi: $PXi> = $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 { + unsafe { + let reg = &(*IOCONFIG::ptr()); + reg.$portx[$i].modify(|_, w| { + w.flttype().bits(filter as u8); + w.fltclk().bits(clksel as u8) + }) + } + self + } + } + + impl $PXi> { + pub fn input_inversion(self, _cs: &CriticalSection, enable: bool) -> Self { + unsafe { + let reg = &(*IOCONFIG::ptr()); + if enable { + reg.$portx[$i].modify(|_, w| w.invinp().set_bit()); + } else { + reg.$portx[$i].modify(|_, w| w.invinp().clear_bit()); + } + } + self + } + } + + impl $PXi> { + pub fn output_inversion(self, _cs: &CriticalSection, enable: bool) -> Self { + unsafe { + let reg = &(*IOCONFIG::ptr()); + if enable { + reg.$portx[$i].modify(|_, w| w.invout().set_bit()); + } else { + reg.$portx[$i].modify(|_, w| w.invout().clear_bit()); + } + } + self + } + + /// Enable Input even when in output mode. In + /// this mode the input receiver is enabled even + /// if the direction is configured as an output. + /// This allows monitoring of output values + pub fn enable_input(self, _cs: &CriticalSection, enable: bool) -> Self { + unsafe { + let reg = &(*IOCONFIG::ptr()); + if enable { + reg.$portx[$i].modify(|_, w| w.iewo().set_bit()); + } else { + reg.$portx[$i].modify(|_, w| w.iewo().clear_bit()); + } + } + self + } + + /// Enable Pull up/down even when output is active. The Default is to disable pull + /// up/down when output is actively driven. This bit enables the pull up/down all the time. + /// + /// # Arguments + /// + /// `enable` - Enable the peripheral functionality + /// `enable_pullup` - Enable the pullup itself + pub fn enable_pull_up(self, _cs: &CriticalSection, enable: bool, enable_pullup: bool) -> Self { + unsafe { + let reg = &(*IOCONFIG::ptr()); + reg.$portx[$i].modify(|_, w| { + if enable { w.pwoa().set_bit(); } else { w.pwoa().clear_bit(); } + if enable_pullup { w.pen().set_bit(); } else { w.pen().clear_bit(); } + w.plevel().set_bit() + }); + } + self + } + /// Enable Pull up/down even when output is active. The Default is to disable pull + /// up/down when output is actively driven. This bit enables the pull up/down all the time. + /// + /// # Arguments + /// + /// `enable` - Enable the peripheral functionality + /// `enable_pullup` - Enable the pulldown itself + pub fn enable_pull_down(self, _cs: &CriticalSection, enable: bool, enable_pulldown: bool) -> Self { + unsafe { + let reg = &(*IOCONFIG::ptr()); + reg.$portx[$i].modify(|_, w| { + if enable { w.pwoa().set_bit(); } else { w.pwoa().clear_bit(); } + if enable_pulldown { w.pen().set_bit(); } else { w.pen().clear_bit(); } + w.plevel().clear_bit() + }); + } + self + } + } + + impl $PXi> { + /// Erases the pin number from the type + /// + /// This is useful when you want to collect the pins into an array where you + /// need all the elements to have the same type + pub fn downgrade(self) -> Pin> { + Pin { + i: $i, + port: $PORTX::ptr() as *const dyn GpioRegExt, + _mode: self._mode, + } + } + } + + impl StatefulOutputPin for $PXi> { + fn is_set_high(&self) -> Result { + self.is_set_low().map(|v| !v) + } + fn is_set_low(&self) -> Result { + Ok(unsafe { (*$PORTX::ptr()).is_set_low(0) }) + } + } + impl OutputPin for $PXi> { + type Error = Infallible; + fn set_high(&mut self) -> Result<(), Self::Error> { + Ok(unsafe { (*$PORTX::ptr()).set_high(0) }) + } + fn set_low(&mut self) -> Result<(), Self::Error> { + Ok(unsafe { (*$PORTX::ptr()).set_low(0) }) + } + } + impl toggleable::Default for $PXi> {} + impl $PXi> { + /// Erases the pin number from the type + /// + /// This is useful when you want to collect the pins into an array where you + /// need all the elements to have the same type + pub fn downgrade(self) -> Pin> { + Pin { + i: $i, + port: $PORTX::ptr() as *const dyn GpioRegExt, + _mode: self._mode, + } + } + } + impl InputPin for $PXi> { + type Error = Infallible; + fn is_high(&self) -> Result { + self.is_low().map(|v| !v) + } + fn is_low(&self) -> Result { + Ok(unsafe { (*$PORTX::ptr()).is_low(0) }) + } + } + )+ + } + } +} + +gpio!(PORTA, porta, [ + PA0: (pa0, 0), + PA1: (pa1, 1), + PA2: (pa2, 2), + PA3: (pa3, 3), + PA4: (pa4, 4), + PA5: (pa5, 5), + PA6: (pa6, 6), + PA7: (pa7, 7), + PA8: (pa8, 8), + PA9: (pa9, 9), + PA10: (pa10, 10), + PA11: (pa11, 11), + PA12: (pa12, 12), + PA13: (pa13, 13), + PA14: (pa14, 14), + PA15: (pa15, 15), + PA16: (pa16, 16), + PA17: (pa17, 17), + PA18: (pa18, 18), + PA19: (pa19, 19), + PA20: (pa20, 20), + PA21: (pa21, 21), + PA22: (pa22, 22), + PA23: (pa23, 23), + PA24: (pa24, 24), + PA25: (pa25, 25), + PA26: (pa26, 26), + PA27: (pa27, 27), + PA28: (pa28, 28), + PA29: (pa29, 29), + PA30: (pa30, 30), + PA31: (pa31, 31), +]); + +gpio!(PORTB, portb, [ + PB0: (pb0, 0), + PB1: (pb1, 1), + PB2: (pb2, 2), + PB3: (pb3, 3), + PB4: (pb4, 4), + PB5: (pb5, 5), + PB6: (pb6, 6), + PB7: (pb7, 7), + PB8: (pb8, 8), + PB9: (pb9, 9), + PB10: (pb10, 10), + PB11: (pb11, 11), + PB12: (pb12, 12), + PB13: (pb13, 13), + PB14: (pb14, 14), + PB15: (pb15, 15), + PB16: (pb16, 16), + PB17: (pb17, 17), + PB18: (pb18, 18), + PB19: (pb19, 19), + PB20: (pb20, 20), + PB21: (pb21, 21), + PB22: (pb22, 22), + PB23: (pb23, 23), +]); diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..a8c2307 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,7 @@ +#![no_std] + +pub use va108xx; + +pub mod gpio; + +pub use va108xx as pac; diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} From 9020fc92d03701f7d2dbbac29434724ceb34072f Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sat, 6 Nov 2021 16:16:53 +0100 Subject: [PATCH 2/6] Refactored parts of the GPIO implementation --- Cargo.toml | 2 +- src/gpio.rs | 268 ++++++++++++++++++++++++++++--------------------- src/lib.rs | 2 +- src/prelude.rs | 4 + 4 files changed, 161 insertions(+), 115 deletions(-) create mode 100644 src/prelude.rs diff --git a/Cargo.toml b/Cargo.toml index d93dbf1..4f3d5a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ nb = "1" embedded-hal = { features = ["unproven"], version = "0.2.6" } [dependencies.va108xx] -version = "0.1.0" +version = "0.1" [features] rt = ["va108xx/rt"] \ No newline at end of file diff --git a/src/gpio.rs b/src/gpio.rs index 7174f53..27e7b0b 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -1,7 +1,8 @@ use crate::pac::SYSCONFIG; use core::convert::Infallible; 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 pub trait GpioExt { @@ -9,14 +10,21 @@ pub trait GpioExt { type Parts; /// 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 { 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; + fn input_enabled_for_output(&self, pos: usize, port_id: char) -> bool; fn set_high(&self, pos: u8); fn set_low(&self, pos: u8); + fn toggle(&self, pos: u8); } /// Input mode (type state) @@ -77,10 +85,10 @@ pub enum FilterClkSel { /// Fully erased pin pub struct Pin { i: u8, + port_id: char, port: *const dyn GpioRegExt, _mode: PhantomData, } -unsafe impl Sync for Pin {} // NOTE(unsafe) this only enables read access to the same pin from multiple threads unsafe impl Send for Pin {} impl StatefulOutputPin for Pin> { @@ -90,11 +98,11 @@ impl StatefulOutputPin for Pin> { } #[inline(always)] fn is_set_low(&self) -> Result { - Ok(unsafe { (*self.port).is_set_low(self.i) }) + unsafe { (*self.port).is_set_low(self.i.into(), self.port_id) } } } impl OutputPin for Pin> { - type Error = Infallible; + type Error = PinModeError; #[inline(always)] fn set_high(&mut self) -> Result<(), Self::Error> { unsafe { (*self.port).set_high(self.i) }; @@ -106,7 +114,16 @@ impl OutputPin for Pin> { Ok(()) } } -impl toggleable::Default for Pin> {} + +impl ToggleableOutputPin for Pin> { + type Error = Infallible; + #[inline(always)] + fn toggle(&mut self) -> Result<(), Self::Error> { + unsafe { (*self.port).toggle(self.i) } + Ok(()) + } +} + impl InputPin for Pin> { type Error = Infallible; #[inline(always)] @@ -133,36 +150,59 @@ impl InputPin for Pin> { // This is only needs to be implemented for PORTA because PORTB is derived // from PORTA impl GpioRegExt for crate::pac::porta::RegisterBlock { + #[inline(always)] fn is_low(&self, pos: u8) -> bool { self.datainraw().read().bits() & (1 << pos) == 0 } - fn is_set_low(&self, pos: u8) -> bool { - // Note that this only works if the IENWO bit is enabled in IOCONFIG - // This is done by default for output pins for now - self.datainraw().read().bits() & (1 << pos) == 0 + #[inline(always)] + fn is_set_low(&self, pos: usize, port_id: char) -> Result { + if self.input_enabled_for_output(pos, port_id) { + Ok(self.datainraw().read().bits() & (1 << pos) == 0) + } else { + Err(PinModeError::InputDisabledForOutput) + } } + #[inline(always)] fn set_high(&self, pos: u8) { unsafe { self.setout().write(|w| w.bits(1 << pos)) } } + #[inline(always)] fn set_low(&self, pos: u8) { 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 { - ($PORTX:ident, $portx:ident, [ + ($PORTX:ident, $portx:ident, $port_id:expr, [ $($PXi:ident: ($pxi:ident, $i:expr),)+ ]) => { pub mod $portx { use core::marker::PhantomData; use core::convert::Infallible; - use cortex_m::interrupt::CriticalSection; use super::{ 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 embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, toggleable}; + use embedded_hal::digital::v2::{ + InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin + }; pub struct Parts { $( pub $pxi: $PXi>, @@ -171,7 +211,7 @@ macro_rules! gpio { impl GpioExt for $PORTX { type Parts = Parts; - fn split(self, syscfg: &mut SYSCONFIG) -> Parts { + fn split(&mut self, syscfg: &mut SYSCONFIG) -> Parts { syscfg.peripheral_clk_enable.modify(|_, w| { w.$portx().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 { - let reg = &(*IOCONFIG::ptr()); - reg.$portx[index].modify(|_, w| { + iocfg.$portx[index].modify(|_, w| { w.funsel().bits(mode) }) } @@ -201,130 +240,120 @@ macro_rules! gpio { } impl $PXi { - pub fn into_funsel_1(self, _cs: &CriticalSection) -> $PXi> { - _set_alternate_mode(0, 1); + pub fn into_funsel_1(self, iocfg: &mut IOCONFIG) -> $PXi> { + _set_alternate_mode(iocfg, $i, 1); $PXi { _mode: PhantomData } } - pub fn into_funsel_2(self, _cs: &CriticalSection) -> $PXi> { - _set_alternate_mode(0, 2); + pub fn into_funsel_2(self, iocfg: &mut IOCONFIG) -> $PXi> { + _set_alternate_mode(iocfg, $i, 2); $PXi { _mode: PhantomData } } - pub fn into_funsel_3(self, _cs: &CriticalSection) -> $PXi> { - _set_alternate_mode(0, 3); + pub fn into_funsel_3(self, iocfg: &mut IOCONFIG) -> $PXi> { + _set_alternate_mode(iocfg, $i, 3); $PXi { _mode: PhantomData } } - pub fn into_floating_input(self, _cs: &CriticalSection) -> $PXi> { + pub fn into_floating_input( + self, iocfg: &mut IOCONFIG + ) -> $PXi> { unsafe { - let reg = &(*IOCONFIG::ptr()); - reg.$portx[0].modify(|_, w| { + iocfg.$portx[$i].modify(|_, w| { w.funsel().bits(0); w.pen().clear_bit(); w.opendrn().clear_bit() }); 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 } } - pub fn into_pull_up_input(self, _cs: &CriticalSection) -> $PXi> { + pub fn into_pull_up_input(self, iocfg: &mut IOCONFIG) -> $PXi> { unsafe { - let reg = &(*IOCONFIG::ptr()); - reg.$portx[0].modify(|_, w| { + iocfg.$portx[$i].modify(|_, w| { w.funsel().bits(0); w.pen().set_bit(); w.plevel().set_bit(); w.opendrn().clear_bit() }); 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 } } - pub fn into_pull_down_input(self, _cs: &CriticalSection) -> $PXi> { + pub fn into_pull_down_input( + self, iocfg: &mut IOCONFIG, port_reg: &mut $PORTX + ) -> $PXi> { unsafe { - let reg = &(*IOCONFIG::ptr()); - reg.$portx[0].modify(|_, w| { + iocfg.$portx[$i].modify(|_, w| { w.funsel().bits(0); w.pen().set_bit(); w.plevel().clear_bit(); w.opendrn().clear_bit() }); - 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 } } - pub fn into_open_drain_output(self, _cs: &CriticalSection) -> $PXi> { + pub fn into_open_drain_output( + self, iocfg: &mut IOCONFIG + ) -> $PXi> { unsafe { - let reg = &(*IOCONFIG::ptr()); - reg.$portx[$i].modify(|_, w| { + iocfg.$portx[$i].modify(|_, w| { w.funsel().bits(0); w.pen().clear_bit(); w.opendrn().set_bit() }); 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> = $PXi { _mode: PhantomData }; - // Enable input functionality by default to ensure this is a stateful output pin - let $pxi = $pxi.enable_input(_cs, true); - $pxi + $PXi { _mode: PhantomData } } - pub fn into_push_pull_output(self, _cs: &CriticalSection) -> $PXi> { + pub fn into_push_pull_output( + self, iocfg: &mut IOCONFIG, port_reg: &mut $PORTX + ) -> $PXi> { unsafe { - let reg = &(*IOCONFIG::ptr()); - reg.$portx[$i].modify(|_, w| { + iocfg.$portx[$i].modify(|_, w| { w.funsel().bits(0); w.opendrn().clear_bit() }); - 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> = $PXi { _mode: PhantomData }; - // Enable input functionality by default to ensure this is a stateful output pin - let $pxi = $pxi.enable_input(_cs, true); - $pxi + $PXi { _mode: PhantomData } } - 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 { - let reg = &(*IOCONFIG::ptr()); - reg.$portx[$i].modify(|_, w| { + iocfg.$portx[$i].modify(|_, w| { w.flttype().bits(filter as u8); w.fltclk().bits(clksel as u8) - }) + }); } self } } impl $PXi> { - pub fn input_inversion(self, _cs: &CriticalSection, enable: bool) -> Self { - unsafe { - let reg = &(*IOCONFIG::ptr()); - if enable { - reg.$portx[$i].modify(|_, w| w.invinp().set_bit()); - } else { - reg.$portx[$i].modify(|_, w| w.invinp().clear_bit()); - } + pub fn input_inversion(self, iocfg: &mut IOCONFIG, enable: bool) -> Self { + if enable { + iocfg.$portx[$i].modify(|_, w| w.invinp().set_bit()); + } else { + iocfg.$portx[$i].modify(|_, w| w.invinp().clear_bit()); } self } } impl $PXi> { - pub fn output_inversion(self, _cs: &CriticalSection, enable: bool) -> Self { - unsafe { - let reg = &(*IOCONFIG::ptr()); - if enable { - reg.$portx[$i].modify(|_, w| w.invout().set_bit()); - } else { - reg.$portx[$i].modify(|_, w| w.invout().clear_bit()); - } + pub fn output_inversion(self, iocfg: &mut IOCONFIG, enable: bool) -> Self { + if enable { + iocfg.$portx[$i].modify(|_, w| w.invout().set_bit()); + } else { + iocfg.$portx[$i].modify(|_, w| w.invout().clear_bit()); } self } @@ -333,52 +362,49 @@ macro_rules! gpio { /// this mode the input receiver is enabled even /// if the direction is configured as an output. /// This allows monitoring of output values - pub fn enable_input(self, _cs: &CriticalSection, enable: bool) -> Self { - unsafe { - let reg = &(*IOCONFIG::ptr()); - if enable { - reg.$portx[$i].modify(|_, w| w.iewo().set_bit()); - } else { - reg.$portx[$i].modify(|_, w| w.iewo().clear_bit()); - } + pub fn enable_input(self, iocfg: &mut IOCONFIG, enable: bool) -> Self { + if enable { + iocfg.$portx[$i].modify(|_, w| w.iewo().set_bit()); + } else { + iocfg.$portx[$i].modify(|_, w| w.iewo().clear_bit()); } self } - /// Enable Pull up/down even when output is active. The Default is to disable pull - /// up/down when output is actively driven. This bit enables the pull up/down all the time. + /// Enable Pull up/down even when output is active. The Default is to + /// disable pull up/down when output is actively driven. This bit enables the + /// pull up/down all the time. /// /// # Arguments /// /// `enable` - Enable the peripheral functionality /// `enable_pullup` - Enable the pullup itself - pub fn enable_pull_up(self, _cs: &CriticalSection, enable: bool, enable_pullup: bool) -> Self { - unsafe { - let reg = &(*IOCONFIG::ptr()); - reg.$portx[$i].modify(|_, w| { - if enable { w.pwoa().set_bit(); } else { w.pwoa().clear_bit(); } - if enable_pullup { w.pen().set_bit(); } else { w.pen().clear_bit(); } - w.plevel().set_bit() - }); - } + pub fn enable_pull_up( + self, iocfg: &mut IOCONFIG, enable: bool, enable_pullup: bool + ) -> Self { + iocfg.$portx[$i].modify(|_, w| { + if enable { w.pwoa().set_bit(); } else { w.pwoa().clear_bit(); } + if enable_pullup { w.pen().set_bit(); } else { w.pen().clear_bit(); } + w.plevel().set_bit() + }); self } - /// Enable Pull up/down even when output is active. The Default is to disable pull - /// up/down when output is actively driven. This bit enables the pull up/down all the time. + /// Enable Pull up/down even when output is active. The Default is to disable + /// pull up/down when output is actively driven. This bit enables the + /// pull up/down all the time. /// /// # Arguments /// /// `enable` - Enable the peripheral functionality /// `enable_pullup` - Enable the pulldown itself - pub fn enable_pull_down(self, _cs: &CriticalSection, enable: bool, enable_pulldown: bool) -> Self { - unsafe { - let reg = &(*IOCONFIG::ptr()); - reg.$portx[$i].modify(|_, w| { - if enable { w.pwoa().set_bit(); } else { w.pwoa().clear_bit(); } - if enable_pulldown { w.pen().set_bit(); } else { w.pen().clear_bit(); } - w.plevel().clear_bit() - }); - } + pub fn enable_pull_down( + self, iocfg: &mut IOCONFIG, enable: bool, enable_pulldown: bool + ) -> Self { + iocfg.$portx[$i].modify(|_, w| { + if enable { w.pwoa().set_bit(); } else { w.pwoa().clear_bit(); } + if enable_pulldown { w.pen().set_bit(); } else { w.pen().clear_bit(); } + w.plevel().clear_bit() + }); self } } @@ -391,6 +417,7 @@ macro_rules! gpio { pub fn downgrade(self) -> Pin> { Pin { i: $i, + port_id: $port_id, port: $PORTX::ptr() as *const dyn GpioRegExt, _mode: self._mode, } @@ -398,23 +425,35 @@ macro_rules! gpio { } impl StatefulOutputPin for $PXi> { + #[inline(always)] fn is_set_high(&self) -> Result { self.is_set_low().map(|v| !v) } + #[inline(always)] fn is_set_low(&self) -> Result { - Ok(unsafe { (*$PORTX::ptr()).is_set_low(0) }) + unsafe { + (*$PORTX::ptr()).is_set_low($i, $port_id) + } } } impl OutputPin for $PXi> { - type Error = Infallible; + type Error = PinModeError; + #[inline(always)] 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> { - Ok(unsafe { (*$PORTX::ptr()).set_low(0) }) + Ok(unsafe { (*$PORTX::ptr()).set_low($i) }) + } + } + impl ToggleableOutputPin for $PXi> { + type Error = Infallible; + #[inline(always)] + fn toggle(&mut self) -> Result<(), Self::Error> { + Ok(unsafe { (*$PORTX::ptr()).toggle($i) }) } } - impl toggleable::Default for $PXi> {} impl $PXi> { /// Erases the pin number from the type /// @@ -423,6 +462,7 @@ macro_rules! gpio { pub fn downgrade(self) -> Pin> { Pin { i: $i, + port_id: $port_id, port: $PORTX::ptr() as *const dyn GpioRegExt, _mode: self._mode, } @@ -430,11 +470,13 @@ macro_rules! gpio { } impl InputPin for $PXi> { type Error = Infallible; + #[inline(always)] fn is_high(&self) -> Result { self.is_low().map(|v| !v) } + #[inline(always)] fn is_low(&self) -> Result { - 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), PA1: (pa1, 1), PA2: (pa2, 2), @@ -477,7 +519,7 @@ gpio!(PORTA, porta, [ PA31: (pa31, 31), ]); -gpio!(PORTB, portb, [ +gpio!(PORTB, portb, 'B', [ PB0: (pb0, 0), PB1: (pb1, 1), PB2: (pb2, 2), diff --git a/src/lib.rs b/src/lib.rs index a8c2307..ccc7032 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,5 +3,5 @@ pub use va108xx; pub mod gpio; - +pub mod prelude; pub use va108xx as pac; diff --git a/src/prelude.rs b/src/prelude.rs new file mode 100644 index 0000000..6dacac5 --- /dev/null +++ b/src/prelude.rs @@ -0,0 +1,4 @@ +//! Prelude +pub use embedded_hal::prelude::*; + +pub use crate::gpio::GpioExt as _stm32h7xx_hal_gpio_GpioExt; From 1e1b7f3c9ff029c58b0d29f89fa6634fb94b8ff4 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sat, 6 Nov 2021 16:19:38 +0100 Subject: [PATCH 3/6] fix prelude naming --- src/prelude.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prelude.rs b/src/prelude.rs index 6dacac5..bbdbc4f 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,4 +1,4 @@ //! Prelude pub use embedded_hal::prelude::*; -pub use crate::gpio::GpioExt as _stm32h7xx_hal_gpio_GpioExt; +pub use crate::gpio::GpioExt as _va108xx_hal_gpio_GpioExt; From a463332d582d0440c1212d409adb0a606a338ea6 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sat, 6 Nov 2021 17:10:06 +0100 Subject: [PATCH 4/6] optimize for size by default --- Cargo.toml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4f3d5a5..fe3dc70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,4 +21,13 @@ embedded-hal = { features = ["unproven"], version = "0.2.6" } version = "0.1" [features] -rt = ["va108xx/rt"] \ No newline at end of file +rt = ["va108xx/rt"] + +[profile.dev] +debug = true +lto = true + +[profile.release] +lto = true +debug = true +opt-level = "s" From 021efc5a5a27dedf0e51b7f6cdf2afb6080a643b Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 8 Nov 2021 01:01:44 +0100 Subject: [PATCH 5/6] Update GPIO code --- src/gpio.rs | 156 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 135 insertions(+), 21 deletions(-) diff --git a/src/gpio.rs b/src/gpio.rs index 27e7b0b..f84834e 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -1,4 +1,5 @@ use crate::pac::SYSCONFIG; +use cortex_m::singleton; use core::convert::Infallible; use core::marker::PhantomData; use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin}; @@ -10,18 +11,30 @@ pub trait GpioExt { type Parts; /// Splits the GPIO block into independent pins and registers. - fn split(&mut self, syscfg: &mut SYSCONFIG) -> Self::Parts; + fn split(&mut self, syscfg: &mut SYSCONFIG) -> Option; } #[derive(Debug, PartialEq)] pub enum PinModeError { InputDisabledForOutput, + IsMasked, +} + +#[derive(Debug, PartialEq)] +pub enum PinState { + Low = 0, + High = 1, +} + +enum PortId { + A, + B } trait GpioRegExt { fn is_low(&self, pos: u8) -> bool; - fn is_set_low(&self, pos: usize, port_id: char) -> Result; - fn input_enabled_for_output(&self, pos: usize, port_id: char) -> bool; + fn is_set_low(&self, pos: usize, port_id: &PortId) -> Result; + fn input_enabled_for_output(&self, pos: usize, port_id: &PortId) -> bool; fn set_high(&self, pos: u8); fn set_low(&self, pos: u8); fn toggle(&self, pos: u8); @@ -85,7 +98,7 @@ pub enum FilterClkSel { /// Fully erased pin pub struct Pin { i: u8, - port_id: char, + port_id: PortId, port: *const dyn GpioRegExt, _mode: PhantomData, } @@ -98,7 +111,7 @@ impl StatefulOutputPin for Pin> { } #[inline(always)] fn is_set_low(&self) -> Result { - unsafe { (*self.port).is_set_low(self.i.into(), self.port_id) } + unsafe { (*self.port).is_set_low(self.i.into(), &self.port_id) } } } impl OutputPin for Pin> { @@ -155,7 +168,7 @@ impl GpioRegExt for crate::pac::porta::RegisterBlock { self.datainraw().read().bits() & (1 << pos) == 0 } #[inline(always)] - fn is_set_low(&self, pos: usize, port_id: char) -> Result { + fn is_set_low(&self, pos: usize, port_id: &PortId) -> Result { if self.input_enabled_for_output(pos, port_id) { Ok(self.datainraw().read().bits() & (1 << pos) == 0) } else { @@ -175,20 +188,19 @@ impl GpioRegExt for crate::pac::porta::RegisterBlock { unsafe { self.togout().write(|w| w.bits(1 << pos)) } } #[inline(always)] - fn input_enabled_for_output(&self, pos: usize, port_id: char) -> bool { + fn input_enabled_for_output(&self, pos: usize, port_id: &PortId) -> 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(), + PortId::A => iocfg.porta[pos].read().iewo().bit_is_set(), + PortId::B => iocfg.portb[pos].read().iewo().bit_is_set(), } } } } macro_rules! gpio { - ($PORTX:ident, $portx:ident, $port_id:expr, [ + ($PORTX:ident, $portx:ident, $port_id:path, [ $($PXi:ident: ($pxi:ident, $i:expr),)+ ]) => { pub mod $portx { @@ -197,7 +209,7 @@ macro_rules! gpio { use super::{ FUNSEL1, FUNSEL2, FUNSEL3, Floating, Funsel, GpioExt, Input, OpenDrain, PullUp, Output, FilterType, FilterClkSel, Pin, GpioRegExt, PushPull, - PinModeError + PinModeError, PinState, PortId, singleton }; use crate::{pac::$PORTX, pac::SYSCONFIG, pac::IOCONFIG}; use embedded_hal::digital::v2::{ @@ -209,20 +221,28 @@ macro_rules! gpio { )+ } + pub fn get_perid(port: &$PORTX) -> u32 { + port.perid.read().bits() + } + impl GpioExt for $PORTX { type Parts = Parts; - fn split(&mut self, syscfg: &mut SYSCONFIG) -> Parts { + + /// This function splits the PORT into the individual pins + /// Should only be called once and returns None on subsequent calls + fn split(&mut self, syscfg: &mut SYSCONFIG) -> Option { + let _: &'static mut bool = singleton!(: bool = false)?; syscfg.peripheral_clk_enable.modify(|_, w| { w.$portx().set_bit(); w.gpio().set_bit(); w.ioconfig().set_bit(); w }); - Parts { + Some(Parts { $( $pxi: $PXi { _mode : PhantomData }, )+ - } + }) } } @@ -252,8 +272,34 @@ macro_rules! gpio { _set_alternate_mode(iocfg, $i, 3); $PXi { _mode: PhantomData } } + + // Get DATAMASK bit for this particular pin + #[inline(always)] + pub fn datamask(&self, port: &$PORTX) -> bool { + (port.datamask().read().bits() >> $i) == 1 + } + /// Set DATAMASK bit for this particular pin. 1 is the default + /// state of the bit and allows access of the corresponding bit + #[inline(always)] + pub fn set_datamask(self, port: &mut $PORTX) -> Self { + unsafe { + port.datamask().modify(|r, w| w.bits(r.bits() | (1 << $i))) + } + self + } + + /// Clear DATAMASK bit for this particular pin. This prevents access + /// of the corresponding bit for output and input operations + #[inline(always)] + pub fn clear_datamask(self, port: &mut $PORTX) -> Self { + unsafe { + port.datamask().modify(|r, w| w.bits(r.bits() & !(1 << $i))) + } + self + } + pub fn into_floating_input( - self, iocfg: &mut IOCONFIG + self, iocfg: &mut IOCONFIG, port: &mut $PORTX ) -> $PXi> { unsafe { iocfg.$portx[$i].modify(|_, w| { @@ -261,8 +307,7 @@ macro_rules! gpio { w.pen().clear_bit(); w.opendrn().clear_bit() }); - let port_reg = &(*$PORTX::ptr()); - port_reg.dir().modify(|r,w| w.bits(r.bits() & !(1 << $i))); + port.dir().modify(|r,w| w.bits(r.bits() & !(1 << $i))); } $PXi { _mode: PhantomData } } @@ -320,6 +365,7 @@ macro_rules! gpio { w.opendrn().clear_bit() }); port_reg.dir().modify(|r,w| w.bits(r.bits() | (1 << $i))); + port_reg.clrout().write(|w| w.bits(1 << $i)) } $PXi { _mode: PhantomData } } @@ -346,6 +392,22 @@ macro_rules! gpio { } self } + + /// This function takes account for the data mask register + #[inline(always)] + pub fn is_high_masked(&self, port: &$PORTX) -> Result { + self.is_low_masked(port).map(|v| !v) + } + + /// This function takes account for the data mask register + #[inline(always)] + pub fn is_low_masked(&self, port: &$PORTX) -> Result { + if ((port.datamask().read().bits() >> $i) & 1) == 0 { + Err(PinModeError::IsMasked) + } else { + Ok(port.datain().read().bits() & (1 << $i) == 0) + } + } } impl $PXi> { @@ -422,6 +484,58 @@ macro_rules! gpio { _mode: self._mode, } } + + /// This function takes account for the data mask register + #[inline(always)] + pub fn set_low_masked(&self, port: &$PORTX) -> Result<(), PinModeError> { + if ((port.datamask().read().bits() >> $i) & 1) == 0 { + Err(PinModeError::IsMasked) + } else { + Ok(unsafe { (*$PORTX::ptr()).set_low($i) }) + } + } + /// This function takes account for the data mask register + #[inline(always)] + pub fn set_high_masked(&self, port: &$PORTX) -> Result<(), PinModeError> { + if ((port.datamask().read().bits() >> $i) & 1) == 0 { + Err(PinModeError::IsMasked) + } else { + Ok(unsafe { (*$PORTX::ptr()).set_high($i) }) + } + } + + pub fn pulse_mode(self, port: &mut $PORTX, enable: bool, default_state: PinState) -> Self { + unsafe { + if enable { + port.pulse().modify(|r, w| w.bits(r.bits() | (1 << $i))); + } else { + port.pulse().modify(|r, w| w.bits(r.bits() & !(1 << $i))); + } + if default_state == PinState::Low { + port.pulsebase().modify(|r,w| w.bits(r.bits() & !(1 << $i))); + } + else { + port.pulsebase().modify(|r,w| w.bits(r.bits() | (1 << $i))); + } + } + self + } + + pub fn delay(self, port: &mut $PORTX, delay_1: bool, delay_2: bool) -> Self { + unsafe { + if delay_1 { + port.delay1().modify(|r, w| w.bits(r.bits() | (1 << $i))); + } else { + port.delay1().modify(|r, w| w.bits(r.bits() & !(1 << $i))); + } + if delay_2 { + port.delay2().modify(|r, w| w.bits(r.bits() | (1 << $i))); + } else { + port.delay2().modify(|r, w| w.bits(r.bits() & !(1 << $i))); + } + } + self + } } impl StatefulOutputPin for $PXi> { @@ -432,7 +546,7 @@ macro_rules! gpio { #[inline(always)] fn is_set_low(&self) -> Result { unsafe { - (*$PORTX::ptr()).is_set_low($i, $port_id) + (*$PORTX::ptr()).is_set_low($i, &$port_id) } } } @@ -484,7 +598,7 @@ macro_rules! gpio { } } -gpio!(PORTA, porta, 'A', [ +gpio!(PORTA, porta, PortId::A, [ PA0: (pa0, 0), PA1: (pa1, 1), PA2: (pa2, 2), @@ -519,7 +633,7 @@ gpio!(PORTA, porta, 'A', [ PA31: (pa31, 31), ]); -gpio!(PORTB, portb, 'B', [ +gpio!(PORTB, portb, PortId::B, [ PB0: (pb0, 0), PB1: (pb1, 1), PB2: (pb2, 2), From f153732fcceaba8b9b7b2e15ab57882ccecb9e98 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 8 Nov 2021 01:04:00 +0100 Subject: [PATCH 6/6] applied cargo fmt --- src/gpio.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gpio.rs b/src/gpio.rs index f84834e..8388398 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -1,7 +1,7 @@ use crate::pac::SYSCONFIG; -use cortex_m::singleton; use core::convert::Infallible; use core::marker::PhantomData; +use cortex_m::singleton; use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin}; use va108xx::IOCONFIG; @@ -28,7 +28,7 @@ pub enum PinState { enum PortId { A, - B + B, } trait GpioRegExt {