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"
delegate = "0.12"
void = { version = "1", default-features = false }
thiserror = { version = "2", default-features = false }
[dependencies.va416xx]
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 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<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.
/// 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<Self, InvalidPinTypeError> {
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<Self, InvalidPinTypeError> {
) -> 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<Self, InvalidPinTypeError> {
) -> 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<Self, InvalidPinTypeError> {
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<Self, InvalidPinTypeError> {
) -> 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<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
/// [`DynPin`]
#[inline]
fn from(_pin: Pin<I, M>) -> 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<I, M>) -> Self {
pin.downgrade()
}
}
@ -401,13 +525,7 @@ where
/// or refuse to perform it.
#[inline]
fn try_from(pin: DynPin) -> Result<Self, Self::Error> {
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()
}
}

View File

@ -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<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 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 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<I: PinId, M: PinMode> {
pub(in crate::gpio) regs: Registers<I>,
mode: PhantomData<M>,
inner: DynPin,
mode: PhantomData<(I, M)>,
}
impl<I: PinId, M: PinMode> Pin<I, M> {
@ -337,18 +342,23 @@ impl<I: PinId, M: PinMode> Pin<I, M> {
#[inline]
pub(crate) unsafe fn new() -> Pin<I, M> {
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<N: PinMode>(mut self) -> Pin<I, N> {
// Only modify registers if we are actually changing pin mode
// This check should compile away
if N::DYN != M::DYN {
self.regs.change_mode::<N>();
self.inner.regs.change_mode(N::DYN);
}
// Safe because we drop the existing Pin
unsafe { Pin::new() }
@ -408,26 +418,73 @@ impl<I: PinId, M: PinMode> Pin<I, M> {
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]
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<P: AnyPin> AsMut<P> for SpecificPin<P> {
//==================================================================================================
impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
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<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
/// - 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<I: PinId, C: InputConfig> Pin<I, Input<C>> {
/// 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<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
//==================================================================================================
@ -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)?)),+]

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
/// 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 {

View File

@ -275,7 +275,7 @@ impl IrqContextTimeoutOrMaxSize {
#[derive(Debug, Default)]
pub struct IrqResult {
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
@ -283,7 +283,7 @@ pub struct IrqResult {
pub struct IrqResultMaxSizeOrTimeout {
complete: bool,
timeout: bool,
pub errors: Option<IrqUartError>,
pub errors: Option<UartErrors>,
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<Uart: Instance> RxWithIrq<Uart> {
fn read_handler(
&self,
errors: &mut Option<IrqUartError>,
errors: &mut Option<UartErrors>,
read_res: &nb::Result<u8, RxError>,
) -> Option<u8> {
match read_res {
@ -1172,7 +1172,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
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<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();
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;