Bugfix and improvements for async GPIO
This commit is contained in:
parent
a65f4039ee
commit
8b55d0923f
@ -27,8 +27,8 @@ embassy-executor = { version = "0.7", features = [
|
|||||||
"executor-interrupt"
|
"executor-interrupt"
|
||||||
]}
|
]}
|
||||||
|
|
||||||
va108xx-hal = "0.9"
|
va108xx-hal = { version = "0.9", path = "../../va108xx-hal" }
|
||||||
va108xx-embassy = "0.1"
|
va108xx-embassy = { version = "0.1", path = "../../va108xx-embassy" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["ticks-hz-1_000", "va108xx-embassy/irq-oc30-oc31"]
|
default = ["ticks-hz-1_000", "va108xx-embassy/irq-oc30-oc31"]
|
||||||
|
@ -14,7 +14,9 @@ use embedded_hal_async::digital::Wait;
|
|||||||
use panic_rtt_target as _;
|
use panic_rtt_target as _;
|
||||||
use rtt_target::{rprintln, rtt_init_print};
|
use rtt_target::{rprintln, rtt_init_print};
|
||||||
use va108xx_embassy::embassy;
|
use va108xx_embassy::embassy;
|
||||||
use va108xx_hal::gpio::{on_interrupt_for_asynch_gpio, InputDynPinAsync, InputPinAsync, PinsB};
|
use va108xx_hal::gpio::{
|
||||||
|
on_interrupt_for_async_gpio_for_port, InputDynPinAsync, InputPinAsync, PinsB, Port,
|
||||||
|
};
|
||||||
use va108xx_hal::{
|
use va108xx_hal::{
|
||||||
gpio::{DynPin, PinsA},
|
gpio::{DynPin, PinsA},
|
||||||
pac::{self, interrupt},
|
pac::{self, interrupt},
|
||||||
@ -244,15 +246,16 @@ async fn output_task(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PB22 to PB23 can be handled by both OC10 and OC11 depending on configuration.
|
// PB22 to PB23 can be handled by both OC10 and OC11 depending on configuration.
|
||||||
|
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn OC10() {
|
fn OC10() {
|
||||||
on_interrupt_for_asynch_gpio();
|
on_interrupt_for_async_gpio_for_port(Port::A);
|
||||||
|
on_interrupt_for_async_gpio_for_port(Port::B);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This interrupt only handles PORT B interrupts.
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn OC11() {
|
fn OC11() {
|
||||||
on_interrupt_for_asynch_gpio();
|
on_interrupt_for_async_gpio_for_port(Port::B);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ embassy-time-queue-utils = "0.1"
|
|||||||
|
|
||||||
once_cell = { version = "1", default-features = false, features = ["critical-section"] }
|
once_cell = { version = "1", default-features = false, features = ["critical-section"] }
|
||||||
|
|
||||||
va108xx-hal = "0.9"
|
va108xx-hal = { version = "0.9", path = "../va108xx-hal" }
|
||||||
|
|
||||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))'.dependencies]
|
[target.'cfg(all(target_arch = "arm", target_os = "none"))'.dependencies]
|
||||||
portable-atomic = { version = "1", features = ["unsafe-assume-single-core"] }
|
portable-atomic = { version = "1", features = ["unsafe-assume-single-core"] }
|
||||||
|
@ -17,6 +17,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
## Changed
|
## Changed
|
||||||
|
|
||||||
- Missing GPIO API replacements from `x` to `configure_x`
|
- Missing GPIO API replacements from `x` to `configure_x`
|
||||||
|
- Renamed GPIO `DynGroup` to `Port`
|
||||||
|
- Rename generic GPIO interrupt handler into `on_interrupt_for_asynch_gpio`
|
||||||
|
into `on_interrupt_for_async_gpio_for_port` which expects a Port argument
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- Bug in async GPIO interrupt handler where all enabled interrupts, even the ones which might
|
||||||
|
be unrelated to the pin, were disabled.
|
||||||
|
|
||||||
## [v0.9.0]
|
## [v0.9.0]
|
||||||
|
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
//! This module provides the [InputPinAsync] and [InputDynPinAsync] which both implement
|
//! This module provides the [InputPinAsync] and [InputDynPinAsync] which both implement
|
||||||
//! the [embedded_hal_async::digital::Wait] trait. These types allow for asynchronous waiting
|
//! 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
|
//! 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 one generic
|
//! which must be provided for async support to work. However, it provides the
|
||||||
//! [handler][on_interrupt_for_asynch_gpio] which should be called in ALL user interrupt handlers
|
//! [on_interrupt_for_async_gpio_for_port] generic interrupt handler. This should be called in all
|
||||||
//! which handle GPIO interrupts.
|
//! IRQ functions which handle any GPIO interrupts with the corresponding [Port] argument.
|
||||||
//!
|
//!
|
||||||
//! # Example
|
//! # Example
|
||||||
//!
|
//!
|
||||||
@ -21,60 +21,66 @@ use va108xx::{self as pac, Irqsel, Sysconfig};
|
|||||||
use crate::InterruptConfig;
|
use crate::InterruptConfig;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
pin, DynGroup, DynPin, DynPinId, InputConfig, InterruptEdge, InvalidPinTypeError, Pin, PinId,
|
pin, DynPin, DynPinId, InputConfig, InterruptEdge, InvalidPinTypeError, Pin, PinId, Port,
|
||||||
NUM_GPIO_PINS, NUM_PINS_PORT_A,
|
NUM_PINS_PORT_A, NUM_PINS_PORT_B,
|
||||||
};
|
};
|
||||||
|
|
||||||
static WAKERS: [AtomicWaker; NUM_GPIO_PINS] = [const { AtomicWaker::new() }; NUM_GPIO_PINS];
|
static WAKERS_FOR_PORT_A: [AtomicWaker; NUM_PINS_PORT_A] =
|
||||||
static EDGE_DETECTION: [AtomicBool; NUM_GPIO_PINS] =
|
[const { AtomicWaker::new() }; NUM_PINS_PORT_A];
|
||||||
[const { AtomicBool::new(false) }; NUM_GPIO_PINS];
|
static WAKERS_FOR_PORT_B: [AtomicWaker; NUM_PINS_PORT_B] =
|
||||||
|
[const { AtomicWaker::new() }; NUM_PINS_PORT_B];
|
||||||
|
static EDGE_DETECTION_PORT_A: [AtomicBool; NUM_PINS_PORT_A] =
|
||||||
|
[const { AtomicBool::new(false) }; NUM_PINS_PORT_A];
|
||||||
|
static EDGE_DETECTION_PORT_B: [AtomicBool; NUM_PINS_PORT_B] =
|
||||||
|
[const { AtomicBool::new(false) }; NUM_PINS_PORT_B];
|
||||||
|
|
||||||
#[inline]
|
/// Generic interrupt handler for GPIO interrupts on a specific port to support async functionalities
|
||||||
fn pin_id_to_offset(dyn_pin_id: DynPinId) -> usize {
|
|
||||||
match dyn_pin_id.group {
|
|
||||||
DynGroup::A => dyn_pin_id.num as usize,
|
|
||||||
DynGroup::B => NUM_PINS_PORT_A + dyn_pin_id.num as usize,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generic interrupt handler for GPIO interrupts to support the async functionalities.
|
|
||||||
///
|
///
|
||||||
/// This handler will wake the correspoding wakers for the pins which triggered an interrupt
|
/// This function should be called in all interrupt handlers which handle any GPIO interrupts
|
||||||
/// as well as updating the static edge detection structures. This allows the pin future to
|
/// matching the [Port] argument.
|
||||||
/// complete async operations. The user should call this function in ALL interrupt handlers
|
/// The handler will wake the corresponding wakers for the pins that triggered an interrupts
|
||||||
/// which handle any GPIO interrupts.
|
/// as well as update the static edge detection structures. This allows the pin future tocomplete
|
||||||
#[inline]
|
/// complete async operations.
|
||||||
pub fn on_interrupt_for_asynch_gpio() {
|
pub fn on_interrupt_for_async_gpio_for_port(port: Port) {
|
||||||
let periphs = unsafe { pac::Peripherals::steal() };
|
let periphs = unsafe { pac::Peripherals::steal() };
|
||||||
|
|
||||||
handle_interrupt_for_gpio_and_port(
|
let (irq_enb, edge_status, wakers, edge_detection) = match port {
|
||||||
periphs.porta.irq_enb().read().bits(),
|
Port::A => (
|
||||||
periphs.porta.edge_status().read().bits(),
|
periphs.porta.irq_enb().read().bits(),
|
||||||
0,
|
periphs.porta.edge_status().read().bits(),
|
||||||
);
|
WAKERS_FOR_PORT_A.as_ref(),
|
||||||
handle_interrupt_for_gpio_and_port(
|
EDGE_DETECTION_PORT_A.as_ref(),
|
||||||
periphs.portb.irq_enb().read().bits(),
|
),
|
||||||
periphs.portb.edge_status().read().bits(),
|
Port::B => (
|
||||||
NUM_PINS_PORT_A,
|
periphs.portb.irq_enb().read().bits(),
|
||||||
);
|
periphs.portb.edge_status().read().bits(),
|
||||||
|
WAKERS_FOR_PORT_B.as_ref(),
|
||||||
|
EDGE_DETECTION_PORT_B.as_ref(),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
on_interrupt_for_port(irq_enb, edge_status, wakers, edge_detection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uses the enabled interrupt register and the persistent edge status to capture all GPIO events.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn handle_interrupt_for_gpio_and_port(mut irq_enb: u32, edge_status: u32, pin_base_offset: usize) {
|
fn on_interrupt_for_port(
|
||||||
|
mut irq_enb: u32,
|
||||||
|
edge_status: u32,
|
||||||
|
wakers: &'static [AtomicWaker],
|
||||||
|
edge_detection: &'static [AtomicBool],
|
||||||
|
) {
|
||||||
while irq_enb != 0 {
|
while irq_enb != 0 {
|
||||||
let bit_pos = irq_enb.trailing_zeros() as usize;
|
let bit_pos = irq_enb.trailing_zeros() as usize;
|
||||||
let bit_mask = 1 << bit_pos;
|
let bit_mask = 1 << bit_pos;
|
||||||
|
|
||||||
WAKERS[pin_base_offset + bit_pos].wake();
|
wakers[bit_pos].wake();
|
||||||
|
|
||||||
if edge_status & bit_mask != 0 {
|
if edge_status & bit_mask != 0 {
|
||||||
EDGE_DETECTION[pin_base_offset + bit_pos]
|
edge_detection[bit_pos].store(true, core::sync::atomic::Ordering::Relaxed);
|
||||||
.store(true, core::sync::atomic::Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the processed bit
|
// Clear the processed bit
|
||||||
irq_enb &= !bit_mask;
|
irq_enb &= !bit_mask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,6 +91,8 @@ fn handle_interrupt_for_gpio_and_port(mut irq_enb: u32, edge_status: u32, pin_ba
|
|||||||
/// struture is granted to allow writing custom async structures.
|
/// struture is granted to allow writing custom async structures.
|
||||||
pub struct InputPinFuture {
|
pub struct InputPinFuture {
|
||||||
pin_id: DynPinId,
|
pin_id: DynPinId,
|
||||||
|
waker_group: &'static [AtomicWaker],
|
||||||
|
edge_detection_group: &'static [AtomicBool],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputPinFuture {
|
impl InputPinFuture {
|
||||||
@ -102,6 +110,16 @@ impl InputPinFuture {
|
|||||||
Self::new_with_dyn_pin(pin, irq, edge, &mut periphs.sysconfig, &mut periphs.irqsel)
|
Self::new_with_dyn_pin(pin, irq, edge, &mut periphs.sysconfig, &mut periphs.irqsel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_with_dyn_pin(
|
pub fn new_with_dyn_pin(
|
||||||
pin: &mut DynPin,
|
pin: &mut DynPin,
|
||||||
irq: pac::Interrupt,
|
irq: pac::Interrupt,
|
||||||
@ -113,7 +131,9 @@ impl InputPinFuture {
|
|||||||
return Err(InvalidPinTypeError(pin.mode()));
|
return Err(InvalidPinTypeError(pin.mode()));
|
||||||
}
|
}
|
||||||
|
|
||||||
EDGE_DETECTION[pin_id_to_offset(pin.id())]
|
let (waker_group, edge_detection_group) =
|
||||||
|
Self::pin_group_to_waker_and_edge_detection_group(pin.id().group);
|
||||||
|
edge_detection_group[pin.id().num as usize]
|
||||||
.store(false, core::sync::atomic::Ordering::Relaxed);
|
.store(false, core::sync::atomic::Ordering::Relaxed);
|
||||||
pin.configure_edge_interrupt(
|
pin.configure_edge_interrupt(
|
||||||
edge,
|
edge,
|
||||||
@ -122,7 +142,11 @@ impl InputPinFuture {
|
|||||||
Some(irq_sel),
|
Some(irq_sel),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Ok(Self { pin_id: pin.id() })
|
Ok(Self {
|
||||||
|
pin_id: pin.id(),
|
||||||
|
waker_group,
|
||||||
|
edge_detection_group,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
@ -146,7 +170,9 @@ impl InputPinFuture {
|
|||||||
sys_cfg: &mut Sysconfig,
|
sys_cfg: &mut Sysconfig,
|
||||||
irq_sel: &mut Irqsel,
|
irq_sel: &mut Irqsel,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
EDGE_DETECTION[pin_id_to_offset(pin.id())]
|
let (waker_group, edge_detection_group) =
|
||||||
|
Self::pin_group_to_waker_and_edge_detection_group(pin.id().group);
|
||||||
|
edge_detection_group[pin.id().num as usize]
|
||||||
.store(false, core::sync::atomic::Ordering::Relaxed);
|
.store(false, core::sync::atomic::Ordering::Relaxed);
|
||||||
pin.configure_edge_interrupt(
|
pin.configure_edge_interrupt(
|
||||||
edge,
|
edge,
|
||||||
@ -154,14 +180,18 @@ impl InputPinFuture {
|
|||||||
Some(sys_cfg),
|
Some(sys_cfg),
|
||||||
Some(irq_sel),
|
Some(irq_sel),
|
||||||
);
|
);
|
||||||
Self { pin_id: pin.id() }
|
Self {
|
||||||
|
pin_id: pin.id(),
|
||||||
|
edge_detection_group,
|
||||||
|
waker_group,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for InputPinFuture {
|
impl Drop for InputPinFuture {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let periphs = unsafe { pac::Peripherals::steal() };
|
let periphs = unsafe { pac::Peripherals::steal() };
|
||||||
if self.pin_id.group == DynGroup::A {
|
if self.pin_id.group == Port::A {
|
||||||
periphs
|
periphs
|
||||||
.porta
|
.porta
|
||||||
.irq_enb()
|
.irq_enb()
|
||||||
@ -181,9 +211,9 @@ impl Future for InputPinFuture {
|
|||||||
self: core::pin::Pin<&mut Self>,
|
self: core::pin::Pin<&mut Self>,
|
||||||
cx: &mut core::task::Context<'_>,
|
cx: &mut core::task::Context<'_>,
|
||||||
) -> core::task::Poll<Self::Output> {
|
) -> core::task::Poll<Self::Output> {
|
||||||
let idx = pin_id_to_offset(self.pin_id);
|
let idx = self.pin_id.num as usize;
|
||||||
WAKERS[idx].register(cx.waker());
|
self.waker_group[idx].register(cx.waker());
|
||||||
if EDGE_DETECTION[idx].swap(false, core::sync::atomic::Ordering::Relaxed) {
|
if self.edge_detection_group[idx].swap(false, core::sync::atomic::Ordering::Relaxed) {
|
||||||
return core::task::Poll::Ready(());
|
return core::task::Poll::Ready(());
|
||||||
}
|
}
|
||||||
core::task::Poll::Pending
|
core::task::Poll::Pending
|
||||||
@ -200,8 +230,8 @@ impl InputDynPinAsync {
|
|||||||
/// passed as well and is used to route and enable the interrupt.
|
/// 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
|
/// Please note that the interrupt handler itself must be provided by the user and the
|
||||||
/// generic [on_interrupt_for_asynch_gpio] function must be called inside that function for
|
/// generic [on_interrupt_for_async_gpio_for_port] function must be called inside that function
|
||||||
/// the asynchronous functionality to work.
|
/// for the asynchronous functionality to work.
|
||||||
pub fn new(pin: DynPin, irq: pac::Interrupt) -> Result<Self, InvalidPinTypeError> {
|
pub fn new(pin: DynPin, irq: pac::Interrupt) -> Result<Self, InvalidPinTypeError> {
|
||||||
if !pin.is_input_pin() {
|
if !pin.is_input_pin() {
|
||||||
return Err(InvalidPinTypeError(pin.mode()));
|
return Err(InvalidPinTypeError(pin.mode()));
|
||||||
@ -335,8 +365,8 @@ impl<I: PinId, C: InputConfig> InputPinAsync<I, C> {
|
|||||||
/// passed as well and is used to route and enable the interrupt.
|
/// 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
|
/// Please note that the interrupt handler itself must be provided by the user and the
|
||||||
/// generic [on_interrupt_for_asynch_gpio] function must be called inside that function for
|
/// generic [on_interrupt_for_async_gpio_for_port] function must be called inside that function
|
||||||
/// the asynchronous functionality to work.
|
/// for the asynchronous functionality to work.
|
||||||
pub fn new(pin: Pin<I, pin::Input<C>>, irq: pac::Interrupt) -> Self {
|
pub fn new(pin: Pin<I, pin::Input<C>>, irq: pac::Interrupt) -> Self {
|
||||||
Self { pin, irq }
|
Self { pin, irq }
|
||||||
}
|
}
|
||||||
|
@ -57,9 +57,9 @@
|
|||||||
//! [InvalidPinTypeError].
|
//! [InvalidPinTypeError].
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
pin::{FilterType, InterruptEdge, InterruptLevel, Pin, PinId, PinMode, PinState},
|
pin::{FilterType, Pin, PinId, PinMode},
|
||||||
reg::RegisterInterface,
|
reg::RegisterInterface,
|
||||||
InputDynPinAsync,
|
InputDynPinAsync, InterruptEdge, InterruptLevel, PinState,
|
||||||
};
|
};
|
||||||
use crate::{clock::FilterClkSel, enable_nvic_interrupt, pac, FunSel, InterruptConfig};
|
use crate::{clock::FilterClkSel, enable_nvic_interrupt, pac, FunSel, InterruptConfig};
|
||||||
|
|
||||||
@ -156,19 +156,13 @@ pub const DYN_ALT_FUNC_3: DynPinMode = DynPinMode::Alternate(DynAlternate::Sel3)
|
|||||||
// DynGroup & DynPinId
|
// DynGroup & DynPinId
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
/// Value-level `enum` for pin groups
|
pub type DynGroup = super::Port;
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
|
||||||
pub enum DynGroup {
|
|
||||||
A,
|
|
||||||
B,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Value-level `struct` representing pin IDs
|
/// Value-level `struct` representing pin IDs
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct DynPinId {
|
pub struct DynPinId {
|
||||||
pub group: DynGroup,
|
pub group: super::Port,
|
||||||
pub num: u8,
|
pub num: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,12 +363,12 @@ impl DynPin {
|
|||||||
if irq_cfg.route {
|
if irq_cfg.route {
|
||||||
match self.regs.id().group {
|
match self.regs.id().group {
|
||||||
// Set the correct interrupt number in the IRQSEL register
|
// Set the correct interrupt number in the IRQSEL register
|
||||||
DynGroup::A => {
|
super::Port::A => {
|
||||||
irqsel
|
irqsel
|
||||||
.porta0(self.regs.id().num as usize)
|
.porta0(self.regs.id().num as usize)
|
||||||
.write(|w| unsafe { w.bits(irq_cfg.id as u32) });
|
.write(|w| unsafe { w.bits(irq_cfg.id as u32) });
|
||||||
}
|
}
|
||||||
DynGroup::B => {
|
super::Port::B => {
|
||||||
irqsel
|
irqsel
|
||||||
.portb0(self.regs.id().num as usize)
|
.portb0(self.regs.id().num as usize)
|
||||||
.write(|w| unsafe { w.bits(irq_cfg.id as u32) });
|
.write(|w| unsafe { w.bits(irq_cfg.id as u32) });
|
||||||
|
@ -22,14 +22,47 @@
|
|||||||
//!
|
//!
|
||||||
//! - [Blinky example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/blinky.rs)
|
//! - [Blinky example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/blinky.rs)
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Errors, Definitions and Constants
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
pub const NUM_PINS_PORT_A: usize = 32;
|
||||||
|
pub const NUM_PINS_PORT_B: usize = 24;
|
||||||
|
pub const NUM_GPIO_PINS: usize = NUM_PINS_PORT_A + NUM_PINS_PORT_B;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
|
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
#[error("The pin is masked")]
|
#[error("The pin is masked")]
|
||||||
pub struct IsMaskedError;
|
pub struct IsMaskedError;
|
||||||
|
|
||||||
pub const NUM_PINS_PORT_A: usize = 32;
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
pub const NUM_PINS_PORT_B: usize = 24;
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub const NUM_GPIO_PINS: usize = NUM_PINS_PORT_A + NUM_PINS_PORT_B;
|
pub enum Port {
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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 dynpin;
|
pub mod dynpin;
|
||||||
pub use dynpin::*;
|
pub use dynpin::*;
|
||||||
|
@ -70,9 +70,9 @@
|
|||||||
//! This module implements all of the embedded HAL GPIO traits for each [`Pin`]
|
//! This module implements all of the embedded HAL GPIO traits for each [`Pin`]
|
||||||
//! in the corresponding [`PinMode`]s, namely: [`InputPin`], [`OutputPin`],
|
//! in the corresponding [`PinMode`]s, namely: [`InputPin`], [`OutputPin`],
|
||||||
//! and [`StatefulOutputPin`].
|
//! and [`StatefulOutputPin`].
|
||||||
use super::dynpin::{DynAlternate, DynGroup, DynInput, DynOutput, DynPinId, DynPinMode};
|
use super::dynpin::{DynAlternate, DynInput, DynOutput, DynPinId, DynPinMode};
|
||||||
use super::reg::RegisterInterface;
|
use super::reg::RegisterInterface;
|
||||||
use super::{DynPin, InputPinAsync};
|
use super::{DynPin, InputPinAsync, InterruptEdge, InterruptLevel, PinState, Port};
|
||||||
use crate::{
|
use crate::{
|
||||||
pac::{Irqsel, Porta, Portb, Sysconfig},
|
pac::{Irqsel, Porta, Portb, Sysconfig},
|
||||||
typelevel::Sealed,
|
typelevel::Sealed,
|
||||||
@ -84,32 +84,6 @@ use core::mem::transmute;
|
|||||||
use embedded_hal::digital::{InputPin, OutputPin, StatefulOutputPin};
|
use embedded_hal::digital::{InputPin, OutputPin, StatefulOutputPin};
|
||||||
use paste::paste;
|
use paste::paste;
|
||||||
|
|
||||||
//==================================================================================================
|
|
||||||
// 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
|
// Input configuration
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
@ -321,7 +295,7 @@ macro_rules! pin_id {
|
|||||||
impl Sealed for $Id {}
|
impl Sealed for $Id {}
|
||||||
impl PinId for $Id {
|
impl PinId for $Id {
|
||||||
const DYN: DynPinId = DynPinId {
|
const DYN: DynPinId = DynPinId {
|
||||||
group: DynGroup::$Group,
|
group: Port::$Group,
|
||||||
num: $NUM,
|
num: $NUM,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use super::dynpin::{self, DynGroup, DynPinId, DynPinMode};
|
use super::dynpin::{self, DynPinId, DynPinMode};
|
||||||
use super::pin::{FilterType, InterruptEdge, InterruptLevel, PinState};
|
use super::pin::FilterType;
|
||||||
use super::IsMaskedError;
|
use super::{InterruptEdge, InterruptLevel, IsMaskedError, PinState, Port};
|
||||||
use crate::clock::FilterClkSel;
|
use crate::clock::FilterClkSel;
|
||||||
use va108xx::{ioconfig, porta};
|
use va108xx::{ioconfig, porta};
|
||||||
|
|
||||||
@ -146,15 +146,15 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn port_reg(&self) -> &PortRegisterBlock {
|
fn port_reg(&self) -> &PortRegisterBlock {
|
||||||
match self.id().group {
|
match self.id().group {
|
||||||
DynGroup::A => unsafe { &(*Self::PORTA) },
|
Port::A => unsafe { &(*Self::PORTA) },
|
||||||
DynGroup::B => unsafe { &(*Self::PORTB) },
|
Port::B => unsafe { &(*Self::PORTB) },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn iocfg_port(&self) -> &PortReg {
|
fn iocfg_port(&self) -> &PortReg {
|
||||||
let ioconfig = unsafe { va108xx::Ioconfig::ptr().as_ref().unwrap() };
|
let ioconfig = unsafe { va108xx::Ioconfig::ptr().as_ref().unwrap() };
|
||||||
match self.id().group {
|
match self.id().group {
|
||||||
DynGroup::A => ioconfig.porta(self.id().num as usize),
|
Port::A => ioconfig.porta(self.id().num as usize),
|
||||||
DynGroup::B => ioconfig.portb0(self.id().num as usize),
|
Port::B => ioconfig.portb0(self.id().num as usize),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user