updated GPIO impl

This commit is contained in:
Robin Müller 2025-02-14 09:43:16 +01:00
parent 4fa1b17f20
commit 423449c1c6
Signed by: muellerr
GPG Key ID: A649FB78196E3849
6 changed files with 302 additions and 214 deletions

View File

@ -26,6 +26,7 @@ defmt = { version = "0.3", optional = true }
fugit = "0.3" fugit = "0.3"
delegate = "0.12" delegate = "0.12"
void = { version = "1", default-features = false } void = { version = "1", default-features = false }
thiserror = { version = "2", default-features = false }
[dependencies.va416xx] [dependencies.va416xx]
default-features = false default-features = false

View File

@ -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, FloatingInput> = 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 embedded_hal::digital::{ErrorKind, ErrorType, InputPin, OutputPin, StatefulOutputPin};
use super::{ use super::{
@ -10,7 +67,8 @@ use super::{
//================================================================================================== //==================================================================================================
/// Value-level `enum` for disabled configurations /// 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 { pub enum DynDisabled {
Floating, Floating,
PullDown, PullDown,
@ -18,7 +76,8 @@ pub enum DynDisabled {
} }
/// Value-level `enum` for input configurations /// 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 { pub enum DynInput {
Floating, Floating,
PullDown, PullDown,
@ -26,7 +85,8 @@ pub enum DynInput {
} }
/// Value-level `enum` for output configurations /// 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 { pub enum DynOutput {
PushPull, PushPull,
OpenDrain, OpenDrain,
@ -36,12 +96,32 @@ pub enum DynOutput {
pub type DynAlternate = crate::FunSel; 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 // DynPinMode
//================================================================================================== //==================================================================================================
/// Value-level `enum` representing pin modes /// 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 { pub enum DynPinMode {
Input(DynInput), Input(DynInput),
Output(DynOutput), Output(DynOutput),
@ -76,7 +156,8 @@ pub const DYN_ALT_FUNC_3: DynPinMode = DynPinMode::Alternate(DynAlternate::Sel3)
//================================================================================================== //==================================================================================================
/// Value-level `enum` for pin groups /// 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 { pub enum DynGroup {
A, A,
B, B,
@ -88,7 +169,8 @@ pub enum DynGroup {
} }
/// Value-level `struct` representing pin IDs /// 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 struct DynPinId {
pub group: DynGroup, pub group: DynGroup,
pub num: u8, pub num: u8,
@ -102,16 +184,16 @@ pub struct DynPinId {
/// ///
/// This `struct` takes ownership of a [`DynPinId`] and provides an API to /// This `struct` takes ownership of a [`DynPinId`] and provides an API to
/// access the corresponding regsiters. /// access the corresponding regsiters.
struct DynRegisters { #[derive(Debug)]
id: DynPinId, #[cfg_attr(feature = "defmt", derive(defmt::format))]
} pub(crate) struct DynRegisters(DynPinId);
// [`DynRegisters`] takes ownership of the [`DynPinId`], and [`DynPin`] // [`DynRegisters`] takes ownership of the [`DynPinId`], and [`DynPin`]
// guarantees that each pin is a singleton, so this implementation is safe. // guarantees that each pin is a singleton, so this implementation is safe.
unsafe impl RegisterInterface for DynRegisters { unsafe impl RegisterInterface for DynRegisters {
#[inline] #[inline]
fn id(&self) -> DynPinId { fn id(&self) -> DynPinId {
self.id self.0
} }
} }
@ -124,25 +206,7 @@ impl DynRegisters {
/// the same [`DynPinId`] /// the same [`DynPinId`]
#[inline] #[inline]
unsafe fn new(id: DynPinId) -> Self { unsafe fn new(id: DynPinId) -> Self {
DynRegisters { id } 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
} }
} }
@ -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 /// 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. /// 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 { pub struct DynPin {
regs: DynRegisters, pub(crate) regs: DynRegisters,
mode: DynPinMode, mode: DynPinMode,
} }
@ -168,7 +234,7 @@ impl DynPin {
/// must be at most one corresponding [`DynPin`] in existence at any given /// must be at most one corresponding [`DynPin`] in existence at any given
/// time. Violating this requirement is `unsafe`. /// time. Violating this requirement is `unsafe`.
#[inline] #[inline]
unsafe fn new(id: DynPinId, mode: DynPinMode) -> Self { pub(crate) unsafe fn new(id: DynPinId, mode: DynPinMode) -> Self {
DynPin { DynPin {
regs: DynRegisters::new(id), regs: DynRegisters::new(id),
mode, mode,
@ -178,7 +244,7 @@ impl DynPin {
/// Return a copy of the pin ID /// Return a copy of the pin ID
#[inline] #[inline]
pub fn id(&self) -> DynPinId { pub fn id(&self) -> DynPinId {
self.regs.id self.regs.0
} }
/// Return a copy of the pin mode /// Return a copy of the pin mode
@ -254,7 +320,45 @@ impl DynPin {
self.into_mode(DYN_RD_OPEN_DRAIN_OUTPUT); 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<bool, crate::gpio::IsMaskedError> {
self.regs.read_pin_masked()
}
#[inline]
pub fn is_low_masked(&self) -> Result<bool, crate::gpio::IsMaskedError> {
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. /// See p.53 of the programmers guide for more information.
/// Possible delays in clock cycles: /// Possible delays in clock cycles:
@ -262,71 +366,78 @@ impl DynPin {
/// - Delay 2: 2 /// - Delay 2: 2
/// - Delay 1 + Delay 2: 3 /// - Delay 1 + Delay 2: 3
#[inline] #[inline]
pub fn delay(self, delay_1: bool, delay_2: bool) -> Result<Self, InvalidPinTypeError> { pub fn configure_delay(
&mut self,
delay_1: bool,
delay_2: bool,
) -> Result<(), InvalidPinTypeError> {
match self.mode { match self.mode {
DynPinMode::Output(_) => { DynPinMode::Output(_) => {
self.regs.delay(delay_1, delay_2); self.regs.configure_delay(delay_1, delay_2);
Ok(self) Ok(())
} }
_ => Err(InvalidPinTypeError(())), _ => Err(InvalidPinTypeError(self.mode)),
} }
} }
/// See p.52 of the programmers guide for more information. /// 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 /// 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 /// one clock cycle before returning to the configured default state
pub fn pulse_mode( pub fn configure_pulse_mode(
self, &mut self,
enable: bool, enable: bool,
default_state: PinState, default_state: PinState,
) -> Result<Self, InvalidPinTypeError> { ) -> Result<(), InvalidPinTypeError> {
match self.mode { match self.mode {
DynPinMode::Output(_) => { DynPinMode::Output(_) => {
self.regs.pulse_mode(enable, default_state); self.regs.configure_pulse_mode(enable, default_state);
Ok(self) Ok(())
} }
_ => Err(InvalidPinTypeError(())), _ => Err(InvalidPinTypeError(self.mode)),
} }
} }
/// See p.37 and p.38 of the programmers guide for more information. /// See p.37 and p.38 of the programmers guide for more information.
#[inline] #[inline]
pub fn filter_type( pub fn configure_filter_type(
self, &mut self,
filter: FilterType, filter: FilterType,
clksel: FilterClkSel, clksel: FilterClkSel,
) -> Result<Self, InvalidPinTypeError> { ) -> Result<(), InvalidPinTypeError> {
match self.mode { match self.mode {
DynPinMode::Input(_) => { DynPinMode::Input(_) => {
self.regs.filter_type(filter, clksel); self.regs.configure_filter_type(filter, clksel);
Ok(self) Ok(())
} }
_ => Err(InvalidPinTypeError(())), _ => Err(InvalidPinTypeError(self.mode)),
} }
} }
pub fn interrupt_edge(mut self, edge_type: InterruptEdge) -> Result<Self, InvalidPinTypeError> { pub fn configure_edge_interrupt(
&mut self,
edge_type: InterruptEdge,
) -> Result<(), InvalidPinTypeError> {
match self.mode { match self.mode {
DynPinMode::Input(_) | DynPinMode::Output(_) => { DynPinMode::Input(_) | DynPinMode::Output(_) => {
self.regs.interrupt_edge(edge_type); self.regs.configure_edge_interrupt(edge_type);
self.irq_enb(); self.irq_enb();
Ok(self) Ok(())
} }
_ => Err(InvalidPinTypeError(())), _ => Err(InvalidPinTypeError(self.mode)),
} }
} }
pub fn interrupt_level( pub fn configure_level_interrupt(
mut self, &mut self,
level_type: InterruptLevel, level_type: InterruptLevel,
) -> Result<Self, InvalidPinTypeError> { ) -> Result<(), InvalidPinTypeError> {
match self.mode { match self.mode {
DynPinMode::Input(_) | DynPinMode::Output(_) => { DynPinMode::Input(_) | DynPinMode::Output(_) => {
self.regs.interrupt_level(level_type); self.regs.configure_level_interrupt(level_type);
self.irq_enb(); 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 => { DynPinMode::Input(_) | DYN_RD_OPEN_DRAIN_OUTPUT | DYN_RD_PUSH_PULL_OUTPUT => {
Ok(self.regs.read_pin()) Ok(self.regs.read_pin())
} }
_ => Err(InvalidPinTypeError(())), _ => Err(InvalidPinTypeError(self.mode)),
} }
} }
#[inline] #[inline]
@ -346,7 +457,7 @@ impl DynPin {
self.regs.write_pin(bit); self.regs.write_pin(bit);
Ok(()) Ok(())
} }
_ => Err(InvalidPinTypeError(())), _ => Err(InvalidPinTypeError(self.mode)),
} }
} }
@ -366,6 +477,21 @@ impl DynPin {
fn _set_high(&mut self) -> Result<(), InvalidPinTypeError> { fn _set_high(&mut self) -> Result<(), InvalidPinTypeError> {
self._write(true) 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<I: PinId, M: PinMode>(self) -> Result<Pin<I, M>, 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 /// Erase the type-level information in a [`Pin`] and return a value-level
/// [`DynPin`] /// [`DynPin`]
#[inline] #[inline]
fn from(_pin: Pin<I, M>) -> Self { fn from(pin: Pin<I, M>) -> Self {
// The `Pin` is consumed, so it is safe to replace it with the pin.downgrade()
// corresponding `DynPin`
unsafe { DynPin::new(I::DYN, M::DYN) }
} }
} }
@ -401,13 +525,7 @@ where
/// or refuse to perform it. /// or refuse to perform it.
#[inline] #[inline]
fn try_from(pin: DynPin) -> Result<Self, Self::Error> { fn try_from(pin: DynPin) -> Result<Self, Self::Error> {
if pin.regs.id == I::DYN && pin.mode == M::DYN { pin.upgrade()
// The `DynPin` is consumed, so it is safe to replace it with the
// corresponding `Pin`
Ok(unsafe { Self::new() })
} else {
Err(InvalidPinTypeError(()))
}
} }
} }

View File

@ -21,57 +21,11 @@
//! ## Examples //! ## Examples
//! //!
//! - [Blinky example](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/examples/simple/examples/blinky.rs) //! - [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))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[error("pin is masked")]
pub struct IsMaskedError; 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<bool, crate::gpio::IsMaskedError> {
self.regs.read_pin_masked()
}
#[inline]
pub fn is_low_masked(&self) -> Result<bool, crate::gpio::IsMaskedError> {
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 mod pin;
pub use pin::*; pub use pin::*;

View File

@ -78,7 +78,8 @@ use embedded_hal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin};
use va416xx::{Porta, Portb, Portc, Portd, Porte, Portf, Portg}; use va416xx::{Porta, Portb, Portc, Portd, Porte, Portf, Portg};
use super::{ 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)] #[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum InterruptEdge { pub enum InterruptEdge {
HighToLow, HighToLow,
LowToHigh, LowToHigh,
@ -93,12 +95,14 @@ pub enum InterruptEdge {
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum InterruptLevel { pub enum InterruptLevel {
Low = 0, Low = 0,
High = 1, High = 1,
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum PinState { pub enum PinState {
Low = 0, Low = 0,
High = 1, High = 1,
@ -321,9 +325,10 @@ macro_rules! pin_id {
//================================================================================================== //==================================================================================================
/// A type-level GPIO pin, parameterized by [`PinId`] and [`PinMode`] types /// A type-level GPIO pin, parameterized by [`PinId`] and [`PinMode`] types
#[derive(Debug)]
pub struct Pin<I: PinId, M: PinMode> { pub struct Pin<I: PinId, M: PinMode> {
pub(in crate::gpio) regs: Registers<I>, inner: DynPin,
mode: PhantomData<M>, mode: PhantomData<(I, M)>,
} }
impl<I: PinId, M: PinMode> Pin<I, M> { impl<I: PinId, M: PinMode> Pin<I, M> {
@ -337,18 +342,23 @@ impl<I: PinId, M: PinMode> Pin<I, M> {
#[inline] #[inline]
pub(crate) unsafe fn new() -> Pin<I, M> { pub(crate) unsafe fn new() -> Pin<I, M> {
Pin { Pin {
regs: Registers::new(), inner: DynPin::new(I::DYN, M::DYN),
mode: PhantomData, mode: PhantomData,
} }
} }
#[inline]
pub fn id(&self) -> DynPinId {
self.inner.id()
}
/// Convert the pin to the requested [`PinMode`] /// Convert the pin to the requested [`PinMode`]
#[inline] #[inline]
pub fn into_mode<N: PinMode>(mut self) -> Pin<I, N> { pub fn into_mode<N: PinMode>(mut self) -> Pin<I, N> {
// Only modify registers if we are actually changing pin mode // Only modify registers if we are actually changing pin mode
// This check should compile away // This check should compile away
if N::DYN != M::DYN { if N::DYN != M::DYN {
self.regs.change_mode::<N>(); self.inner.regs.change_mode(N::DYN);
} }
// Safe because we drop the existing Pin // Safe because we drop the existing Pin
unsafe { Pin::new() } unsafe { Pin::new() }
@ -408,26 +418,73 @@ impl<I: PinId, M: PinMode> Pin<I, M> {
self.into_mode() 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<bool, crate::gpio::IsMaskedError> {
self.inner.is_high_masked()
}
#[inline]
pub fn is_low_masked(&self) -> Result<bool, crate::gpio::IsMaskedError> {
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] #[inline]
pub(crate) fn _set_high(&mut self) { pub(crate) fn _set_high(&mut self) {
self.regs.write_pin(true) self.inner.regs.write_pin(true)
} }
#[inline] #[inline]
pub(crate) fn _set_low(&mut self) { 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] #[inline]
pub(crate) fn _is_low(&self) -> bool { pub(crate) fn _is_low(&self) -> bool {
!self.regs.read_pin() !self.inner.regs.read_pin()
} }
#[inline] #[inline]
pub(crate) fn _is_high(&self) -> bool { pub(crate) fn _is_high(&self) -> bool {
self.regs.read_pin() self.inner.regs.read_pin()
} }
} }
@ -519,16 +576,14 @@ impl<P: AnyPin> AsMut<P> for SpecificPin<P> {
//================================================================================================== //==================================================================================================
impl<I: PinId, C: InputConfig> Pin<I, Input<C>> { impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
pub fn interrupt_edge(mut self, edge_type: InterruptEdge) -> Self { pub fn configure_edge_interrupt(&mut self, edge_type: InterruptEdge) {
self.regs.interrupt_edge(edge_type); self.inner.regs.configure_edge_interrupt(edge_type);
self.irq_enb(); self.irq_enb();
self
} }
pub fn interrupt_level(mut self, level_type: InterruptLevel) -> Self { pub fn configure_interrupt_level(&mut self, level_type: InterruptLevel) {
self.regs.interrupt_level(level_type); self.inner.regs.configure_level_interrupt(level_type);
self.irq_enb(); self.irq_enb();
self
} }
} }
@ -539,38 +594,33 @@ impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
/// - Delay 2: 2 /// - Delay 2: 2
/// - Delay 1 + Delay 2: 3 /// - Delay 1 + Delay 2: 3
#[inline] #[inline]
pub fn delay(self, delay_1: bool, delay_2: bool) -> Self { pub fn configure_delay(&mut self, delay_1: bool, delay_2: bool) {
self.regs.delay(delay_1, delay_2); self.inner.regs.configure_delay(delay_1, delay_2);
self
} }
/// See p.52 of the programmers guide for more information. /// 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 /// 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 /// one clock cycle before returning to the configured default state
pub fn pulse_mode(self, enable: bool, default_state: PinState) -> Self { pub fn configure_pulse_mode(&mut self, enable: bool, default_state: PinState) {
self.regs.pulse_mode(enable, default_state); self.inner.regs.configure_pulse_mode(enable, default_state);
self
} }
pub fn interrupt_edge(mut self, edge_type: InterruptEdge) -> Self { pub fn configure_edge_interrupt(&mut self, edge_type: InterruptEdge) {
self.regs.interrupt_edge(edge_type); self.inner.regs.configure_edge_interrupt(edge_type);
self.irq_enb(); self.irq_enb();
self
} }
pub fn interrupt_level(mut self, level_type: InterruptLevel) -> Self { pub fn configure_level_interrupt(&mut self, level_type: InterruptLevel) {
self.regs.interrupt_level(level_type); self.inner.regs.configure_level_interrupt(level_type);
self.irq_enb(); self.irq_enb();
self
} }
} }
impl<I: PinId, C: InputConfig> Pin<I, Input<C>> { impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
/// See p.37 and p.38 of the programmers guide for more information. /// See p.37 and p.38 of the programmers guide for more information.
#[inline] #[inline]
pub fn filter_type(self, filter: FilterType, clksel: FilterClkSel) -> Self { pub fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
self.regs.filter_type(filter, clksel); self.inner.regs.configure_filter_type(filter, clksel);
self
} }
} }
@ -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<I: PinId> {
id: PhantomData<I>,
}
// [`Registers`] takes ownership of the [`PinId`], and [`Pin`] guarantees that
// each pin is a singleton, so this implementation is safe.
unsafe impl<I: PinId> RegisterInterface for Registers<I> {
#[inline]
fn id(&self) -> DynPinId {
I::DYN
}
}
impl<I: PinId> Registers<I> {
/// 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<M: PinMode>(&mut self) {
RegisterInterface::change_mode(self, M::DYN);
}
}
//================================================================================================== //==================================================================================================
// Pin definitions // 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 { macro_rules! declare_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)?)),+]

View File

@ -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 /// 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 /// When using edge mode, it is possible to generate interrupts on both edges as well
#[inline] #[inline]
fn interrupt_edge(&mut self, edge_type: InterruptEdge) { fn configure_edge_interrupt(&mut self, edge_type: InterruptEdge) {
unsafe { unsafe {
self.port_reg() self.port_reg()
.irq_sen() .irq_sen()
@ -271,7 +279,7 @@ pub(super) unsafe trait RegisterInterface {
/// Configure which edge or level type triggers an interrupt /// Configure which edge or level type triggers an interrupt
#[inline] #[inline]
fn interrupt_level(&mut self, level: InterruptLevel) { fn configure_level_interrupt(&mut self, level: InterruptLevel) {
unsafe { unsafe {
self.port_reg() self.port_reg()
.irq_sen() .irq_sen()
@ -290,7 +298,7 @@ pub(super) unsafe trait RegisterInterface {
/// Only useful for input pins /// Only useful for input pins
#[inline] #[inline]
fn filter_type(&self, filter: FilterType, clksel: FilterClkSel) { fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
self.iocfg_port().modify(|_, w| { self.iocfg_port().modify(|_, w| {
// Safety: Only write to register for this Pin ID // Safety: Only write to register for this Pin ID
unsafe { unsafe {
@ -328,7 +336,7 @@ pub(super) unsafe trait RegisterInterface {
/// See p.52 of the programmers guide for more information. /// 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 /// 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 /// 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(); let portreg = self.port_reg();
unsafe { unsafe {
if enable { if enable {
@ -353,7 +361,7 @@ pub(super) unsafe trait RegisterInterface {
} }
/// Only useful for output pins /// 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(); let portreg = self.port_reg();
unsafe { unsafe {
if delay_1 { if delay_1 {

View File

@ -275,7 +275,7 @@ impl IrqContextTimeoutOrMaxSize {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct IrqResult { pub struct IrqResult {
pub bytes_read: usize, pub bytes_read: usize,
pub errors: Option<IrqUartError>, pub errors: Option<UartErrors>,
} }
/// This struct is used to return the default IRQ handler result to the user /// This struct is used to return the default IRQ handler result to the user
@ -283,7 +283,7 @@ pub struct IrqResult {
pub struct IrqResultMaxSizeOrTimeout { pub struct IrqResultMaxSizeOrTimeout {
complete: bool, complete: bool,
timeout: bool, timeout: bool,
pub errors: Option<IrqUartError>, pub errors: Option<UartErrors>,
pub bytes_read: usize, pub bytes_read: usize,
} }
@ -336,14 +336,14 @@ enum IrqReceptionMode {
} }
#[derive(Default, Debug, Copy, Clone)] #[derive(Default, Debug, Copy, Clone)]
pub struct IrqUartError { pub struct UartErrors {
overflow: bool, overflow: bool,
framing: bool, framing: bool,
parity: bool, parity: bool,
other: bool, other: bool,
} }
impl IrqUartError { impl UartErrors {
#[inline(always)] #[inline(always)]
pub fn overflow(&self) -> bool { pub fn overflow(&self) -> bool {
self.overflow self.overflow
@ -365,7 +365,7 @@ impl IrqUartError {
} }
} }
impl IrqUartError { impl UartErrors {
#[inline(always)] #[inline(always)]
pub fn error(&self) -> bool { pub fn error(&self) -> bool {
self.overflow || self.framing || self.parity self.overflow || self.framing || self.parity
@ -405,10 +405,10 @@ impl Instance for Uart0 {
const IRQ_TX: pac::Interrupt = pac::Interrupt::UART0_TX; const IRQ_TX: pac::Interrupt = pac::Interrupt::UART0_TX;
unsafe fn steal() -> Self { unsafe fn steal() -> Self {
pac::Peripherals::steal().uart0 Self::steal()
} }
fn ptr() -> *const uart_base::RegisterBlock { 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; const IRQ_TX: pac::Interrupt = pac::Interrupt::UART1_TX;
unsafe fn steal() -> Self { unsafe fn steal() -> Self {
pac::Peripherals::steal().uart1 Self::steal()
} }
fn ptr() -> *const uart_base::RegisterBlock { 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; const IRQ_TX: pac::Interrupt = pac::Interrupt::UART2_TX;
unsafe fn steal() -> Self { unsafe fn steal() -> Self {
pac::Peripherals::steal().uart2 Self::steal()
} }
fn ptr() -> *const uart_base::RegisterBlock { fn ptr() -> *const uart_base::RegisterBlock {
Uart2::ptr() as *const _ Self::ptr() as *const _
} }
} }
@ -1164,7 +1164,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
fn read_handler( fn read_handler(
&self, &self,
errors: &mut Option<IrqUartError>, errors: &mut Option<UartErrors>,
read_res: &nb::Result<u8, RxError>, read_res: &nb::Result<u8, RxError>,
) -> Option<u8> { ) -> Option<u8> {
match read_res { match read_res {
@ -1172,7 +1172,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
Err(nb::Error::WouldBlock) => None, Err(nb::Error::WouldBlock) => None,
Err(nb::Error::Other(e)) => { Err(nb::Error::Other(e)) => {
// Ensure `errors` is Some(IrqUartError), initializing if it's None // 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` // Now we can safely modify fields inside `err`
match e { match e {
@ -1185,14 +1185,14 @@ impl<Uart: Instance> RxWithIrq<Uart> {
} }
} }
fn check_for_errors(&self, errors: &mut Option<IrqUartError>) { fn check_for_errors(&self, errors: &mut Option<UartErrors>) {
let rx_status = self.uart().rxstatus().read(); let rx_status = self.uart().rxstatus().read();
if rx_status.rxovr().bit_is_set() if rx_status.rxovr().bit_is_set()
|| rx_status.rxfrm().bit_is_set() || rx_status.rxfrm().bit_is_set()
|| rx_status.rxpar().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() { if rx_status.rxovr().bit_is_set() {
err.overflow = true; err.overflow = true;