GPIO refactoring and API improvements

This commit is contained in:
Robin Müller 2025-02-09 12:38:20 +01:00
parent b2d17e10ed
commit da1f2902b2
9 changed files with 198 additions and 198 deletions

View File

@ -21,7 +21,7 @@ jobs:
- uses: dtolnay/rust-toolchain@stable - uses: dtolnay/rust-toolchain@stable
- name: Install nextest - name: Install nextest
uses: taiki-e/install-action@nextest uses: taiki-e/install-action@nextest
- run: cargo nextest run --all-features -p va108xx-hal - run: cargo nextest run --all-features -p va108xx-hal --no-tests=pass
# I think we can skip those on an embedded crate.. # I think we can skip those on an embedded crate..
# - run: cargo test --doc -p va108xx-hal # - run: cargo test --doc -p va108xx-hal

View File

@ -99,9 +99,11 @@ fn main() -> ! {
} }
TestCase::TestMask => { TestCase::TestMask => {
// Tie PORTA[0] to PORTA[1] for these tests! // Tie PORTA[0] to PORTA[1] for these tests!
let input = pinsa.pa1.into_pull_down_input().clear_datamask(); let mut input = pinsa.pa1.into_pull_down_input();
input.clear_datamask();
assert!(!input.datamask()); assert!(!input.datamask());
let mut out = pinsa.pa0.into_push_pull_output().clear_datamask(); let mut out = pinsa.pa0.into_push_pull_output();
out.clear_datamask();
assert!(input.is_low_masked().is_err()); assert!(input.is_low_masked().is_err());
assert!(out.set_high_masked().is_err()); assert!(out.set_high_masked().is_err());
} }
@ -119,17 +121,15 @@ fn main() -> ! {
assert_eq!(PinsB::get_perid(), 0x004007e1); assert_eq!(PinsB::get_perid(), 0x004007e1);
} }
TestCase::Pulse => { TestCase::Pulse => {
let mut output_pulsed = pinsa let mut output_pulsed = pinsa.pa0.into_push_pull_output();
.pa0 output_pulsed.pulse_mode(true, PinState::Low);
.into_push_pull_output()
.pulse_mode(true, PinState::Low);
rprintln!("Pulsing high 10 times.."); rprintln!("Pulsing high 10 times..");
output_pulsed.set_low().unwrap(); output_pulsed.set_low().unwrap();
for _ in 0..10 { for _ in 0..10 {
output_pulsed.set_high().unwrap(); output_pulsed.set_high().unwrap();
cortex_m::asm::delay(25_000_000); cortex_m::asm::delay(25_000_000);
} }
let mut output_pulsed = output_pulsed.pulse_mode(true, PinState::High); output_pulsed.pulse_mode(true, PinState::High);
rprintln!("Pulsing low 10 times.."); rprintln!("Pulsing low 10 times..");
for _ in 0..10 { for _ in 0..10 {
output_pulsed.set_low().unwrap(); output_pulsed.set_low().unwrap();

View File

@ -68,10 +68,7 @@ mod app {
Shared { Shared {
rb: StaticRb::default(), rb: StaticRb::default(),
}, },
Local { Local { rx, tx },
rx,
tx,
},
) )
} }

View File

@ -251,10 +251,10 @@ mod app {
} }
let packet_len = packet_len.unwrap(); let packet_len = packet_len.unwrap();
log::info!(target: "TC Handler", "received packet with length {}", packet_len); log::info!(target: "TC Handler", "received packet with length {}", packet_len);
let popped_packet_len = cx.shared.tc_rb.lock(|rb| { let popped_packet_len = cx
rb.buf .shared
.pop_slice(&mut cx.local.tc_buf[0..packet_len]) .tc_rb
}); .lock(|rb| rb.buf.pop_slice(&mut cx.local.tc_buf[0..packet_len]));
assert_eq!(popped_packet_len, packet_len); assert_eq!(popped_packet_len, packet_len);
// Read a telecommand, now handle it. // Read a telecommand, now handle it.
handle_valid_pus_tc(&mut cx); handle_valid_pus_tc(&mut cx);
@ -272,8 +272,7 @@ mod app {
let written_size = tm.write_to_bytes(cx.local.verif_buf).unwrap(); let written_size = tm.write_to_bytes(cx.local.verif_buf).unwrap();
cx.shared.tm_rb.lock(|prod| { cx.shared.tm_rb.lock(|prod| {
prod.sizes.try_push(tm.len_written()).unwrap(); prod.sizes.try_push(tm.len_written()).unwrap();
prod.buf prod.buf.push_slice(&cx.local.verif_buf[0..written_size]);
.push_slice(&cx.local.verif_buf[0..written_size]);
}); });
}; };
let token = cx.local.verif_reporter.add_tc(&pus_tc); let token = cx.local.verif_reporter.add_tc(&pus_tc);

View File

@ -8,9 +8,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [unreleased] ## [unreleased]
## [v0.9.0] 2024-10-07 ## [v0.9.0]
- Deleted some HAL re-exports in the PWM module - Deleted some HAL re-exports in the PWM module
- GPIO API: Interrupt, pulse and filter and `set_datamask` and `clear_datamask` APIs are now
methods which mutable modify the pin instead of consuming and returning it.
- Add `downgrade` method for `Pin` and `upgrade` method for `DynPin` as explicit conversion
methods.
## [v0.8.0] 2024-09-30 ## [v0.8.0] 2024-09-30

View File

@ -172,7 +172,7 @@ 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 { pub(crate) struct DynRegisters {
id: DynPinId, id: DynPinId,
} }
@ -207,7 +207,7 @@ impl DynRegisters {
/// 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.
pub struct DynPin { pub struct DynPin {
regs: DynRegisters, pub(crate) regs: DynRegisters,
mode: DynPinMode, mode: DynPinMode,
} }
@ -220,7 +220,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,
@ -306,7 +306,69 @@ 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)
}
pub(crate) fn irq_enb(
&mut self,
irq_cfg: crate::IrqCfg,
syscfg: Option<&mut va108xx::Sysconfig>,
irqsel: Option<&mut va108xx::Irqsel>,
) {
if let Some(syscfg) = syscfg {
crate::clock::enable_peripheral_clock(syscfg, crate::clock::PeripheralClocks::Irqsel);
}
self.regs.enable_irq();
if let Some(irqsel) = irqsel {
if irq_cfg.route {
match self.regs.id().group {
// Set the correct interrupt number in the IRQSEL register
DynGroup::A => {
irqsel
.porta0(self.regs.id().num as usize)
.write(|w| unsafe { w.bits(irq_cfg.irq as u32) });
}
DynGroup::B => {
irqsel
.portb0(self.regs.id().num as usize)
.write(|w| unsafe { w.bits(irq_cfg.irq as u32) });
}
}
}
}
}
/// 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:
@ -327,15 +389,16 @@ impl DynPin {
/// 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
#[inline]
pub fn pulse_mode( pub fn 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.pulse_mode(enable, default_state);
Ok(self) Ok(())
} }
_ => Err(InvalidPinTypeError), _ => Err(InvalidPinTypeError),
} }
@ -344,48 +407,50 @@ impl DynPin {
/// 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 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.filter_type(filter, clksel);
Ok(self) Ok(())
} }
_ => Err(InvalidPinTypeError), _ => Err(InvalidPinTypeError),
} }
} }
#[inline]
pub fn interrupt_edge( pub fn interrupt_edge(
mut self, &mut self,
edge_type: InterruptEdge, edge_type: InterruptEdge,
irq_cfg: IrqCfg, irq_cfg: IrqCfg,
syscfg: Option<&mut pac::Sysconfig>, syscfg: Option<&mut pac::Sysconfig>,
irqsel: Option<&mut pac::Irqsel>, irqsel: Option<&mut pac::Irqsel>,
) -> Result<Self, InvalidPinTypeError> { ) -> Result<(), InvalidPinTypeError> {
match self.mode { match self.mode {
DynPinMode::Input(_) | DynPinMode::Output(_) => { DynPinMode::Input(_) | DynPinMode::Output(_) => {
self.regs.interrupt_edge(edge_type); self.regs.interrupt_edge(edge_type);
self.irq_enb(irq_cfg, syscfg, irqsel); self.irq_enb(irq_cfg, syscfg, irqsel);
Ok(self) Ok(())
} }
_ => Err(InvalidPinTypeError), _ => Err(InvalidPinTypeError),
} }
} }
#[inline]
pub fn interrupt_level( pub fn interrupt_level(
mut self, &mut self,
level_type: InterruptLevel, level_type: InterruptLevel,
irq_cfg: IrqCfg, irq_cfg: IrqCfg,
syscfg: Option<&mut pac::Sysconfig>, syscfg: Option<&mut pac::Sysconfig>,
irqsel: Option<&mut pac::Irqsel>, irqsel: Option<&mut pac::Irqsel>,
) -> 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.interrupt_level(level_type);
self.irq_enb(irq_cfg, syscfg, irqsel); self.irq_enb(irq_cfg, syscfg, irqsel);
Ok(self) Ok(())
} }
_ => Err(InvalidPinTypeError), _ => Err(InvalidPinTypeError),
} }
@ -438,6 +503,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.id == 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)
}
} }
//================================================================================================== //==================================================================================================
@ -448,10 +528,8 @@ impl<I: PinId, M: PinMode> From<Pin<I, M>> for DynPin {
/// 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) }
} }
} }
@ -465,13 +543,7 @@ impl<I: PinId, M: PinMode> TryFrom<DynPin> for Pin<I, M> {
/// 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)
}
} }
} }
@ -506,10 +578,12 @@ impl embedded_hal::digital::InputPin for DynPin {
} }
impl embedded_hal::digital::StatefulOutputPin for DynPin { impl embedded_hal::digital::StatefulOutputPin for DynPin {
#[inline]
fn is_set_high(&mut self) -> Result<bool, Self::Error> { fn is_set_high(&mut self) -> Result<bool, Self::Error> {
self._is_high() self._is_high()
} }
#[inline]
fn is_set_low(&mut self) -> Result<bool, Self::Error> { fn is_set_low(&mut self) -> Result<bool, Self::Error> {
self._is_low() self._is_low()
} }

View File

@ -26,81 +26,6 @@
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
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,
irq_cfg: crate::IrqCfg,
syscfg: Option<&mut va108xx::Sysconfig>,
irqsel: Option<&mut va108xx::Irqsel>,
) {
if syscfg.is_some() {
crate::clock::enable_peripheral_clock(
syscfg.unwrap(),
crate::clock::PeripheralClocks::Irqsel,
);
}
self.regs.enable_irq();
if let Some(irqsel) = irqsel {
if irq_cfg.route {
match self.regs.id().group {
// Set the correct interrupt number in the IRQSEL register
DynGroup::A => {
irqsel
.porta0(self.regs.id().num as usize)
.write(|w| unsafe { w.bits(irq_cfg.irq as u32) });
}
DynGroup::B => {
irqsel
.portb0(self.regs.id().num as usize)
.write(|w| unsafe { w.bits(irq_cfg.irq as u32) });
}
}
}
}
}
);
};
}
pub mod dynpin; pub mod dynpin;
pub use dynpin::*; pub use dynpin::*;

View File

@ -72,6 +72,7 @@
//! and [`StatefulOutputPin`]. //! and [`StatefulOutputPin`].
use super::dynpin::{DynAlternate, DynGroup, DynInput, DynOutput, DynPinId, DynPinMode}; use super::dynpin::{DynAlternate, DynGroup, DynInput, DynOutput, DynPinId, DynPinMode};
use super::reg::RegisterInterface; use super::reg::RegisterInterface;
use super::DynPin;
use crate::{ use crate::{
pac::{Irqsel, Porta, Portb, Sysconfig}, pac::{Irqsel, Porta, Portb, Sysconfig},
typelevel::Sealed, typelevel::Sealed,
@ -321,8 +322,8 @@ 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
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>, phantom: PhantomData<(I, M)>,
} }
impl<I: PinId, M: PinMode> Pin<I, M> { impl<I: PinId, M: PinMode> Pin<I, M> {
@ -336,8 +337,8 @@ 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, phantom: PhantomData,
} }
} }
@ -347,7 +348,7 @@ impl<I: PinId, M: PinMode> Pin<I, M> {
// 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() }
@ -407,31 +408,78 @@ 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,
irq_cfg: crate::IrqCfg,
syscfg: Option<&mut va108xx::Sysconfig>,
irqsel: Option<&mut va108xx::Irqsel>,
) {
self.inner.irq_enb(irq_cfg, syscfg, irqsel);
}
#[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] #[inline]
pub(crate) fn _toggle_with_toggle_reg(&mut self) { pub(crate) fn _toggle_with_toggle_reg(&mut self) {
self.regs.toggle(); 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()
} }
} }
@ -524,27 +572,25 @@ 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( pub fn interrupt_edge(
mut self, &mut self,
edge_type: InterruptEdge, edge_type: InterruptEdge,
irq_cfg: IrqCfg, irq_cfg: IrqCfg,
syscfg: Option<&mut Sysconfig>, syscfg: Option<&mut Sysconfig>,
irqsel: Option<&mut Irqsel>, irqsel: Option<&mut Irqsel>,
) -> Self { ) {
self.regs.interrupt_edge(edge_type); self.inner.regs.interrupt_edge(edge_type);
self.irq_enb(irq_cfg, syscfg, irqsel); self.irq_enb(irq_cfg, syscfg, irqsel);
self
} }
pub fn interrupt_level( pub fn interrupt_level(
mut self, &mut self,
level_type: InterruptLevel, level_type: InterruptLevel,
irq_cfg: IrqCfg, irq_cfg: IrqCfg,
syscfg: Option<&mut Sysconfig>, syscfg: Option<&mut Sysconfig>,
irqsel: Option<&mut Irqsel>, irqsel: Option<&mut Irqsel>,
) -> Self { ) {
self.regs.interrupt_level(level_type); self.inner.regs.interrupt_level(level_type);
self.irq_enb(irq_cfg, syscfg, irqsel); self.irq_enb(irq_cfg, syscfg, irqsel);
self
} }
} }
@ -556,7 +602,7 @@ impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
/// - 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 delay(self, delay_1: bool, delay_2: bool) -> Self {
self.regs.delay(delay_1, delay_2); self.inner.regs.delay(delay_1, delay_2);
self self
} }
@ -568,42 +614,38 @@ impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
/// 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 pulse_mode(&mut self, enable: bool, default_state: PinState) {
self.regs.pulse_mode(enable, default_state); self.inner.regs.pulse_mode(enable, default_state);
self
} }
pub fn interrupt_edge( pub fn interrupt_edge(
mut self, &mut self,
edge_type: InterruptEdge, edge_type: InterruptEdge,
irq_cfg: IrqCfg, irq_cfg: IrqCfg,
syscfg: Option<&mut Sysconfig>, syscfg: Option<&mut Sysconfig>,
irqsel: Option<&mut Irqsel>, irqsel: Option<&mut Irqsel>,
) -> Self { ) {
self.regs.interrupt_edge(edge_type); self.inner.regs.interrupt_edge(edge_type);
self.irq_enb(irq_cfg, syscfg, irqsel); self.irq_enb(irq_cfg, syscfg, irqsel);
self
} }
pub fn interrupt_level( pub fn interrupt_level(
mut self, &mut self,
level_type: InterruptLevel, level_type: InterruptLevel,
irq_cfg: IrqCfg, irq_cfg: IrqCfg,
syscfg: Option<&mut Sysconfig>, syscfg: Option<&mut Sysconfig>,
irqsel: Option<&mut Irqsel>, irqsel: Option<&mut Irqsel>,
) -> Self { ) {
self.regs.interrupt_level(level_type); self.inner.regs.interrupt_level(level_type);
self.irq_enb(irq_cfg, syscfg, irqsel); self.irq_enb(irq_cfg, syscfg, irqsel);
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 filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
self.regs.filter_type(filter, clksel); self.inner.regs.filter_type(filter, clksel);
self
} }
} }
@ -679,47 +721,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
//================================================================================================== //==================================================================================================

View File

@ -293,7 +293,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 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 {
@ -331,7 +331,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 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 {