diff --git a/va416xx-hal/Cargo.toml b/va416xx-hal/Cargo.toml index df81791..2a3d3b3 100644 --- a/va416xx-hal/Cargo.toml +++ b/va416xx-hal/Cargo.toml @@ -16,21 +16,26 @@ critical-section = "1" nb = "1" paste = "1" embedded-hal-nb = "1" +embedded-hal-async = "1" embedded-hal = "1" embedded-io = "0.6" num_enum = { version = "0.7", default-features = false } typenum = "1" bitflags = "2" bitfield = "0.17" -defmt = { version = "0.3", optional = true } fugit = "0.3" delegate = "0.12" void = { version = "1", default-features = false } thiserror = { version = "2", default-features = false } +portable-atomic = "1" +embassy-sync = "0.6" + +defmt = { version = "0.3", optional = true } [dependencies.va416xx] default-features = false -version = "0.3" +path = "../va416xx" +version = "0.4" features = ["critical-section"] [features] diff --git a/va416xx-hal/src/gpio/asynch.rs b/va416xx-hal/src/gpio/asynch.rs new file mode 100644 index 0000000..1d175b1 --- /dev/null +++ b/va416xx-hal/src/gpio/asynch.rs @@ -0,0 +1,452 @@ +//! # Async GPIO functionality for the VA416xx family. +//! +//! This module provides the [InputPinAsync] and [InputDynPinAsync] which both implement +//! the [embedded_hal_async::digital::Wait] trait. These types allow for asynchronous waiting +//! on GPIO pins. Please note that this module does not specify/declare the interrupt handlers +//! which must be provided for async support to work. However, it provides the +//! [on_interrupt_for_async_gpio_for_port] generic interrupt handler. This should be called in all +//! IRQ functions which handle any GPIO interrupts with the corresponding [Port] argument. +//! +//! # Example +//! +//! - [Async GPIO example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/embassy/src/bin/async-gpio.rs) +use core::future::Future; + +use embassy_sync::waitqueue::AtomicWaker; +use embedded_hal::digital::InputPin; +use embedded_hal_async::digital::Wait; +use portable_atomic::AtomicBool; +use va416xx::{self as pac}; + +use super::{ + pin, DynPin, DynPinId, InputConfig, InterruptEdge, InvalidPinTypeError, Pin, PinId, Port, + NUM_PINS_PORT_A_TO_F, +}; + +static WAKERS_FOR_PORT_A: [AtomicWaker; NUM_PINS_PORT_A_TO_F] = + [const { AtomicWaker::new() }; NUM_PINS_PORT_A_TO_F]; +static WAKERS_FOR_PORT_B: [AtomicWaker; NUM_PINS_PORT_A_TO_F] = + [const { AtomicWaker::new() }; NUM_PINS_PORT_A_TO_F]; +static WAKERS_FOR_PORT_C: [AtomicWaker; NUM_PINS_PORT_A_TO_F] = + [const { AtomicWaker::new() }; NUM_PINS_PORT_A_TO_F]; +static WAKERS_FOR_PORT_D: [AtomicWaker; NUM_PINS_PORT_A_TO_F] = + [const { AtomicWaker::new() }; NUM_PINS_PORT_A_TO_F]; +static WAKERS_FOR_PORT_E: [AtomicWaker; NUM_PINS_PORT_A_TO_F] = + [const { AtomicWaker::new() }; NUM_PINS_PORT_A_TO_F]; +static WAKERS_FOR_PORT_F: [AtomicWaker; NUM_PINS_PORT_A_TO_F] = + [const { AtomicWaker::new() }; NUM_PINS_PORT_A_TO_F]; + +static EDGE_DETECTION_PORT_A: [AtomicBool; NUM_PINS_PORT_A_TO_F] = + [const { AtomicBool::new(false) }; NUM_PINS_PORT_A_TO_F]; +static EDGE_DETECTION_PORT_B: [AtomicBool; NUM_PINS_PORT_A_TO_F] = + [const { AtomicBool::new(false) }; NUM_PINS_PORT_A_TO_F]; +static EDGE_DETECTION_PORT_C: [AtomicBool; NUM_PINS_PORT_A_TO_F] = + [const { AtomicBool::new(false) }; NUM_PINS_PORT_A_TO_F]; +static EDGE_DETECTION_PORT_D: [AtomicBool; NUM_PINS_PORT_A_TO_F] = + [const { AtomicBool::new(false) }; NUM_PINS_PORT_A_TO_F]; +static EDGE_DETECTION_PORT_E: [AtomicBool; NUM_PINS_PORT_A_TO_F] = + [const { AtomicBool::new(false) }; NUM_PINS_PORT_A_TO_F]; +static EDGE_DETECTION_PORT_F: [AtomicBool; NUM_PINS_PORT_A_TO_F] = + [const { AtomicBool::new(false) }; NUM_PINS_PORT_A_TO_F]; + +#[derive(Debug, thiserror::Error)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[error("port G does not support async functionality")] +pub struct PortGDoesNotSupportAsyncError; + +#[derive(Debug, thiserror::Error)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum AsyncDynPinError { + #[error("invalid pin type: {0}")] + InvalidPinType(#[from] InvalidPinTypeError), + #[error("port g does not support async functionality: {0}")] + PortGDoesNotSupportAsync(#[from] PortGDoesNotSupportAsyncError), +} + +/// Generic interrupt handler for GPIO interrupts on a specific port to support async functionalities +/// +/// This function should be called in all interrupt handlers which handle any GPIO interrupts +/// matching the [Port] argument. +/// The handler will wake the corresponding wakers for the pins that triggered an interrupts +/// as well as update the static edge detection structures. This allows the pin future tocomplete +/// complete async operations. +pub fn on_interrupt_for_async_gpio_for_port( + port: Port, +) -> Result<(), PortGDoesNotSupportAsyncError> { + let periphs = unsafe { pac::Peripherals::steal() }; + + let (irq_enb, edge_status, wakers, edge_detection) = match port { + Port::A => ( + periphs.porta.irq_enb().read().bits(), + periphs.porta.edge_status().read().bits(), + &WAKERS_FOR_PORT_A, + &EDGE_DETECTION_PORT_A, + ), + Port::B => ( + periphs.portb.irq_enb().read().bits(), + periphs.portb.edge_status().read().bits(), + &WAKERS_FOR_PORT_B, + &EDGE_DETECTION_PORT_B, + ), + Port::C => ( + periphs.portc.irq_enb().read().bits(), + periphs.portc.edge_status().read().bits(), + &WAKERS_FOR_PORT_C, + &EDGE_DETECTION_PORT_C, + ), + Port::D => ( + periphs.portd.irq_enb().read().bits(), + periphs.portd.edge_status().read().bits(), + &WAKERS_FOR_PORT_D, + &EDGE_DETECTION_PORT_D, + ), + Port::E => ( + periphs.porte.irq_enb().read().bits(), + periphs.porte.edge_status().read().bits(), + &WAKERS_FOR_PORT_E, + &EDGE_DETECTION_PORT_E, + ), + Port::F => ( + periphs.portf.irq_enb().read().bits(), + periphs.portf.edge_status().read().bits(), + &WAKERS_FOR_PORT_F, + &EDGE_DETECTION_PORT_F, + ), + Port::G => return Err(PortGDoesNotSupportAsyncError), + }; + + on_interrupt_for_port(irq_enb, edge_status, wakers, edge_detection); + Ok(()) +} + +#[inline] +fn on_interrupt_for_port( + mut irq_enb: u32, + edge_status: u32, + wakers: &'static [AtomicWaker], + edge_detection: &'static [AtomicBool], +) { + while irq_enb != 0 { + let bit_pos = irq_enb.trailing_zeros() as usize; + let bit_mask = 1 << bit_pos; + + wakers[bit_pos].wake(); + + if edge_status & bit_mask != 0 { + edge_detection[bit_pos].store(true, core::sync::atomic::Ordering::Relaxed); + + // Clear the processed bit + irq_enb &= !bit_mask; + } + } +} + +/// Input pin future which implements the [Future] trait. +/// +/// Generally, you want to use the [InputPinAsync] or [InputDynPinAsync] types instead of this +/// which also implements the [embedded_hal_async::digital::Wait] trait. However, access to this +/// struture is granted to allow writing custom async structures. +pub struct InputPinFuture { + pin_id: DynPinId, + waker_group: &'static [AtomicWaker], + edge_detection_group: &'static [AtomicBool], +} + +impl InputPinFuture { + pub fn new_with_dyn_pin( + pin: &mut DynPin, + edge: InterruptEdge, + ) -> Result { + if !pin.is_input_pin() { + return Err(InvalidPinTypeError(pin.mode()).into()); + } + if pin.id().port == Port::G { + return Err(PortGDoesNotSupportAsyncError.into()); + } + + let (waker_group, edge_detection_group) = + Self::pin_group_to_waker_and_edge_detection_group(pin.id().port); + edge_detection_group[pin.id().num as usize] + .store(false, core::sync::atomic::Ordering::Relaxed); + pin.configure_edge_interrupt(edge).unwrap(); + Ok(Self { + pin_id: pin.id(), + waker_group, + edge_detection_group, + }) + } + + pub fn new_with_pin( + pin: &mut Pin>, + edge: InterruptEdge, + ) -> Result { + if pin.id().port == Port::G { + return Err(PortGDoesNotSupportAsyncError); + } + let (waker_group, edge_detection_group) = + Self::pin_group_to_waker_and_edge_detection_group(pin.id().port); + edge_detection_group[pin.id().num as usize] + .store(false, core::sync::atomic::Ordering::Relaxed); + pin.configure_edge_interrupt(edge); + Ok(Self { + pin_id: pin.id(), + waker_group, + edge_detection_group, + }) + } + + #[inline] + pub fn pin_group_to_waker_and_edge_detection_group( + group: Port, + ) -> (&'static [AtomicWaker], &'static [AtomicBool]) { + match group { + Port::A => (WAKERS_FOR_PORT_A.as_ref(), EDGE_DETECTION_PORT_A.as_ref()), + Port::B => (WAKERS_FOR_PORT_B.as_ref(), EDGE_DETECTION_PORT_B.as_ref()), + Port::C => (WAKERS_FOR_PORT_C.as_ref(), EDGE_DETECTION_PORT_C.as_ref()), + Port::D => (WAKERS_FOR_PORT_D.as_ref(), EDGE_DETECTION_PORT_D.as_ref()), + Port::E => (WAKERS_FOR_PORT_E.as_ref(), EDGE_DETECTION_PORT_E.as_ref()), + Port::F => (WAKERS_FOR_PORT_F.as_ref(), EDGE_DETECTION_PORT_F.as_ref()), + _ => panic!("unexpected pin group G"), + } + } +} + +impl Drop for InputPinFuture { + fn drop(&mut self) { + // TODO: Fix this. Try to use HAL helpers. + let periphs = unsafe { pac::Peripherals::steal() }; + if self.pin_id.port == Port::A { + periphs + .porta + .irq_enb() + .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.pin_id.num)) }); + } else { + periphs + .porta + .irq_enb() + .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.pin_id.num)) }); + } + } +} + +impl Future for InputPinFuture { + type Output = (); + fn poll( + self: core::pin::Pin<&mut Self>, + cx: &mut core::task::Context<'_>, + ) -> core::task::Poll { + let idx = self.pin_id.num as usize; + self.waker_group[idx].register(cx.waker()); + if self.edge_detection_group[idx].swap(false, core::sync::atomic::Ordering::Relaxed) { + return core::task::Poll::Ready(()); + } + core::task::Poll::Pending + } +} + +pub struct InputDynPinAsync { + pin: DynPin, +} + +impl InputDynPinAsync { + /// Create a new asynchronous input pin from a [DynPin]. The interrupt ID to be used must be + /// passed as well and is used to route and enable the interrupt. + /// + /// Please note that the interrupt handler itself must be provided by the user and the + /// generic [on_interrupt_for_async_gpio_for_port] function must be called inside that function + /// for the asynchronous functionality to work. + pub fn new(pin: DynPin) -> Result { + if !pin.is_input_pin() { + return Err(InvalidPinTypeError(pin.mode()).into()); + } + if pin.id().port == Port::G { + return Err(PortGDoesNotSupportAsyncError.into()); + } + Ok(Self { pin }) + } + + /// Asynchronously wait until the pin is high. + /// + /// This returns immediately if the pin is already high. + pub async fn wait_for_high(&mut self) { + // Unwrap okay, checked pin in constructor. + let fut = + InputPinFuture::new_with_dyn_pin(&mut self.pin, InterruptEdge::LowToHigh).unwrap(); + if self.pin.is_high().unwrap() { + return; + } + fut.await; + } + + /// Asynchronously wait until the pin is low. + /// + /// This returns immediately if the pin is already high. + pub async fn wait_for_low(&mut self) { + // Unwrap okay, checked pin in constructor. + let fut = + InputPinFuture::new_with_dyn_pin(&mut self.pin, InterruptEdge::HighToLow).unwrap(); + if self.pin.is_low().unwrap() { + return; + } + fut.await; + } + + /// Asynchronously wait until the pin sees a falling edge. + pub async fn wait_for_falling_edge(&mut self) { + // Unwrap okay, checked pin in constructor. + InputPinFuture::new_with_dyn_pin(&mut self.pin, InterruptEdge::HighToLow) + .unwrap() + .await; + } + + /// Asynchronously wait until the pin sees a rising edge. + pub async fn wait_for_rising_edge(&mut self) { + // Unwrap okay, checked pin in constructor. + InputPinFuture::new_with_dyn_pin(&mut self.pin, InterruptEdge::LowToHigh) + .unwrap() + .await; + } + + /// Asynchronously wait until the pin sees any edge (either rising or falling). + pub async fn wait_for_any_edge(&mut self) { + // Unwrap okay, checked pin in constructor. + InputPinFuture::new_with_dyn_pin(&mut self.pin, InterruptEdge::BothEdges) + .unwrap() + .await; + } + + pub fn release(self) -> DynPin { + self.pin + } +} + +impl embedded_hal::digital::ErrorType for InputDynPinAsync { + type Error = core::convert::Infallible; +} + +impl Wait for InputDynPinAsync { + async fn wait_for_high(&mut self) -> Result<(), Self::Error> { + self.wait_for_high().await; + Ok(()) + } + + async fn wait_for_low(&mut self) -> Result<(), Self::Error> { + self.wait_for_low().await; + Ok(()) + } + + async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_rising_edge().await; + Ok(()) + } + + async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_falling_edge().await; + Ok(()) + } + + async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_any_edge().await; + Ok(()) + } +} + +pub struct InputPinAsync { + pin: Pin>, +} + +impl InputPinAsync { + /// Create a new asynchronous input pin from a typed [Pin]. The interrupt ID to be used must be + /// passed as well and is used to route and enable the interrupt. + /// + /// Please note that the interrupt handler itself must be provided by the user and the + /// generic [on_interrupt_for_async_gpio_for_port] function must be called inside that function + /// for the asynchronous functionality to work. + pub fn new(pin: Pin>) -> Result { + if pin.id().port == Port::G { + return Err(PortGDoesNotSupportAsyncError); + } + Ok(Self { pin }) + } + + /// Asynchronously wait until the pin is high. + /// + /// This returns immediately if the pin is already high. + pub async fn wait_for_high(&mut self) { + // Unwrap okay, checked pin in constructor. + let fut = InputPinFuture::new_with_pin(&mut self.pin, InterruptEdge::LowToHigh).unwrap(); + if self.pin.is_high().unwrap() { + return; + } + fut.await; + } + + /// Asynchronously wait until the pin is low. + /// + /// This returns immediately if the pin is already high. + pub async fn wait_for_low(&mut self) { + let fut = InputPinFuture::new_with_pin(&mut self.pin, InterruptEdge::HighToLow).unwrap(); + if self.pin.is_low().unwrap() { + return; + } + fut.await; + } + + /// Asynchronously wait until the pin sees falling edge. + pub async fn wait_for_falling_edge(&mut self) { + // Unwrap okay, checked pin in constructor. + InputPinFuture::new_with_pin(&mut self.pin, InterruptEdge::HighToLow) + .unwrap() + .await; + } + + /// Asynchronously wait until the pin sees rising edge. + pub async fn wait_for_rising_edge(&mut self) { + // Unwrap okay, checked pin in constructor. + InputPinFuture::new_with_pin(&mut self.pin, InterruptEdge::LowToHigh) + .unwrap() + .await; + } + + /// Asynchronously wait until the pin sees any edge (either rising or falling). + pub async fn wait_for_any_edge(&mut self) { + // Unwrap okay, checked pin in constructor. + InputPinFuture::new_with_pin(&mut self.pin, InterruptEdge::BothEdges) + .unwrap() + .await; + } + + pub fn release(self) -> Pin> { + self.pin + } +} +impl embedded_hal::digital::ErrorType for InputPinAsync { + type Error = core::convert::Infallible; +} + +impl Wait for InputPinAsync { + async fn wait_for_high(&mut self) -> Result<(), Self::Error> { + self.wait_for_high().await; + Ok(()) + } + + async fn wait_for_low(&mut self) -> Result<(), Self::Error> { + self.wait_for_low().await; + Ok(()) + } + + async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_rising_edge().await; + Ok(()) + } + + async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_falling_edge().await; + Ok(()) + } + + async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_any_edge().await; + Ok(()) + } +} diff --git a/va416xx-hal/src/gpio/dynpin.rs b/va416xx-hal/src/gpio/dynpin.rs index 335493e..85e3ff5 100644 --- a/va416xx-hal/src/gpio/dynpin.rs +++ b/va416xx-hal/src/gpio/dynpin.rs @@ -59,7 +59,7 @@ use embedded_hal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin}; use super::{ reg::RegisterInterface, FilterClkSel, FilterType, InterruptEdge, InterruptLevel, Pin, PinId, - PinMode, PinState, + PinMode, PinState, Port, }; //================================================================================================== @@ -155,24 +155,13 @@ pub const DYN_ALT_FUNC_3: DynPinMode = DynPinMode::Alternate(DynAlternate::Sel3) // DynGroup & DynPinId //================================================================================================== -/// Value-level `enum` for pin groups -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum DynGroup { - A, - B, - C, - D, - E, - F, - G, -} +pub type DynGroup = Port; /// Value-level `struct` representing pin IDs #[derive(Debug, PartialEq, Eq, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct DynPinId { - pub group: DynGroup, + pub port: Port, pub num: u8, } @@ -263,6 +252,11 @@ impl DynPin { } } + #[inline] + pub fn is_input_pin(&self) -> bool { + matches!(self.mode, DynPinMode::Input(_)) + } + #[inline] pub fn into_funsel_1(&mut self) { self.into_mode(DYN_ALT_FUNC_1); diff --git a/va416xx-hal/src/gpio/mod.rs b/va416xx-hal/src/gpio/mod.rs index 59de6a5..9338388 100644 --- a/va416xx-hal/src/gpio/mod.rs +++ b/va416xx-hal/src/gpio/mod.rs @@ -21,15 +21,62 @@ //! ## Examples //! //! - [Blinky example](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/examples/simple/examples/blinky.rs) + +//================================================================================================== +// Errors, Definitions and Constants +//================================================================================================== + +pub const NUM_PINS_PORT_A_TO_F: usize = 16; +pub const NUM_PINS_PORT_G: usize = 8; +pub const NUM_GPIO_PINS: usize = NUM_PINS_PORT_A_TO_F * 6 + NUM_PINS_PORT_G; +pub const NUM_GPIO_PINS_WITH_IRQ: usize = NUM_GPIO_PINS - NUM_PINS_PORT_G; + #[derive(Debug, PartialEq, Eq, thiserror::Error)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[error("pin is masked")] pub struct IsMaskedError; +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Port { + A, + B, + C, + D, + E, + F, + G, +} + +#[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum InterruptEdge { + HighToLow, + LowToHigh, + BothEdges, +} + +#[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, +} + pub mod pin; pub use pin::*; pub mod dynpin; pub use dynpin::*; +pub mod asynch; +pub use asynch::*; + mod reg; diff --git a/va416xx-hal/src/gpio/pin.rs b/va416xx-hal/src/gpio/pin.rs index 95a4d02..b246a46 100644 --- a/va416xx-hal/src/gpio/pin.rs +++ b/va416xx-hal/src/gpio/pin.rs @@ -78,36 +78,10 @@ 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, DynPin, DynPinId, - DynPinMode, + reg::RegisterInterface, DynAlternate, DynInput, DynOutput, DynPin, DynPinId, DynPinMode, + InterruptEdge, InterruptLevel, PinState, Port, }; -//================================================================================================== -// Errors and Definitions -//================================================================================================== - -#[derive(Debug, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum InterruptEdge { - HighToLow, - LowToHigh, - BothEdges, -} - -#[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, -} - //================================================================================================== // Input configuration //================================================================================================== @@ -312,7 +286,7 @@ macro_rules! pin_id { $(#[$meta])? impl PinId for $Id { const DYN: DynPinId = DynPinId { - group: DynGroup::$Group, + port: Port::$Group, num: $NUM, }; } diff --git a/va416xx-hal/src/gpio/reg.rs b/va416xx-hal/src/gpio/reg.rs index 427f6d1..777562a 100644 --- a/va416xx-hal/src/gpio/reg.rs +++ b/va416xx-hal/src/gpio/reg.rs @@ -1,8 +1,9 @@ use crate::FunSel; use super::{ - dynpin::{self, DynGroup, DynPinId}, + dynpin::{self, DynPinId}, DynPinMode, FilterClkSel, FilterType, InterruptEdge, InterruptLevel, IsMaskedError, PinState, + Port, }; use va416xx::{ioconfig, porta, Ioconfig, Porta, Portb, Portc, Portd, Porte, Portf, Portg}; @@ -146,28 +147,28 @@ pub(super) unsafe trait RegisterInterface { #[inline(always)] fn port_reg(&self) -> &PortRegisterBlock { - match self.id().group { - DynGroup::A => unsafe { &(*Porta::ptr()) }, - DynGroup::B => unsafe { &(*Portb::ptr()) }, - DynGroup::C => unsafe { &(*Portc::ptr()) }, - DynGroup::D => unsafe { &(*Portd::ptr()) }, - DynGroup::E => unsafe { &(*Porte::ptr()) }, - DynGroup::F => unsafe { &(*Portf::ptr()) }, - DynGroup::G => unsafe { &(*Portg::ptr()) }, + match self.id().port { + Port::A => unsafe { &(*Porta::ptr()) }, + Port::B => unsafe { &(*Portb::ptr()) }, + Port::C => unsafe { &(*Portc::ptr()) }, + Port::D => unsafe { &(*Portd::ptr()) }, + Port::E => unsafe { &(*Porte::ptr()) }, + Port::F => unsafe { &(*Portf::ptr()) }, + Port::G => unsafe { &(*Portg::ptr()) }, } } #[inline(always)] fn iocfg_port(&self) -> &PortReg { let ioconfig = unsafe { Ioconfig::ptr().as_ref().unwrap() }; - match self.id().group { - DynGroup::A => ioconfig.porta(self.id().num as usize), - DynGroup::B => ioconfig.portb0(self.id().num as usize), - DynGroup::C => ioconfig.portc0(self.id().num as usize), - DynGroup::D => ioconfig.portd0(self.id().num as usize), - DynGroup::E => ioconfig.porte0(self.id().num as usize), - DynGroup::F => ioconfig.portf0(self.id().num as usize), - DynGroup::G => ioconfig.portg0(self.id().num as usize), + match self.id().port { + Port::A => ioconfig.porta(self.id().num as usize), + Port::B => ioconfig.portb0(self.id().num as usize), + Port::C => ioconfig.portc0(self.id().num as usize), + Port::D => ioconfig.portd0(self.id().num as usize), + Port::E => ioconfig.porte0(self.id().num as usize), + Port::F => ioconfig.portf0(self.id().num as usize), + Port::G => ioconfig.portg0(self.id().num as usize), } } diff --git a/va416xx-hal/src/timer.rs b/va416xx-hal/src/timer.rs index 2e7d10e..5e9f8d2 100644 --- a/va416xx-hal/src/timer.rs +++ b/va416xx-hal/src/timer.rs @@ -406,7 +406,7 @@ pub type TimRegBlock = pac::tim0::RegisterBlock; /// /// # Safety /// -/// Users should only implement the [`tim_id`] function. No default function +/// Users should only implement the [Self::tim_id] function. No default function /// implementations should be overridden. The implementing type must also have /// "control" over the corresponding pin ID, i.e. it must guarantee that a each /// pin ID is a singleton. diff --git a/va416xx-hal/src/uart.rs b/va416xx-hal/src/uart.rs index 4f1ea2a..cc0e11a 100644 --- a/va416xx-hal/src/uart.rs +++ b/va416xx-hal/src/uart.rs @@ -1,7 +1,7 @@ //! # API for the UART peripheral //! //! The core of this API are the [Uart], [UartBase], [Rx] and [Tx] structures. -//! The RX structure also has a dedicated [RxWithIrq] variant which allows reading the receiver +//! The RX structure also has a dedicated [RxWithInterrupt] variant which allows reading the receiver //! using interrupts. //! //! ## Examples