GPIO refactoring and API improvements
This commit is contained in:
parent
b2d17e10ed
commit
da1f2902b2
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -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
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -68,10 +68,7 @@ mod app {
|
|||||||
Shared {
|
Shared {
|
||||||
rb: StaticRb::default(),
|
rb: StaticRb::default(),
|
||||||
},
|
},
|
||||||
Local {
|
Local { rx, tx },
|
||||||
rx,
|
|
||||||
tx,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
@ -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::*;
|
||||||
|
|
||||||
|
@ -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
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
@ -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 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user