chaos
This commit is contained in:
@ -19,7 +19,10 @@ use portable_atomic::AtomicBool;
|
||||
use crate::{InterruptConfig, NUM_PORT_A, NUM_PORT_B};
|
||||
|
||||
pub use super::ll::InterruptEdge;
|
||||
use super::{Input, Pin, PinIdProvider, Port, ll::PinId};
|
||||
use super::{
|
||||
Input, Port,
|
||||
ll::{LowLevelGpio, PinId},
|
||||
};
|
||||
|
||||
static WAKERS_FOR_PORT_A: [AtomicWaker; NUM_PORT_A] = [const { AtomicWaker::new() }; NUM_PORT_A];
|
||||
static WAKERS_FOR_PORT_B: [AtomicWaker; NUM_PORT_B] = [const { AtomicWaker::new() }; NUM_PORT_B];
|
||||
@ -98,15 +101,14 @@ impl InputPinFuture {
|
||||
edge: InterruptEdge,
|
||||
) -> Self {
|
||||
let (waker_group, edge_detection_group) =
|
||||
Self::pin_group_to_waker_and_edge_detection_group(pin.port());
|
||||
edge_detection_group[pin.offset() as usize]
|
||||
Self::pin_group_to_waker_and_edge_detection_group(pin.id().port());
|
||||
edge_detection_group[pin.id().offset() as usize]
|
||||
.store(false, core::sync::atomic::Ordering::Relaxed);
|
||||
pin.configure_edge_interrupt(edge).unwrap();
|
||||
pin.configure_edge_interrupt(edge);
|
||||
#[cfg(feature = "vor1x")]
|
||||
pin.enable_interrupt(InterruptConfig::new(irq, true, true));
|
||||
Self {
|
||||
port: pin.port(),
|
||||
offset: pin.offset(),
|
||||
id: pin.id(),
|
||||
waker_group,
|
||||
edge_detection_group,
|
||||
}
|
||||
@ -115,8 +117,8 @@ impl InputPinFuture {
|
||||
|
||||
impl Drop for InputPinFuture {
|
||||
fn drop(&mut self) {
|
||||
// The API ensures that we actually own the pin, so stealing it here is okay.
|
||||
unsafe { DynPin::steal(self.pin_id) }.disable_interrupt(false);
|
||||
let mut ll = LowLevelGpio::new(self.id);
|
||||
ll.disable_interrupt(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,7 +128,7 @@ impl Future for InputPinFuture {
|
||||
self: core::pin::Pin<&mut Self>,
|
||||
cx: &mut core::task::Context<'_>,
|
||||
) -> core::task::Poll<Self::Output> {
|
||||
let idx = self.pin_id.num() as usize;
|
||||
let idx = self.id.offset() 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(());
|
||||
@ -159,9 +161,8 @@ impl InputPinAsync {
|
||||
pub async fn wait_for_high(&mut self) {
|
||||
// Unwrap okay, checked pin in constructor.
|
||||
let fut =
|
||||
InputPinFuture::new_with_input_pin(&mut self.pin, self.irq, InterruptEdge::LowToHigh)
|
||||
.unwrap();
|
||||
if self.pin.is_high().unwrap() {
|
||||
InputPinFuture::new_with_input_pin(&mut self.pin, self.irq, InterruptEdge::LowToHigh);
|
||||
if self.pin.is_high() {
|
||||
return;
|
||||
}
|
||||
fut.await;
|
||||
@ -173,9 +174,8 @@ impl InputPinAsync {
|
||||
pub async fn wait_for_low(&mut self) {
|
||||
// Unwrap okay, checked pin in constructor.
|
||||
let fut =
|
||||
InputPinFuture::new_with_input_pin(&mut self.pin, self.irq, InterruptEdge::HighToLow)
|
||||
.unwrap();
|
||||
if self.pin.is_low().unwrap() {
|
||||
InputPinFuture::new_with_input_pin(&mut self.pin, self.irq, InterruptEdge::HighToLow);
|
||||
if self.pin.is_low() {
|
||||
return;
|
||||
}
|
||||
fut.await;
|
||||
@ -184,25 +184,19 @@ impl InputPinAsync {
|
||||
/// 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_input_pin(&mut self.pin, self.irq, InterruptEdge::HighToLow)
|
||||
.unwrap()
|
||||
.await;
|
||||
InputPinFuture::new_with_input_pin(&mut self.pin, self.irq, InterruptEdge::HighToLow).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_input_pin(&mut self.pin, self.irq, InterruptEdge::LowToHigh)
|
||||
.unwrap()
|
||||
.await;
|
||||
InputPinFuture::new_with_input_pin(&mut self.pin, self.irq, InterruptEdge::LowToHigh).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_input_pin(&mut self.pin, self.irq, InterruptEdge::BothEdges)
|
||||
.unwrap()
|
||||
.await;
|
||||
InputPinFuture::new_with_input_pin(&mut self.pin, self.irq, InterruptEdge::BothEdges).await;
|
||||
}
|
||||
|
||||
pub fn release(self) -> Input {
|
||||
@ -240,93 +234,3 @@ impl Wait for InputPinAsync {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InputPinAsync<I: PinIdProvider, C: InputConfig> {
|
||||
pin: Pin<I, pin::Input<C>>,
|
||||
irq: pac::Interrupt,
|
||||
}
|
||||
|
||||
impl<I: PinIdProvider, C: InputConfig> InputPinAsync<I, C> {
|
||||
/// 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<I, pin::Input<C>>, irq: pac::Interrupt) -> Self {
|
||||
Self { pin, irq }
|
||||
}
|
||||
|
||||
/// Asynchronously wait until the pin is high.
|
||||
///
|
||||
/// This returns immediately if the pin is already high.
|
||||
pub async fn wait_for_high(&mut self) {
|
||||
let fut = InputPinFuture::new_with_pin(&mut self.pin, self.irq, InterruptEdge::LowToHigh);
|
||||
if self.pin.is_high() {
|
||||
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, self.irq, InterruptEdge::HighToLow);
|
||||
if self.pin.is_low() {
|
||||
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, self.irq, InterruptEdge::HighToLow).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, self.irq, InterruptEdge::LowToHigh).await;
|
||||
}
|
||||
|
||||
/// Asynchronously wait until the pin sees any edge (either rising or falling).
|
||||
pub async fn wait_for_any_edge(&mut self) {
|
||||
InputPinFuture::new_with_pin(&mut self.pin, self.irq, InterruptEdge::BothEdges).await;
|
||||
}
|
||||
|
||||
pub fn release(self) -> Pin<I, pin::Input<C>> {
|
||||
self.pin
|
||||
}
|
||||
}
|
||||
impl<I: PinIdProvider, C: InputConfig> embedded_hal::digital::ErrorType for InputPinAsync<I, C> {
|
||||
type Error = core::convert::Infallible;
|
||||
}
|
||||
|
||||
impl<I: PinIdProvider, C: InputConfig> Wait for InputPinAsync<I, C> {
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
pub use embedded_hal::digital::PinState;
|
||||
|
||||
#[cfg(feature = "vor1x")]
|
||||
use crate::{PeripheralSelect, sysconfig::enable_peripheral_clock};
|
||||
|
||||
pub use crate::InvalidOffsetError;
|
||||
pub use crate::Port;
|
||||
pub use crate::ioconfig::regs::Pull;
|
||||
@ -20,7 +23,7 @@ pub enum InterruptLevel {
|
||||
High = 1,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct PinId {
|
||||
port: Port,
|
||||
@ -40,7 +43,7 @@ impl PinId {
|
||||
}
|
||||
|
||||
pub const fn offset(&self) -> usize {
|
||||
self.port
|
||||
self.offset
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,10 +67,22 @@ impl LowLevelGpio {
|
||||
self.id
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn port(&self) -> Port {
|
||||
self.id.port()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn offset(&self) -> usize {
|
||||
self.id.offset()
|
||||
}
|
||||
|
||||
pub fn configure_as_input_floating(&mut self) {
|
||||
unsafe {
|
||||
self.ioconfig
|
||||
.modify_pin_config_unchecked(self.port, self.offset, |mut config| {
|
||||
self.ioconfig.modify_pin_config_unchecked(
|
||||
self.id.port(),
|
||||
self.id.offset(),
|
||||
|mut config| {
|
||||
config.set_funsel(FunSel::Sel0);
|
||||
config.set_io_disable(false);
|
||||
config.set_invert_input(false);
|
||||
@ -77,18 +92,21 @@ impl LowLevelGpio {
|
||||
config.set_invert_output(false);
|
||||
config.set_input_enable_when_output(false);
|
||||
config
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
self.gpio.modify_dir(|mut dir| {
|
||||
dir &= !self.mask_32();
|
||||
dir &= !(1 << self.id.offset());
|
||||
dir
|
||||
});
|
||||
}
|
||||
|
||||
pub fn configure_as_input_with_pull(&mut self, pull: Pull) {
|
||||
unsafe {
|
||||
self.ioconfig
|
||||
.modify_pin_config_unchecked(self.port, self.offset, |mut config| {
|
||||
self.ioconfig.modify_pin_config_unchecked(
|
||||
self.id.port(),
|
||||
self.id.offset(),
|
||||
|mut config| {
|
||||
config.set_funsel(FunSel::Sel0);
|
||||
config.set_io_disable(false);
|
||||
config.set_invert_input(false);
|
||||
@ -99,18 +117,21 @@ impl LowLevelGpio {
|
||||
config.set_invert_output(false);
|
||||
config.set_input_enable_when_output(false);
|
||||
config
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
self.gpio.modify_dir(|mut dir| {
|
||||
dir &= !self.mask_32();
|
||||
dir &= !(1 << self.id.offset());
|
||||
dir
|
||||
});
|
||||
}
|
||||
|
||||
pub fn configure_as_output_push_pull(&mut self, init_level: PinState) {
|
||||
unsafe {
|
||||
self.ioconfig
|
||||
.modify_pin_config_unchecked(self.port, self.offset, |mut config| {
|
||||
self.ioconfig.modify_pin_config_unchecked(
|
||||
self.id.port(),
|
||||
self.id.offset(),
|
||||
|mut config| {
|
||||
config.set_funsel(FunSel::Sel0);
|
||||
config.set_io_disable(false);
|
||||
config.set_invert_input(false);
|
||||
@ -120,22 +141,25 @@ impl LowLevelGpio {
|
||||
config.set_invert_output(false);
|
||||
config.set_input_enable_when_output(true);
|
||||
config
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
match init_level {
|
||||
PinState::Low => self.gpio.write_clr_out(1 << self.offset),
|
||||
PinState::High => self.gpio.write_set_out(1 << self.offset),
|
||||
PinState::Low => self.gpio.write_clr_out(self.mask_32()),
|
||||
PinState::High => self.gpio.write_set_out(self.mask_32()),
|
||||
}
|
||||
self.gpio.modify_dir(|mut dir| {
|
||||
dir |= self.mask_32();
|
||||
dir |= 1 << self.id.offset();
|
||||
dir
|
||||
});
|
||||
}
|
||||
|
||||
pub fn configure_as_output_open_drain(&mut self, init_level: PinState) {
|
||||
unsafe {
|
||||
self.ioconfig
|
||||
.modify_pin_config_unchecked(self.port, self.offset, |mut config| {
|
||||
self.ioconfig.modify_pin_config_unchecked(
|
||||
self.id.port(),
|
||||
self.id.offset(),
|
||||
|mut config| {
|
||||
config.set_funsel(FunSel::Sel0);
|
||||
config.set_io_disable(false);
|
||||
config.set_invert_input(false);
|
||||
@ -146,22 +170,26 @@ impl LowLevelGpio {
|
||||
config.set_invert_output(false);
|
||||
config.set_input_enable_when_output(true);
|
||||
config
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
let mask32 = self.mask_32();
|
||||
match init_level {
|
||||
PinState::Low => self.gpio.write_clr_out(1 << self.offset),
|
||||
PinState::High => self.gpio.write_set_out(1 << self.offset),
|
||||
PinState::Low => self.gpio.write_clr_out(mask32),
|
||||
PinState::High => self.gpio.write_set_out(mask32),
|
||||
}
|
||||
self.gpio.modify_dir(|mut dir| {
|
||||
dir |= 1 << self.offset;
|
||||
dir |= mask32;
|
||||
dir
|
||||
});
|
||||
}
|
||||
|
||||
pub fn configure_as_peripheral_pin(&mut self, fun_sel: FunSel, pull: Option<Pull>) {
|
||||
unsafe {
|
||||
self.ioconfig
|
||||
.modify_pin_config_unchecked(self.port, self.offset, |mut config| {
|
||||
self.ioconfig.modify_pin_config_unchecked(
|
||||
self.id.port(),
|
||||
self.id.offset(),
|
||||
|mut config| {
|
||||
config.set_funsel(fun_sel);
|
||||
config.set_io_disable(false);
|
||||
config.set_invert_input(false);
|
||||
@ -170,13 +198,14 @@ impl LowLevelGpio {
|
||||
config.set_pull_dir(pull.unwrap_or(Pull::Up));
|
||||
config.set_invert_output(false);
|
||||
config
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_high(&self) -> bool {
|
||||
(self.gpio.read_data_in() >> self.offset) & 1 == 1
|
||||
(self.gpio.read_data_in() >> self.offset()) & 1 == 1
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -196,7 +225,7 @@ impl LowLevelGpio {
|
||||
|
||||
#[inline]
|
||||
pub fn is_set_high(&self) -> bool {
|
||||
(self.gpio.read_data_out() >> self.offset) & 1 == 1
|
||||
(self.gpio.read_data_out() >> self.offset()) & 1 == 1
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -218,7 +247,19 @@ impl LowLevelGpio {
|
||||
unsafe { crate::enable_nvic_interrupt(irq_cfg.id) };
|
||||
}
|
||||
self.gpio.modify_irq_enb(|mut value| {
|
||||
value |= self.mask_32();
|
||||
value |= 1 << self.id.offset;
|
||||
value
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "vor1x")]
|
||||
pub fn disable_interrupt(&mut self, reset_irqsel: bool) {
|
||||
if reset_irqsel {
|
||||
self.reset_irqsel();
|
||||
}
|
||||
// We only manipulate our own bit.
|
||||
self.gpio.modify_irq_enb(|mut value| {
|
||||
value &= !(1 << self.id.offset);
|
||||
value
|
||||
});
|
||||
}
|
||||
@ -227,36 +268,75 @@ impl LowLevelGpio {
|
||||
/// When using edge mode, it is possible to generate interrupts on both edges as well
|
||||
#[inline]
|
||||
pub fn configure_edge_interrupt(&mut self, edge_type: InterruptEdge) {
|
||||
unsafe {
|
||||
self.gpio.modify_irq_sen(|mut value| {
|
||||
value &= !self.mask_32();
|
||||
value
|
||||
});
|
||||
match edge_type {
|
||||
InterruptEdge::HighToLow => {
|
||||
self.gpio.modify_irq_evt(|mut value| {
|
||||
value &= !self.mask_32();
|
||||
value
|
||||
});
|
||||
}
|
||||
InterruptEdge::LowToHigh => {
|
||||
self.gpio.modify_irq_evt(|mut value| {
|
||||
value |= self.mask_32();
|
||||
value
|
||||
});
|
||||
}
|
||||
InterruptEdge::BothEdges => {
|
||||
self.gpio.modify_irq_edge(|mut value| {
|
||||
value |= self.mask_32();
|
||||
value
|
||||
});
|
||||
}
|
||||
let mask32 = self.mask_32();
|
||||
self.gpio.modify_irq_sen(|mut value| {
|
||||
value &= !mask32;
|
||||
value
|
||||
});
|
||||
match edge_type {
|
||||
InterruptEdge::HighToLow => {
|
||||
self.gpio.modify_irq_evt(|mut value| {
|
||||
value &= !mask32;
|
||||
value
|
||||
});
|
||||
}
|
||||
InterruptEdge::LowToHigh => {
|
||||
self.gpio.modify_irq_evt(|mut value| {
|
||||
value |= mask32;
|
||||
value
|
||||
});
|
||||
}
|
||||
InterruptEdge::BothEdges => {
|
||||
self.gpio.modify_irq_edge(|mut value| {
|
||||
value |= mask32;
|
||||
value
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "vor1x")]
|
||||
/// Configure the IRQSEL peripheral for this particular pin with the given interrupt ID.
|
||||
pub fn configure_irqsel(&mut self, id: va108xx::Interrupt) {
|
||||
let irqsel = unsafe { va108xx::Irqsel::steal() };
|
||||
enable_peripheral_clock(PeripheralSelect::Irqsel);
|
||||
match self.id().port() {
|
||||
// Set the correct interrupt number in the IRQSEL register
|
||||
super::Port::A => {
|
||||
irqsel
|
||||
.porta0(self.id().offset() as usize)
|
||||
.write(|w| unsafe { w.bits(id as u32) });
|
||||
}
|
||||
super::Port::B => {
|
||||
irqsel
|
||||
.portb0(self.id().offset() as usize)
|
||||
.write(|w| unsafe { w.bits(id as u32) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "vor1x")]
|
||||
/// Reset the IRQSEL peripheral value for this particular pin.
|
||||
pub fn reset_irqsel(&mut self) {
|
||||
let irqsel = unsafe { va108xx::Irqsel::steal() };
|
||||
enable_peripheral_clock(PeripheralSelect::Irqsel);
|
||||
match self.id().port() {
|
||||
// Set the correct interrupt number in the IRQSEL register
|
||||
super::Port::A => {
|
||||
irqsel
|
||||
.porta0(self.id().offset() as usize)
|
||||
.write(|w| unsafe { w.bits(u32::MAX) });
|
||||
}
|
||||
super::Port::B => {
|
||||
irqsel
|
||||
.portb0(self.id().offset() as usize)
|
||||
.write(|w| unsafe { w.bits(u32::MAX) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub const fn mask_32(&self) -> u32 {
|
||||
1 << self.offset
|
||||
1 << self.id.offset()
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use core::convert::Infallible;
|
||||
|
||||
pub use embedded_hal::digital::PinState;
|
||||
pub use ll::PinId;
|
||||
pub use ll::{Port, Pull};
|
||||
|
||||
use crate::ioconfig::regs::FunSel;
|
||||
@ -9,15 +10,15 @@ pub mod asynch;
|
||||
pub mod ll;
|
||||
pub mod regs;
|
||||
|
||||
pub trait PinIdProvider {
|
||||
pub trait PinMarker {
|
||||
const ID: ll::PinId;
|
||||
}
|
||||
|
||||
pub struct Pin<I: PinIdProvider> {
|
||||
pub struct Pin<I: PinMarker> {
|
||||
phantom: core::marker::PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<I: PinIdProvider> Pin<I> {
|
||||
impl<I: PinMarker> Pin<I> {
|
||||
#[allow(clippy::new_without_default)]
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
@ -29,7 +30,7 @@ impl<I: PinIdProvider> Pin<I> {
|
||||
pub struct Output(ll::LowLevelGpio);
|
||||
|
||||
impl Output {
|
||||
pub fn new<I: PinIdProvider>(_pin: Pin<I>, init_level: PinState) -> Self {
|
||||
pub fn new<I: PinMarker>(_pin: Pin<I>, init_level: PinState) -> Self {
|
||||
let mut ll = ll::LowLevelGpio::new(I::ID);
|
||||
ll.configure_as_output_push_pull(init_level);
|
||||
Output(ll)
|
||||
@ -101,35 +102,43 @@ impl embedded_hal::digital::StatefulOutputPin for Output {
|
||||
pub struct Input(ll::LowLevelGpio);
|
||||
|
||||
impl Input {
|
||||
pub fn new_floating<I: PinIdProvider>(_pin: Pin<I>) -> Self {
|
||||
pub fn new_floating<I: PinMarker>(_pin: Pin<I>) -> Self {
|
||||
let mut ll = ll::LowLevelGpio::new(I::ID);
|
||||
ll.configure_as_input_floating();
|
||||
Input(ll)
|
||||
}
|
||||
|
||||
pub fn new_with_pull<I: PinIdProvider>(_pin: Pin<I>, pull: Pull) -> Self {
|
||||
pub fn new_with_pull<I: PinMarker>(_pin: Pin<I>, pull: Pull) -> Self {
|
||||
let mut ll = ll::LowLevelGpio::new(I::ID);
|
||||
ll.configure_as_input_with_pull(pull);
|
||||
Input(ll)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn port(&self) -> Port {
|
||||
self.0.port()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn offset(&self) -> usize {
|
||||
self.0.offset()
|
||||
pub fn id(&self) -> PinId {
|
||||
self.0.id()
|
||||
}
|
||||
|
||||
#[cfg(feature = "vor1x")]
|
||||
#[inline]
|
||||
pub fn enable_interrupt(&mut self, irq_cfg: crate::InterruptConfig) {
|
||||
self.0.enable_interrupt(irq_cfg);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn configure_edge_interrupt(&mut self, edge: ll::InterruptEdge) {
|
||||
self.0.configure_edge_interrupt(edge);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_low(&self) -> bool {
|
||||
self.0.is_low()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_high(&self) -> bool {
|
||||
self.0.is_high()
|
||||
}
|
||||
}
|
||||
|
||||
impl embedded_hal::digital::ErrorType for Input {
|
||||
@ -169,7 +178,7 @@ pub struct Flex {
|
||||
}
|
||||
|
||||
impl Flex {
|
||||
pub fn new<I: PinIdProvider>(_pin: Pin<I>) -> Self {
|
||||
pub fn new<I: PinMarker>(_pin: Pin<I>) -> Self {
|
||||
let mut ll = ll::LowLevelGpio::new(I::ID);
|
||||
ll.configure_as_input_floating();
|
||||
Flex {
|
||||
@ -278,7 +287,7 @@ pub struct IoPeriphPin {
|
||||
}
|
||||
|
||||
impl IoPeriphPin {
|
||||
pub fn new<I: PinIdProvider>(_pin: Pin<I>, fun_sel: FunSel, pull: Option<Pull>) -> Self {
|
||||
pub fn new<I: PinMarker>(_pin: Pin<I>, fun_sel: FunSel, pull: Option<Pull>) -> Self {
|
||||
let mut ll = ll::LowLevelGpio::new(I::ID);
|
||||
ll.configure_as_peripheral_pin(fun_sel, pull);
|
||||
IoPeriphPin { ll, fun_sel }
|
||||
|
@ -167,7 +167,7 @@ impl MmioIoConfig<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modify_pin_config<F: FnMut(Config) -> Config>(
|
||||
pub fn modify_pin_config<F: FnOnce(Config) -> Config>(
|
||||
&mut self,
|
||||
port: crate::Port,
|
||||
offset: usize,
|
||||
@ -185,7 +185,7 @@ impl MmioIoConfig<'_> {
|
||||
/// # Safety
|
||||
///
|
||||
/// Calling this function with an invalid offset can lead to undefined behaviour.
|
||||
pub unsafe fn modify_pin_config_unchecked<F: FnMut(Config) -> Config>(
|
||||
pub unsafe fn modify_pin_config_unchecked<F: FnOnce(Config) -> Config>(
|
||||
&mut self,
|
||||
port: crate::Port,
|
||||
offset: usize,
|
||||
|
@ -1,12 +1,32 @@
|
||||
#![no_std]
|
||||
pub mod gpio;
|
||||
pub mod ioconfig;
|
||||
pub mod sysconfig;
|
||||
|
||||
#[cfg(not(feature = "_family-selected"))]
|
||||
compile_error!("no Vorago CPU family was select. Choices: vor1x or vor4x");
|
||||
|
||||
pub use ioconfig::regs::FunSel;
|
||||
|
||||
#[cfg(feature = "vor1x")]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum PeripheralSelect {
|
||||
PortA = 0,
|
||||
PortB = 1,
|
||||
Spi0 = 4,
|
||||
Spi1 = 5,
|
||||
Spi2 = 6,
|
||||
Uart0 = 8,
|
||||
Uart1 = 9,
|
||||
I2c0 = 16,
|
||||
I2c1 = 17,
|
||||
Irqsel = 21,
|
||||
Ioconfig = 22,
|
||||
Utility = 23,
|
||||
Gpio = 24,
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "vor1x")] {
|
||||
/// Number of GPIO ports and IOCONFIG registers for PORT A
|
||||
@ -43,7 +63,7 @@ pub enum Port {
|
||||
}
|
||||
|
||||
impl Port {
|
||||
pub fn max_offset(&self) -> usize {
|
||||
pub const fn max_offset(&self) -> usize {
|
||||
match self {
|
||||
Port::A => NUM_PORT_A,
|
||||
Port::B => NUM_PORT_B,
|
||||
@ -60,7 +80,7 @@ impl Port {
|
||||
///
|
||||
/// Circumvents ownership and safety guarantees by the HAL.
|
||||
pub unsafe fn steal_gpio(&self) -> gpio::regs::MmioGpio<'static> {
|
||||
gpio::regs::Gpio::new_mmio(self)
|
||||
gpio::regs::Gpio::new_mmio(*self)
|
||||
}
|
||||
}
|
||||
|
||||
|
17
vorago-shared-periphs/src/sysconfig.rs
Normal file
17
vorago-shared-periphs/src/sysconfig.rs
Normal file
@ -0,0 +1,17 @@
|
||||
#[cfg(feature = "vor1x")]
|
||||
#[inline]
|
||||
pub fn enable_peripheral_clock(clock: crate::PeripheralSelect) {
|
||||
let syscfg = unsafe { va108xx::Sysconfig::steal() };
|
||||
syscfg
|
||||
.peripheral_clk_enable()
|
||||
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << clock as u8)) });
|
||||
}
|
||||
|
||||
#[cfg(feature = "vor1x")]
|
||||
#[inline]
|
||||
pub fn disable_peripheral_clock(clock: crate::PeripheralSelect) {
|
||||
let syscfg = unsafe { va108xx::Sysconfig::steal() };
|
||||
syscfg
|
||||
.peripheral_clk_enable()
|
||||
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << clock as u8)) });
|
||||
}
|
Reference in New Issue
Block a user