move to updated API

This commit is contained in:
2025-04-16 14:35:57 +02:00
parent dfe34e965f
commit 121b467fb9
49 changed files with 751 additions and 986 deletions

View File

@ -102,8 +102,7 @@ impl InputPinFuture {
) -> Self {
let (waker_group, edge_detection_group) =
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);
edge_detection_group[pin.id().offset()].store(false, core::sync::atomic::Ordering::Relaxed);
pin.configure_edge_interrupt(edge);
#[cfg(feature = "vor1x")]
pin.enable_interrupt(InterruptConfig::new(irq, true, true));
@ -128,7 +127,7 @@ impl Future for InputPinFuture {
self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> core::task::Poll<Self::Output> {
let idx = self.id.offset() as usize;
let idx = self.id.offset();
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(());

View File

@ -1,5 +1,7 @@
pub use embedded_hal::digital::PinState;
use crate::ioconfig::FilterClkSel;
use crate::ioconfig::FilterType;
#[cfg(feature = "vor1x")]
use crate::{PeripheralSelect, sysconfig::enable_peripheral_clock};
@ -27,15 +29,28 @@ pub enum InterruptLevel {
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PinId {
port: Port,
offset: usize,
offset: u8,
}
impl PinId {
pub const fn new_unchecked(port: Port, offset: usize) -> Self {
if offset >= port.max_offset() {
panic!("Pin ID construction: offset is out of range");
}
PinId {
port,
offset: offset as u8,
}
}
pub const fn new(port: Port, offset: usize) -> Result<Self, InvalidOffsetError> {
if offset >= port.max_offset() {
return Err(InvalidOffsetError { offset, port });
}
Ok(PinId { port, offset })
Ok(PinId {
port,
offset: offset as u8,
})
}
pub const fn port(&self) -> Port {
@ -43,7 +58,7 @@ impl PinId {
}
pub const fn offset(&self) -> usize {
self.offset
self.offset as usize
}
}
@ -53,6 +68,15 @@ pub struct LowLevelGpio {
id: PinId,
}
impl core::fmt::Debug for LowLevelGpio {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("LowLevelGpio")
.field("gpio", &self.gpio.port())
.field("id", &self.id)
.finish()
}
}
impl LowLevelGpio {
pub fn new(id: PinId) -> Self {
LowLevelGpio {
@ -78,23 +102,17 @@ impl LowLevelGpio {
}
pub fn configure_as_input_floating(&mut self) {
unsafe {
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);
config.set_open_drain(false);
config.set_pull_enable(false);
config.set_pull_when_output_active(false);
config.set_invert_output(false);
config.set_input_enable_when_output(false);
config
},
);
}
self.ioconfig.modify_pin_config(self.id, |mut config| {
config.set_funsel(FunSel::Sel0);
config.set_io_disable(false);
config.set_invert_input(false);
config.set_open_drain(false);
config.set_pull_enable(false);
config.set_pull_when_output_active(false);
config.set_invert_output(false);
config.set_input_enable_when_output(false);
config
});
self.gpio.modify_dir(|mut dir| {
dir &= !(1 << self.id.offset());
dir
@ -102,24 +120,18 @@ impl LowLevelGpio {
}
pub fn configure_as_input_with_pull(&mut self, pull: Pull) {
unsafe {
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);
config.set_open_drain(false);
config.set_pull_enable(true);
config.set_pull_dir(pull);
config.set_pull_when_output_active(false);
config.set_invert_output(false);
config.set_input_enable_when_output(false);
config
},
);
}
self.ioconfig.modify_pin_config(self.id, |mut config| {
config.set_funsel(FunSel::Sel0);
config.set_io_disable(false);
config.set_invert_input(false);
config.set_open_drain(false);
config.set_pull_enable(true);
config.set_pull_dir(pull);
config.set_pull_when_output_active(false);
config.set_invert_output(false);
config.set_input_enable_when_output(false);
config
});
self.gpio.modify_dir(|mut dir| {
dir &= !(1 << self.id.offset());
dir
@ -127,23 +139,17 @@ impl LowLevelGpio {
}
pub fn configure_as_output_push_pull(&mut self, init_level: PinState) {
unsafe {
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);
config.set_open_drain(false);
config.set_pull_enable(false);
config.set_pull_when_output_active(false);
config.set_invert_output(false);
config.set_input_enable_when_output(true);
config
},
);
}
self.ioconfig.modify_pin_config(self.id, |mut config| {
config.set_funsel(FunSel::Sel0);
config.set_io_disable(false);
config.set_invert_input(false);
config.set_open_drain(false);
config.set_pull_enable(false);
config.set_pull_when_output_active(false);
config.set_invert_output(false);
config.set_input_enable_when_output(true);
config
});
match init_level {
PinState::Low => self.gpio.write_clr_out(self.mask_32()),
PinState::High => self.gpio.write_set_out(self.mask_32()),
@ -155,24 +161,18 @@ impl LowLevelGpio {
}
pub fn configure_as_output_open_drain(&mut self, init_level: PinState) {
unsafe {
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);
config.set_open_drain(true);
config.set_pull_enable(true);
config.set_pull_dir(Pull::Up);
config.set_pull_when_output_active(false);
config.set_invert_output(false);
config.set_input_enable_when_output(true);
config
},
);
}
self.ioconfig.modify_pin_config(self.id, |mut config| {
config.set_funsel(FunSel::Sel0);
config.set_io_disable(false);
config.set_invert_input(false);
config.set_open_drain(true);
config.set_pull_enable(true);
config.set_pull_dir(Pull::Up);
config.set_pull_when_output_active(false);
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(mask32),
@ -185,22 +185,16 @@ impl LowLevelGpio {
}
pub fn configure_as_peripheral_pin(&mut self, fun_sel: FunSel, pull: Option<Pull>) {
unsafe {
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);
config.set_open_drain(false);
config.set_pull_enable(pull.is_some());
config.set_pull_dir(pull.unwrap_or(Pull::Up));
config.set_invert_output(false);
config
},
);
}
self.ioconfig.modify_pin_config(self.id, |mut config| {
config.set_funsel(fun_sel);
config.set_io_disable(false);
config.set_invert_input(false);
config.set_open_drain(false);
config.set_pull_enable(pull.is_some());
config.set_pull_dir(pull.unwrap_or(Pull::Up));
config.set_invert_output(false);
config
});
}
#[inline]
@ -295,6 +289,79 @@ impl LowLevelGpio {
}
}
/// Configure which edge or level type triggers an interrupt
#[inline]
pub fn configure_level_interrupt(&mut self, level: InterruptLevel) {
let mask32 = self.mask_32();
self.gpio.modify_irq_sen(|mut value| {
value |= mask32;
value
});
if level == InterruptLevel::Low {
self.gpio.modify_irq_evt(|mut value| {
value &= !mask32;
value
});
} else {
self.gpio.modify_irq_evt(|mut value| {
value |= mask32;
value
});
}
}
/// Only useful for input pins
#[inline]
pub fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
self.ioconfig.modify_pin_config(self.id, |mut config| {
config.set_filter_type(filter);
config.set_filter_clk_sel(clksel);
config
});
}
/// Only useful for output pins.
#[inline]
pub fn configure_pulse_mode(&mut self, enable: bool, default_state: PinState) {
self.gpio.modify_pulse(|mut value| {
if enable {
value |= 1 << self.id.offset;
} else {
value &= !(1 << self.id.offset);
}
value
});
self.gpio.modify_pulsebase(|mut value| {
if default_state == PinState::High {
value |= 1 << self.id.offset;
} else {
value &= !(1 << self.id.offset);
}
value
});
}
/// Only useful for output pins
#[inline]
pub fn configure_delay(&mut self, delay_1: bool, delay_2: bool) {
self.gpio.modify_delay1(|mut value| {
if delay_1 {
value |= 1 << self.id.offset;
} else {
value &= !(1 << self.id.offset);
}
value
});
self.gpio.modify_delay2(|mut value| {
if delay_2 {
value |= 1 << self.id.offset;
} else {
value &= !(1 << self.id.offset);
}
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) {
@ -304,12 +371,12 @@ impl LowLevelGpio {
// Set the correct interrupt number in the IRQSEL register
super::Port::A => {
irqsel
.porta0(self.id().offset() as usize)
.porta0(self.id().offset())
.write(|w| unsafe { w.bits(id as u32) });
}
super::Port::B => {
irqsel
.portb0(self.id().offset() as usize)
.portb0(self.id().offset())
.write(|w| unsafe { w.bits(id as u32) });
}
}
@ -324,12 +391,12 @@ impl LowLevelGpio {
// Set the correct interrupt number in the IRQSEL register
super::Port::A => {
irqsel
.porta0(self.id().offset() as usize)
.porta0(self.id().offset())
.write(|w| unsafe { w.bits(u32::MAX) });
}
super::Port::B => {
irqsel
.portb0(self.id().offset() as usize)
.portb0(self.id().offset())
.write(|w| unsafe { w.bits(u32::MAX) });
}
}

View File

@ -1,24 +1,22 @@
use core::convert::Infallible;
pub use crate::ioconfig::{FilterClkSel, FilterType, regs::FunSel};
pub use embedded_hal::digital::PinState;
pub use ll::PinId;
pub use ll::{Port, Pull};
use crate::ioconfig::regs::FunSel;
pub use ll::{InterruptEdge, InterruptLevel, PinId, Port, Pull};
pub mod asynch;
pub mod ll;
pub mod regs;
pub trait PinMarker {
pub trait PinIdProvider {
const ID: ll::PinId;
}
pub struct Pin<I: PinMarker> {
pub struct Pin<I: PinIdProvider> {
phantom: core::marker::PhantomData<I>,
}
impl<I: PinMarker> Pin<I> {
impl<I: PinIdProvider> Pin<I> {
#[allow(clippy::new_without_default)]
pub const fn new() -> Self {
Self {
@ -27,10 +25,11 @@ impl<I: PinMarker> Pin<I> {
}
}
#[derive(Debug)]
pub struct Output(ll::LowLevelGpio);
impl Output {
pub fn new<I: PinMarker>(_pin: Pin<I>, init_level: PinState) -> Self {
pub fn new<I: PinIdProvider>(_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)
@ -65,6 +64,12 @@ impl Output {
pub fn is_set_low(&self) -> bool {
self.0.is_set_low()
}
/// Toggle pin output with dedicated HW feature.
#[inline]
pub fn toggle(&mut self) {
self.0.toggle();
}
}
impl embedded_hal::digital::ErrorType for Output {
@ -99,16 +104,17 @@ impl embedded_hal::digital::StatefulOutputPin for Output {
}
}
#[derive(Debug)]
pub struct Input(ll::LowLevelGpio);
impl Input {
pub fn new_floating<I: PinMarker>(_pin: Pin<I>) -> Self {
pub fn new_floating<I: PinIdProvider>(_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: PinMarker>(_pin: Pin<I>, pull: Pull) -> Self {
pub fn new_with_pull<I: PinIdProvider>(_pin: Pin<I>, pull: Pull) -> Self {
let mut ll = ll::LowLevelGpio::new(I::ID);
ll.configure_as_input_with_pull(pull);
Input(ll)
@ -126,10 +132,25 @@ impl Input {
}
#[inline]
pub fn configure_edge_interrupt(&mut self, edge: ll::InterruptEdge) {
pub fn configure_edge_interrupt(&mut self, edge: InterruptEdge) {
self.0.configure_edge_interrupt(edge);
}
#[inline]
pub fn configure_level_interrupt(&mut self, edge: InterruptLevel) {
self.0.configure_level_interrupt(edge);
}
#[inline]
pub fn configure_delay(&mut self, delay_1: bool, delay_2: bool) {
self.0.configure_delay(delay_1, delay_2);
}
#[inline]
pub fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
self.0.configure_filter_type(filter, clksel);
}
#[inline]
pub fn is_low(&self) -> bool {
self.0.is_low()
@ -155,6 +176,7 @@ impl embedded_hal::digital::InputPin for Input {
}
}
#[derive(Debug)]
pub enum PinMode {
InputFloating,
InputWithPull(Pull),
@ -172,13 +194,14 @@ impl PinMode {
}
}
#[derive(Debug)]
pub struct Flex {
ll: ll::LowLevelGpio,
mode: PinMode,
}
impl Flex {
pub fn new<I: PinMarker>(_pin: Pin<I>) -> Self {
pub fn new<I: PinIdProvider>(_pin: Pin<I>) -> Self {
let mut ll = ll::LowLevelGpio::new(I::ID);
ll.configure_as_input_floating();
Flex {
@ -287,12 +310,22 @@ pub struct IoPeriphPin {
}
impl IoPeriphPin {
pub fn new<I: PinMarker>(_pin: Pin<I>, fun_sel: FunSel, pull: Option<Pull>) -> Self {
pub fn new_with_pin<I: PinIdProvider>(
_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 }
}
pub fn new(pin_id: PinId, fun_sel: FunSel, pull: Option<Pull>) -> Self {
let mut ll = ll::LowLevelGpio::new(pin_id);
ll.configure_as_peripheral_pin(fun_sel, pull);
IoPeriphPin { ll, fun_sel }
}
pub fn port(&self) -> Port {
self.ll.port()
}

View File

@ -1 +1,3 @@
pub use regs::{FilterClkSel, FilterType};
pub mod regs;

View File

@ -1,6 +1,6 @@
use core::marker::PhantomData;
use crate::{InvalidOffsetError, NUM_PORT_A, NUM_PORT_B};
use crate::{NUM_PORT_A, NUM_PORT_B, gpio::PinId};
#[cfg(feature = "vor4x")]
use crate::{NUM_PORT_DEFAULT, NUM_PORT_G};
@ -73,7 +73,7 @@ pub struct Config {
#[bit(6, rw)]
invert_input: bool,
#[bits(3..=5, rw)]
filter_sel: FilterClkSel,
filter_clk_sel: FilterClkSel,
#[bits(0..=2, rw)]
filter_type: Option<FilterType>,
}
@ -134,24 +134,9 @@ impl IoConfig {
}
impl MmioIoConfig<'_> {
pub fn read_pin_config(
&self,
port: crate::Port,
offset: usize,
) -> Result<Config, InvalidOffsetError> {
if offset >= port.max_offset() {
return Err(InvalidOffsetError { port, offset });
}
Ok(unsafe { self.read_pin_config_unchecked(port, offset) })
}
/// This function does NOT perform any bounds checking.
///
/// # Safety
///
/// Calling this function with an invalid offset can lead to undefined behaviour.
pub unsafe fn read_pin_config_unchecked(&self, port: crate::Port, offset: usize) -> Config {
match port {
pub fn read_pin_config(&self, id: PinId) -> Config {
let offset = id.offset();
match id.port() {
crate::Port::A => unsafe { self.read_port_a_unchecked(offset) },
crate::Port::B => unsafe { self.read_port_b_unchecked(offset) },
#[cfg(feature = "vor4x")]
@ -167,63 +152,14 @@ impl MmioIoConfig<'_> {
}
}
pub fn modify_pin_config<F: FnOnce(Config) -> Config>(
&mut self,
port: crate::Port,
offset: usize,
f: F,
) -> Result<(), InvalidOffsetError> {
if offset >= port.max_offset() {
return Err(InvalidOffsetError { port, offset });
}
unsafe { self.modify_pin_config_unchecked(port, offset, f) };
Ok(())
pub fn modify_pin_config<F: FnOnce(Config) -> Config>(&mut self, id: PinId, f: F) {
let config = self.read_pin_config(id);
self.write_pin_config(id, f(config))
}
/// This function does NOT perform any bounds checking.
///
/// # Safety
///
/// Calling this function with an invalid offset can lead to undefined behaviour.
pub unsafe fn modify_pin_config_unchecked<F: FnOnce(Config) -> Config>(
&mut self,
port: crate::Port,
offset: usize,
mut f: F,
) {
unsafe {
let config = self.read_pin_config_unchecked(port, offset);
self.write_pin_config_unchecked(port, offset, f(config))
}
}
pub fn write_pin_config(
&mut self,
port: crate::Port,
offset: usize,
config: Config,
) -> Result<(), InvalidOffsetError> {
if offset >= port.max_offset() {
return Err(InvalidOffsetError { port, offset });
}
unsafe {
self.write_pin_config_unchecked(port, offset, config);
}
Ok(())
}
/// This function does NOT perform any bounds checking.
///
/// # Safety
///
/// Calling this function with an invalid offset can lead to undefined behaviour.
pub unsafe fn write_pin_config_unchecked(
&mut self,
port: crate::Port,
offset: usize,
config: Config,
) {
match port {
pub fn write_pin_config(&mut self, id: PinId, config: Config) {
let offset = id.offset();
match id.port() {
crate::Port::A => unsafe { self.write_port_a_unchecked(offset, config) },
crate::Port::B => unsafe { self.write_port_b_unchecked(offset, config) },
#[cfg(feature = "vor4x")]

View File

View File

@ -15,3 +15,29 @@ pub fn disable_peripheral_clock(clock: crate::PeripheralSelect) {
.peripheral_clk_enable()
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << clock as u8)) });
}
#[cfg(feature = "vor1x")]
#[inline]
pub fn assert_peripheral_reset(periph_sel: crate::PeripheralSelect) {
let syscfg = unsafe { va108xx::Sysconfig::steal() };
syscfg
.peripheral_reset()
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << periph_sel as u8)) });
}
#[cfg(feature = "vor1x")]
#[inline]
pub fn deassert_peripheral_reset(periph_sel: crate::PeripheralSelect) {
let syscfg = unsafe { va108xx::Sysconfig::steal() };
syscfg
.peripheral_reset()
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << periph_sel as u8)) });
}
#[cfg(feature = "vor1x")]
#[inline]
pub fn reset_peripheral_for_cycles(periph_sel: crate::PeripheralSelect, cycles: u32) {
assert_peripheral_reset(periph_sel);
cortex_m::asm::delay(cycles);
deassert_peripheral_reset(periph_sel);
}