diff --git a/va416xx-hal/Cargo.toml b/va416xx-hal/Cargo.toml index 511b212..5ca6983 100644 --- a/va416xx-hal/Cargo.toml +++ b/va416xx-hal/Cargo.toml @@ -26,6 +26,7 @@ defmt = { version = "0.3", optional = true } fugit = "0.3" delegate = "0.12" void = { version = "1", default-features = false } +thiserror = { version = "2", default-features = false } [dependencies.va416xx] default-features = false diff --git a/va416xx-hal/src/gpio/dynpin.rs b/va416xx-hal/src/gpio/dynpin.rs index ab1c20c..aaef725 100644 --- a/va416xx-hal/src/gpio/dynpin.rs +++ b/va416xx-hal/src/gpio/dynpin.rs @@ -1,3 +1,60 @@ +//! # Type-erased, value-level module for GPIO pins +//! +//! Although the type-level API is generally preferred, it is not suitable in +//! all cases. Because each pin is represented by a distinct type, it is not +//! possible to store multiple pins in a homogeneous data structure. The +//! value-level API solves this problem by erasing the type information and +//! tracking the pin at run-time. +//! +//! Value-level pins are represented by the [`DynPin`] type. [`DynPin`] has two +//! fields, `id` and `mode` with types [`DynPinId`] and [`DynPinMode`] +//! respectively. The implementation of these types closely mirrors the +//! type-level API. +//! +//! Instances of [`DynPin`] cannot be created directly. Rather, they must be +//! created from their type-level equivalents using [`From`]/[`Into`]. +//! +//! ``` +//! // Move a pin out of the Pins struct and convert to a DynPin +//! let pa0: DynPin = pins.pa0.into(); +//! ``` +//! +//! Conversions between pin modes use a value-level version of the type-level +//! API. +//! +//! ``` +//! // Use one of the literal function names +//! pa0.into_floating_input(); +//! // Use a method and a DynPinMode variant +//! pa0.into_mode(DYN_FLOATING_INPUT); +//! ``` +//! +//! Because the pin state cannot be tracked at compile-time, many [`DynPin`] +//! operations become fallible. Run-time checks are inserted to ensure that +//! users don't try to, for example, set the output level of an input pin. +//! +//! Users may try to convert value-level pins back to their type-level +//! equivalents. However, this option is fallible, because the compiler cannot +//! guarantee the pin has the correct ID or is in the correct mode at +//! compile-time. Use [TryFrom]/[TryInto] for this conversion. +//! +//! ``` +//! // Convert to a `DynPin` +//! let pa0: DynPin = pins.pa0.into(); +//! // Change pin mode +//! pa0.into_floating_input(); +//! // Convert back to a `Pin` +//! let pa0: Pin = pa0.try_into().unwrap(); +//! ``` +//! +//! # Embedded HAL traits +//! +//! This module implements all of the embedded HAL GPIO traits for [`DynPin`]. +//! However, whereas the type-level API uses +//! `Error = core::convert::Infallible`, the value-level API can return a real +//! error. If the [`DynPin`] is not in the correct [`DynPinMode`] for the +//! operation, the trait functions will return +//! [InvalidPinTypeError]. use embedded_hal::digital::{ErrorKind, ErrorType, InputPin, OutputPin, StatefulOutputPin}; use super::{ @@ -10,7 +67,8 @@ use super::{ //================================================================================================== /// Value-level `enum` for disabled configurations -#[derive(PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::format))] pub enum DynDisabled { Floating, PullDown, @@ -18,7 +76,8 @@ pub enum DynDisabled { } /// Value-level `enum` for input configurations -#[derive(PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::format))] pub enum DynInput { Floating, PullDown, @@ -26,7 +85,8 @@ pub enum DynInput { } /// Value-level `enum` for output configurations -#[derive(PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::format))] pub enum DynOutput { PushPull, OpenDrain, @@ -36,12 +96,32 @@ pub enum DynOutput { pub type DynAlternate = crate::FunSel; +//============================================================================== +// Error +//============================================================================== + +/// GPIO error type +/// +/// [`DynPin`]s are not tracked and verified at compile-time, so run-time +/// operations are fallible. This `enum` represents the corresponding errors. +#[derive(Debug, PartialEq, Eq, thiserror::Error)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[error("Invalid pin type for operation: {0:?}")] +pub struct InvalidPinTypeError(pub DynPinMode); + +impl embedded_hal::digital::Error for InvalidPinTypeError { + fn kind(&self) -> embedded_hal::digital::ErrorKind { + embedded_hal::digital::ErrorKind::Other + } +} + //================================================================================================== // DynPinMode //================================================================================================== /// Value-level `enum` representing pin modes -#[derive(PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::format))] pub enum DynPinMode { Input(DynInput), Output(DynOutput), @@ -76,7 +156,8 @@ pub const DYN_ALT_FUNC_3: DynPinMode = DynPinMode::Alternate(DynAlternate::Sel3) //================================================================================================== /// Value-level `enum` for pin groups -#[derive(PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::format))] pub enum DynGroup { A, B, @@ -88,7 +169,8 @@ pub enum DynGroup { } /// Value-level `struct` representing pin IDs -#[derive(PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::format))] pub struct DynPinId { pub group: DynGroup, pub num: u8, @@ -102,16 +184,16 @@ pub struct DynPinId { /// /// This `struct` takes ownership of a [`DynPinId`] and provides an API to /// access the corresponding regsiters. -struct DynRegisters { - id: DynPinId, -} +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::format))] +pub(crate) struct DynRegisters(DynPinId); // [`DynRegisters`] takes ownership of the [`DynPinId`], and [`DynPin`] // guarantees that each pin is a singleton, so this implementation is safe. unsafe impl RegisterInterface for DynRegisters { #[inline] fn id(&self) -> DynPinId { - self.id + self.0 } } @@ -124,25 +206,7 @@ impl DynRegisters { /// the same [`DynPinId`] #[inline] unsafe fn new(id: DynPinId) -> Self { - DynRegisters { id } - } -} - -//============================================================================== -// Error -//============================================================================== - -/// GPIO error type -/// -/// [`DynPin`]s are not tracked and verified at compile-time, so run-time -/// operations are fallible. This `enum` represents the corresponding errors. -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct InvalidPinTypeError(pub(crate) ()); - -impl embedded_hal::digital::Error for InvalidPinTypeError { - fn kind(&self) -> embedded_hal::digital::ErrorKind { - ErrorKind::Other + DynRegisters(id) } } @@ -154,8 +218,10 @@ impl embedded_hal::digital::Error for InvalidPinTypeError { /// /// This type acts as a type-erased version of [`Pin`]. Every pin is represented /// by the same type, and pins are tracked and distinguished at run-time. +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::format))] pub struct DynPin { - regs: DynRegisters, + pub(crate) regs: DynRegisters, mode: DynPinMode, } @@ -168,7 +234,7 @@ impl DynPin { /// must be at most one corresponding [`DynPin`] in existence at any given /// time. Violating this requirement is `unsafe`. #[inline] - unsafe fn new(id: DynPinId, mode: DynPinMode) -> Self { + pub(crate) unsafe fn new(id: DynPinId, mode: DynPinMode) -> Self { DynPin { regs: DynRegisters::new(id), mode, @@ -178,7 +244,7 @@ impl DynPin { /// Return a copy of the pin ID #[inline] pub fn id(&self) -> DynPinId { - self.regs.id + self.regs.0 } /// Return a copy of the pin mode @@ -254,7 +320,45 @@ impl DynPin { self.into_mode(DYN_RD_OPEN_DRAIN_OUTPUT); } - common_reg_if_functions!(); + #[inline] + pub fn datamask(&self) -> bool { + self.regs.datamask() + } + + #[inline] + pub fn clear_datamask(&mut self) { + self.regs.clear_datamask(); + } + + #[inline] + pub fn set_datamask(&mut self) { + self.regs.set_datamask(); + } + + #[inline] + pub fn is_high_masked(&self) -> Result { + self.regs.read_pin_masked() + } + + #[inline] + pub fn is_low_masked(&self) -> Result { + self.regs.read_pin_masked().map(|v| !v) + } + + #[inline] + pub fn set_high_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> { + self.regs.write_pin_masked(true) + } + + #[inline] + pub fn set_low_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> { + self.regs.write_pin_masked(false) + } + + #[inline] + pub fn irq_enb(&mut self) { + self.regs.enable_irq(); + } /// See p.53 of the programmers guide for more information. /// Possible delays in clock cycles: @@ -262,71 +366,78 @@ impl DynPin { /// - Delay 2: 2 /// - Delay 1 + Delay 2: 3 #[inline] - pub fn delay(self, delay_1: bool, delay_2: bool) -> Result { + pub fn configure_delay( + &mut self, + delay_1: bool, + delay_2: bool, + ) -> Result<(), InvalidPinTypeError> { match self.mode { DynPinMode::Output(_) => { - self.regs.delay(delay_1, delay_2); - Ok(self) + self.regs.configure_delay(delay_1, delay_2); + Ok(()) } - _ => Err(InvalidPinTypeError(())), + _ => Err(InvalidPinTypeError(self.mode)), } } /// See p.52 of the programmers guide for more information. /// When configured for pulse mode, a given pin will set the non-default state for exactly /// one clock cycle before returning to the configured default state - pub fn pulse_mode( - self, + pub fn configure_pulse_mode( + &mut self, enable: bool, default_state: PinState, - ) -> Result { + ) -> Result<(), InvalidPinTypeError> { match self.mode { DynPinMode::Output(_) => { - self.regs.pulse_mode(enable, default_state); - Ok(self) + self.regs.configure_pulse_mode(enable, default_state); + Ok(()) } - _ => Err(InvalidPinTypeError(())), + _ => Err(InvalidPinTypeError(self.mode)), } } /// See p.37 and p.38 of the programmers guide for more information. #[inline] - pub fn filter_type( - self, + pub fn configure_filter_type( + &mut self, filter: FilterType, clksel: FilterClkSel, - ) -> Result { + ) -> Result<(), InvalidPinTypeError> { match self.mode { DynPinMode::Input(_) => { - self.regs.filter_type(filter, clksel); - Ok(self) + self.regs.configure_filter_type(filter, clksel); + Ok(()) } - _ => Err(InvalidPinTypeError(())), + _ => Err(InvalidPinTypeError(self.mode)), } } - pub fn interrupt_edge(mut self, edge_type: InterruptEdge) -> Result { + pub fn configure_edge_interrupt( + &mut self, + edge_type: InterruptEdge, + ) -> Result<(), InvalidPinTypeError> { match self.mode { DynPinMode::Input(_) | DynPinMode::Output(_) => { - self.regs.interrupt_edge(edge_type); + self.regs.configure_edge_interrupt(edge_type); self.irq_enb(); - Ok(self) + Ok(()) } - _ => Err(InvalidPinTypeError(())), + _ => Err(InvalidPinTypeError(self.mode)), } } - pub fn interrupt_level( - mut self, + pub fn configure_level_interrupt( + &mut self, level_type: InterruptLevel, - ) -> Result { + ) -> Result<(), InvalidPinTypeError> { match self.mode { DynPinMode::Input(_) | DynPinMode::Output(_) => { - self.regs.interrupt_level(level_type); + self.regs.configure_level_interrupt(level_type); self.irq_enb(); - Ok(self) + Ok(()) } - _ => Err(InvalidPinTypeError(())), + _ => Err(InvalidPinTypeError(self.mode)), } } @@ -336,7 +447,7 @@ impl DynPin { DynPinMode::Input(_) | DYN_RD_OPEN_DRAIN_OUTPUT | DYN_RD_PUSH_PULL_OUTPUT => { Ok(self.regs.read_pin()) } - _ => Err(InvalidPinTypeError(())), + _ => Err(InvalidPinTypeError(self.mode)), } } #[inline] @@ -346,7 +457,7 @@ impl DynPin { self.regs.write_pin(bit); Ok(()) } - _ => Err(InvalidPinTypeError(())), + _ => Err(InvalidPinTypeError(self.mode)), } } @@ -366,6 +477,21 @@ impl DynPin { fn _set_high(&mut self) -> Result<(), InvalidPinTypeError> { self._write(true) } + + /// Try to recreate a type-level [`Pin`] from a value-level [`DynPin`] + /// + /// There is no way for the compiler to know if the conversion will be + /// successful at compile-time. We must verify the conversion at run-time + /// or refuse to perform it. + #[inline] + pub fn upgrade(self) -> Result, InvalidPinTypeError> { + if self.regs.0 == I::DYN && self.mode == M::DYN { + // The `DynPin` is consumed, so it is safe to replace it with the + // corresponding `Pin` + return Ok(unsafe { Pin::new() }); + } + Err(InvalidPinTypeError(self.mode)) + } } //============================================================================== @@ -380,10 +506,8 @@ where /// Erase the type-level information in a [`Pin`] and return a value-level /// [`DynPin`] #[inline] - fn from(_pin: Pin) -> Self { - // The `Pin` is consumed, so it is safe to replace it with the - // corresponding `DynPin` - unsafe { DynPin::new(I::DYN, M::DYN) } + fn from(pin: Pin) -> Self { + pin.downgrade() } } @@ -401,13 +525,7 @@ where /// or refuse to perform it. #[inline] fn try_from(pin: DynPin) -> Result { - if pin.regs.id == I::DYN && pin.mode == M::DYN { - // The `DynPin` is consumed, so it is safe to replace it with the - // corresponding `Pin` - Ok(unsafe { Self::new() }) - } else { - Err(InvalidPinTypeError(())) - } + pin.upgrade() } } diff --git a/va416xx-hal/src/gpio/mod.rs b/va416xx-hal/src/gpio/mod.rs index 19d6889..59de6a5 100644 --- a/va416xx-hal/src/gpio/mod.rs +++ b/va416xx-hal/src/gpio/mod.rs @@ -21,57 +21,11 @@ //! ## Examples //! //! - [Blinky example](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/examples/simple/examples/blinky.rs) -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, thiserror::Error)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[error("pin is masked")] pub struct IsMaskedError; -macro_rules! common_reg_if_functions { - () => { - paste::paste!( - #[inline] - pub fn datamask(&self) -> bool { - self.regs.datamask() - } - - #[inline] - pub fn clear_datamask(self) -> Self { - self.regs.clear_datamask(); - self - } - - #[inline] - pub fn set_datamask(self) -> Self { - self.regs.set_datamask(); - self - } - - #[inline] - pub fn is_high_masked(&self) -> Result { - self.regs.read_pin_masked() - } - - #[inline] - pub fn is_low_masked(&self) -> Result { - self.regs.read_pin_masked().map(|v| !v) - } - - #[inline] - pub fn set_high_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> { - self.regs.write_pin_masked(true) - } - - #[inline] - pub fn set_low_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> { - self.regs.write_pin_masked(false) - } - - fn irq_enb(&mut self) { - self.regs.enable_irq(); - } - ); - }; -} - pub mod pin; pub use pin::*; diff --git a/va416xx-hal/src/gpio/pin.rs b/va416xx-hal/src/gpio/pin.rs index b28f629..ba7491a 100644 --- a/va416xx-hal/src/gpio/pin.rs +++ b/va416xx-hal/src/gpio/pin.rs @@ -78,7 +78,8 @@ use embedded_hal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin}; use va416xx::{Porta, Portb, Portc, Portd, Porte, Portf, Portg}; use super::{ - reg::RegisterInterface, DynAlternate, DynGroup, DynInput, DynOutput, DynPinId, DynPinMode, + reg::RegisterInterface, DynAlternate, DynGroup, DynInput, DynOutput, DynPin, DynPinId, + DynPinMode, }; //================================================================================================== @@ -86,6 +87,7 @@ use super::{ //================================================================================================== #[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum InterruptEdge { HighToLow, LowToHigh, @@ -93,12 +95,14 @@ pub enum InterruptEdge { } #[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum InterruptLevel { Low = 0, High = 1, } #[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum PinState { Low = 0, High = 1, @@ -321,9 +325,10 @@ macro_rules! pin_id { //================================================================================================== /// A type-level GPIO pin, parameterized by [`PinId`] and [`PinMode`] types +#[derive(Debug)] pub struct Pin { - pub(in crate::gpio) regs: Registers, - mode: PhantomData, + inner: DynPin, + mode: PhantomData<(I, M)>, } impl Pin { @@ -337,18 +342,23 @@ impl Pin { #[inline] pub(crate) unsafe fn new() -> Pin { Pin { - regs: Registers::new(), + inner: DynPin::new(I::DYN, M::DYN), mode: PhantomData, } } + #[inline] + pub fn id(&self) -> DynPinId { + self.inner.id() + } + /// Convert the pin to the requested [`PinMode`] #[inline] pub fn into_mode(mut self) -> Pin { // Only modify registers if we are actually changing pin mode // This check should compile away if N::DYN != M::DYN { - self.regs.change_mode::(); + self.inner.regs.change_mode(N::DYN); } // Safe because we drop the existing Pin unsafe { Pin::new() } @@ -408,26 +418,73 @@ impl Pin { self.into_mode() } - common_reg_if_functions!(); + #[inline] + pub fn datamask(&self) -> bool { + self.inner.datamask() + } + + #[inline] + pub fn clear_datamask(&mut self) { + self.inner.clear_datamask() + } + + #[inline] + pub fn set_datamask(&mut self) { + self.inner.set_datamask() + } + + #[inline] + pub fn is_high_masked(&self) -> Result { + self.inner.is_high_masked() + } + + #[inline] + pub fn is_low_masked(&self) -> Result { + self.inner.is_low_masked() + } + + #[inline] + pub fn set_high_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> { + self.inner.set_high_masked() + } + + #[inline] + pub fn set_low_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> { + self.inner.set_low_masked() + } + + #[inline] + pub fn downgrade(self) -> DynPin { + self.inner + } + + fn irq_enb(&mut self) { + self.inner.irq_enb(); + } #[inline] pub(crate) fn _set_high(&mut self) { - self.regs.write_pin(true) + self.inner.regs.write_pin(true) } #[inline] pub(crate) fn _set_low(&mut self) { - self.regs.write_pin(false) + self.inner.regs.write_pin(false) + } + + #[inline] + pub(crate) fn _toggle_with_toggle_reg(&mut self) { + self.inner.regs.toggle(); } #[inline] pub(crate) fn _is_low(&self) -> bool { - !self.regs.read_pin() + !self.inner.regs.read_pin() } #[inline] pub(crate) fn _is_high(&self) -> bool { - self.regs.read_pin() + self.inner.regs.read_pin() } } @@ -519,16 +576,14 @@ impl AsMut

for SpecificPin

{ //================================================================================================== impl Pin> { - pub fn interrupt_edge(mut self, edge_type: InterruptEdge) -> Self { - self.regs.interrupt_edge(edge_type); + pub fn configure_edge_interrupt(&mut self, edge_type: InterruptEdge) { + self.inner.regs.configure_edge_interrupt(edge_type); self.irq_enb(); - self } - pub fn interrupt_level(mut self, level_type: InterruptLevel) -> Self { - self.regs.interrupt_level(level_type); + pub fn configure_interrupt_level(&mut self, level_type: InterruptLevel) { + self.inner.regs.configure_level_interrupt(level_type); self.irq_enb(); - self } } @@ -539,38 +594,33 @@ impl Pin> { /// - Delay 2: 2 /// - Delay 1 + Delay 2: 3 #[inline] - pub fn delay(self, delay_1: bool, delay_2: bool) -> Self { - self.regs.delay(delay_1, delay_2); - self + pub fn configure_delay(&mut self, delay_1: bool, delay_2: bool) { + self.inner.regs.configure_delay(delay_1, delay_2); } /// See p.52 of the programmers guide for more information. /// When configured for pulse mode, a given pin will set the non-default state for exactly /// one clock cycle before returning to the configured default state - pub fn pulse_mode(self, enable: bool, default_state: PinState) -> Self { - self.regs.pulse_mode(enable, default_state); - self + pub fn configure_pulse_mode(&mut self, enable: bool, default_state: PinState) { + self.inner.regs.configure_pulse_mode(enable, default_state); } - pub fn interrupt_edge(mut self, edge_type: InterruptEdge) -> Self { - self.regs.interrupt_edge(edge_type); + pub fn configure_edge_interrupt(&mut self, edge_type: InterruptEdge) { + self.inner.regs.configure_edge_interrupt(edge_type); self.irq_enb(); - self } - pub fn interrupt_level(mut self, level_type: InterruptLevel) -> Self { - self.regs.interrupt_level(level_type); + pub fn configure_level_interrupt(&mut self, level_type: InterruptLevel) { + self.inner.regs.configure_level_interrupt(level_type); self.irq_enb(); - self } } impl Pin> { /// See p.37 and p.38 of the programmers guide for more information. #[inline] - pub fn filter_type(self, filter: FilterType, clksel: FilterClkSel) -> Self { - self.regs.filter_type(filter, clksel); - self + pub fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) { + self.inner.regs.configure_filter_type(filter, clksel); } } @@ -646,47 +696,6 @@ where } } -//================================================================================================== -// Registers -//================================================================================================== - -/// Provide a safe register interface for [`Pin`]s -/// -/// This `struct` takes ownership of a [`PinId`] and provides an API to -/// access the corresponding registers. -pub(in crate::gpio) struct Registers { - id: PhantomData, -} - -// [`Registers`] takes ownership of the [`PinId`], and [`Pin`] guarantees that -// each pin is a singleton, so this implementation is safe. -unsafe impl RegisterInterface for Registers { - #[inline] - fn id(&self) -> DynPinId { - I::DYN - } -} - -impl Registers { - /// Create a new instance of [`Registers`] - /// - /// # Safety - /// - /// Users must never create two simultaneous instances of this `struct` with - /// the same [`PinId`] - #[inline] - unsafe fn new() -> Self { - Registers { id: PhantomData } - } - - /// Provide a type-level equivalent for the - /// [`RegisterInterface::change_mode`] method. - #[inline] - pub(in crate::gpio) fn change_mode(&mut self) { - RegisterInterface::change_mode(self, M::DYN); - } -} - //================================================================================================== // Pin definitions //================================================================================================== @@ -745,8 +754,6 @@ macro_rules! pins { } } -//$Group:ident, $PinsName:ident, $Port:ident, [$(($Id:ident, $NUM:literal $(, $meta:meta)?)),+] -//$Group:ident, $PinsName:ident, $Port:ident, [$(($Id:ident, $NUM:literal, $meta: meta),)+] macro_rules! declare_pins { ( $Group:ident, $PinsName:ident, $Port:ident, [$(($Id:ident, $NUM:literal $(, $meta:meta)?)),+] diff --git a/va416xx-hal/src/gpio/reg.rs b/va416xx-hal/src/gpio/reg.rs index 5e06d01..7d964bc 100644 --- a/va416xx-hal/src/gpio/reg.rs +++ b/va416xx-hal/src/gpio/reg.rs @@ -241,10 +241,18 @@ pub(super) unsafe trait RegisterInterface { } } + /// Toggle the logic level of an output pin + #[inline(always)] + fn toggle(&mut self) { + // Safety: TOGOUT is a "mask" register, and we only write the bit for + // this pin ID + unsafe { self.port_reg().togout().write(|w| w.bits(self.mask_32())) }; + } + /// Only useful for interrupt pins. Configure whether to use edges or level as interrupt soure /// When using edge mode, it is possible to generate interrupts on both edges as well #[inline] - fn interrupt_edge(&mut self, edge_type: InterruptEdge) { + fn configure_edge_interrupt(&mut self, edge_type: InterruptEdge) { unsafe { self.port_reg() .irq_sen() @@ -271,7 +279,7 @@ pub(super) unsafe trait RegisterInterface { /// Configure which edge or level type triggers an interrupt #[inline] - fn interrupt_level(&mut self, level: InterruptLevel) { + fn configure_level_interrupt(&mut self, level: InterruptLevel) { unsafe { self.port_reg() .irq_sen() @@ -290,7 +298,7 @@ pub(super) unsafe trait RegisterInterface { /// Only useful for input pins #[inline] - fn filter_type(&self, filter: FilterType, clksel: FilterClkSel) { + fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) { self.iocfg_port().modify(|_, w| { // Safety: Only write to register for this Pin ID unsafe { @@ -328,7 +336,7 @@ pub(super) unsafe trait RegisterInterface { /// See p.52 of the programmers guide for more information. /// When configured for pulse mode, a given pin will set the non-default state for exactly /// one clock cycle before returning to the configured default state - fn pulse_mode(&self, enable: bool, default_state: PinState) { + fn configure_pulse_mode(&mut self, enable: bool, default_state: PinState) { let portreg = self.port_reg(); unsafe { if enable { @@ -353,7 +361,7 @@ pub(super) unsafe trait RegisterInterface { } /// Only useful for output pins - fn delay(&self, delay_1: bool, delay_2: bool) { + fn configure_delay(&mut self, delay_1: bool, delay_2: bool) { let portreg = self.port_reg(); unsafe { if delay_1 { diff --git a/va416xx-hal/src/uart.rs b/va416xx-hal/src/uart.rs index ca97991..49dbe9e 100644 --- a/va416xx-hal/src/uart.rs +++ b/va416xx-hal/src/uart.rs @@ -275,7 +275,7 @@ impl IrqContextTimeoutOrMaxSize { #[derive(Debug, Default)] pub struct IrqResult { pub bytes_read: usize, - pub errors: Option, + pub errors: Option, } /// This struct is used to return the default IRQ handler result to the user @@ -283,7 +283,7 @@ pub struct IrqResult { pub struct IrqResultMaxSizeOrTimeout { complete: bool, timeout: bool, - pub errors: Option, + pub errors: Option, pub bytes_read: usize, } @@ -336,14 +336,14 @@ enum IrqReceptionMode { } #[derive(Default, Debug, Copy, Clone)] -pub struct IrqUartError { +pub struct UartErrors { overflow: bool, framing: bool, parity: bool, other: bool, } -impl IrqUartError { +impl UartErrors { #[inline(always)] pub fn overflow(&self) -> bool { self.overflow @@ -365,7 +365,7 @@ impl IrqUartError { } } -impl IrqUartError { +impl UartErrors { #[inline(always)] pub fn error(&self) -> bool { self.overflow || self.framing || self.parity @@ -405,10 +405,10 @@ impl Instance for Uart0 { const IRQ_TX: pac::Interrupt = pac::Interrupt::UART0_TX; unsafe fn steal() -> Self { - pac::Peripherals::steal().uart0 + Self::steal() } fn ptr() -> *const uart_base::RegisterBlock { - Uart0::ptr() as *const _ + Self::ptr() as *const _ } } @@ -419,10 +419,10 @@ impl Instance for Uart1 { const IRQ_TX: pac::Interrupt = pac::Interrupt::UART1_TX; unsafe fn steal() -> Self { - pac::Peripherals::steal().uart1 + Self::steal() } fn ptr() -> *const uart_base::RegisterBlock { - Uart1::ptr() as *const _ + Self::ptr() as *const _ } } @@ -433,10 +433,10 @@ impl Instance for Uart2 { const IRQ_TX: pac::Interrupt = pac::Interrupt::UART2_TX; unsafe fn steal() -> Self { - pac::Peripherals::steal().uart2 + Self::steal() } fn ptr() -> *const uart_base::RegisterBlock { - Uart2::ptr() as *const _ + Self::ptr() as *const _ } } @@ -1164,7 +1164,7 @@ impl RxWithIrq { fn read_handler( &self, - errors: &mut Option, + errors: &mut Option, read_res: &nb::Result, ) -> Option { match read_res { @@ -1172,7 +1172,7 @@ impl RxWithIrq { Err(nb::Error::WouldBlock) => None, Err(nb::Error::Other(e)) => { // Ensure `errors` is Some(IrqUartError), initializing if it's None - let err = errors.get_or_insert(IrqUartError::default()); + let err = errors.get_or_insert(UartErrors::default()); // Now we can safely modify fields inside `err` match e { @@ -1185,14 +1185,14 @@ impl RxWithIrq { } } - fn check_for_errors(&self, errors: &mut Option) { + fn check_for_errors(&self, errors: &mut Option) { let rx_status = self.uart().rxstatus().read(); if rx_status.rxovr().bit_is_set() || rx_status.rxfrm().bit_is_set() || rx_status.rxpar().bit_is_set() { - let err = errors.get_or_insert(IrqUartError::default()); + let err = errors.get_or_insert(UartErrors::default()); if rx_status.rxovr().bit_is_set() { err.overflow = true;