diff --git a/va108xx-hal/src/gpio/mod.rs b/va108xx-hal/src/gpio/mod.rs index 032e790..46bcd4c 100644 --- a/va108xx-hal/src/gpio/mod.rs +++ b/va108xx-hal/src/gpio/mod.rs @@ -12,6 +12,11 @@ //! //! The [crate::pins] module exposes singletons to access the [Pin]s required by this module //! in a type-safe way. +//! +//! ## Examples +//! +//! - [Blinky example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/blinky.rs) +//! - [Async GPIO example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/embassy/src/bin/async-gpio.rs) pub use vorago_shared_periphs::gpio::*; pub use vorago_shared_periphs::gpio::asynch; diff --git a/va108xx-hal/src/gpio_tmp/asynch.rs b/va108xx-hal/src/gpio_tmp/asynch.rs deleted file mode 100644 index e69de29..0000000 diff --git a/va108xx-hal/src/gpio_tmp/dynpin.rs b/va108xx-hal/src/gpio_tmp/dynpin.rs deleted file mode 100644 index 993150c..0000000 --- a/va108xx-hal/src/gpio_tmp/dynpin.rs +++ /dev/null @@ -1,947 +0,0 @@ -//! # Type-erased, value-level module for GPIO pins -//! -//! Although the type-level API is generally preferred, it is not suitable in -//! all cases. Because each pin is represented by a distinct type, it is not -//! possible to store multiple pins in a homogeneous data structure. The -//! value-level API solves this problem by erasing the type information and -//! tracking the pin at run-time. -//! -//! Value-level pins are represented by the [`DynPin`] type. [`DynPin`] has two -//! fields, `id` and `mode` with types [`DynPinId`] and [`DynPinMode`] -//! respectively. The implementation of these types closely mirrors the -//! type-level API. -//! -//! Instances of [`DynPin`] cannot be created directly. Rather, they must be -//! created from their type-level equivalents using [`From`]/[`Into`]. -//! -//! ``` -//! // Move a pin out of the Pins struct and convert to a DynPin -//! let pa0: DynPin = pins.pa0.into(); -//! ``` -//! -//! Conversions between pin modes use a value-level version of the type-level -//! API. -//! -//! ``` -//! // Use one of the literal function names -//! pa0.into_floating_input(); -//! // Use a method and a DynPinMode variant -//! pa0.into_mode(DYN_FLOATING_INPUT); -//! ``` -//! -//! Because the pin state cannot be tracked at compile-time, many [`DynPin`] -//! operations become fallible. Run-time checks are inserted to ensure that -//! users don't try to, for example, set the output level of an input pin. -//! -//! Users may try to convert value-level pins back to their type-level -//! equivalents. However, this option is fallible, because the compiler cannot -//! guarantee the pin has the correct ID or is in the correct mode at -//! compile-time. Use [TryFrom]/[TryInto] for this conversion. -//! -//! ``` -//! // Convert to a `DynPin` -//! let pa0: DynPin = pins.pa0.into(); -//! // Change pin mode -//! pa0.into_floating_input(); -//! // Convert back to a `Pin` -//! let pa0: Pin = pa0.try_into().unwrap(); -//! ``` -//! -//! # Embedded HAL traits -//! -//! This module implements all of the embedded HAL GPIO traits for [`DynPin`]. -//! However, whereas the type-level API uses -//! `Error = core::convert::Infallible`, the value-level API can return a real -//! error. If the [`DynPin`] is not in the correct [`DynPinMode`] for the -//! operation, the trait functions will return -//! [InvalidPinTypeError]. - -use super::{ - pin::{FilterType, Pin, PinId, PinMode}, - InputDynPinAsync, InterruptEdge, InterruptLevel, IsMaskedError, PinState, Port, -}; -use crate::{clock::FilterClkSel, enable_nvic_interrupt, pac, FunSel}; - -//================================================================================================== -// DynPinMode configurations -//================================================================================================== - -/// Value-level `enum` for disabled configurations -#[derive(PartialEq, Eq, Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum DynDisabled { - Floating, - PullDown, - PullUp, -} - -/// Value-level `enum` for input configurations -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum DynInput { - Floating, - PullDown, - PullUp, -} - -/// Value-level `enum` for output configurations -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum DynOutput { - PushPull, - OpenDrain, - ReadablePushPull, - ReadableOpenDrain, -} - -pub type DynAlternate = FunSel; - -//============================================================================== -// Error -//============================================================================== - -/// GPIO error type -/// -/// [`DynPin`]s are not tracked and verified at compile-time, so run-time -/// operations are fallible. This `enum` represents the corresponding errors. -#[derive(Debug, PartialEq, Eq, thiserror::Error)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[error("Invalid pin type for operation: {0:?}")] -pub struct InvalidPinTypeError(pub DynPinMode); - -impl embedded_hal::digital::Error for InvalidPinTypeError { - fn kind(&self) -> embedded_hal::digital::ErrorKind { - embedded_hal::digital::ErrorKind::Other - } -} - -//================================================================================================== -// DynPinMode -//================================================================================================== - -/// Value-level `enum` representing pin modes -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum DynPinMode { - Input(DynInput), - Output(DynOutput), - Alternate(DynAlternate), -} - -/// Value-level variant of [`DynPinMode`] for floating input mode -pub const DYN_FLOATING_INPUT: DynPinMode = DynPinMode::Input(DynInput::Floating); -/// Value-level variant of [`DynPinMode`] for pull-down input mode -pub const DYN_PULL_DOWN_INPUT: DynPinMode = DynPinMode::Input(DynInput::PullDown); -/// Value-level variant of [`DynPinMode`] for pull-up input mode -pub const DYN_PULL_UP_INPUT: DynPinMode = DynPinMode::Input(DynInput::PullUp); - -/// Value-level variant of [`DynPinMode`] for push-pull output mode -pub const DYN_PUSH_PULL_OUTPUT: DynPinMode = DynPinMode::Output(DynOutput::PushPull); -/// Value-level variant of [`DynPinMode`] for open-drain output mode -pub const DYN_OPEN_DRAIN_OUTPUT: DynPinMode = DynPinMode::Output(DynOutput::OpenDrain); -/// Value-level variant of [`DynPinMode`] for readable push-pull output mode -pub const DYN_RD_PUSH_PULL_OUTPUT: DynPinMode = DynPinMode::Output(DynOutput::ReadablePushPull); -/// Value-level variant of [`DynPinMode`] for readable opendrain output mode -pub const DYN_RD_OPEN_DRAIN_OUTPUT: DynPinMode = DynPinMode::Output(DynOutput::ReadableOpenDrain); - -/// Value-level variant of [`DynPinMode`] for function select 1 -pub const DYN_ALT_FUNC_1: DynPinMode = DynPinMode::Alternate(DynAlternate::Sel1); -/// Value-level variant of [`DynPinMode`] for function select 2 -pub const DYN_ALT_FUNC_2: DynPinMode = DynPinMode::Alternate(DynAlternate::Sel2); -/// Value-level variant of [`DynPinMode`] for function select 3 -pub const DYN_ALT_FUNC_3: DynPinMode = DynPinMode::Alternate(DynAlternate::Sel3); - -//================================================================================================== -// DynGroup & DynPinId -//================================================================================================== - -pub type DynGroup = Port; - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct DynPinId { - port: Port, - num: u8, -} - -impl DynPinId { - pub const fn new(port: Port, num: u8) -> Self { - DynPinId { port, num } - } - - pub const fn port(&self) -> Port { - self.port - } - pub const fn num(&self) -> u8 { - self.num - } -} - -//================================================================================================== -// ModeFields -//================================================================================================== - -/// Collect all fields needed to set the [`PinMode`](super::PinMode) -#[derive(Default)] -struct ModeFields { - dir: bool, - opendrn: bool, - pull_en: bool, - /// true for pullup, false for pulldown - pull_dir: bool, - funsel: u8, - enb_input: bool, -} - -impl From for ModeFields { - #[inline] - fn from(mode: DynPinMode) -> Self { - let mut fields = Self::default(); - match mode { - DynPinMode::Input(config) => { - fields.dir = false; - fields.funsel = FunSel::Sel0 as u8; - match config { - DynInput::Floating => (), - DynInput::PullUp => { - fields.pull_en = true; - fields.pull_dir = true; - } - DynInput::PullDown => { - fields.pull_en = true; - } - } - } - DynPinMode::Output(config) => { - fields.dir = true; - fields.funsel = FunSel::Sel0 as u8; - match config { - DynOutput::PushPull => (), - DynOutput::OpenDrain => { - fields.opendrn = true; - } - DynOutput::ReadableOpenDrain => { - fields.enb_input = true; - fields.opendrn = true; - } - DynOutput::ReadablePushPull => { - fields.enb_input = true; - } - } - } - DynPinMode::Alternate(config) => { - fields.funsel = config as u8; - } - } - fields - } -} - -/// Type definition to avoid confusion: These register blocks are identical -type PortRegisterBlock = pac::porta::RegisterBlock; -pub type PortReg = pac::ioconfig::Porta; - -//================================================================================================== -// DynPin -//================================================================================================== - -/// A value-level pin, parameterized by [`DynPinId`] and [`DynPinMode`] -/// -/// 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. -#[derive(Debug)] -pub struct DynPin { - id: DynPinId, - mode: DynPinMode, -} - -impl DynPin { - /// Create a new [DynPin] - /// - /// # Safety - /// - /// Each [DynPin] must be a singleton. For a given [DynPinId], there - /// must be at most one corresponding [`DynPin`] in existence at any given - /// time. Violating this requirement is `unsafe`. - #[inline] - pub(crate) const unsafe fn new(id: DynPinId, mode: DynPinMode) -> Self { - DynPin { id, mode } - } - - /// Steals a new [DynPin]. - /// - /// This function will simply set the internal mode to [DYN_FLOATING_INPUT] pin without - /// modifying any registers related to the behaviour of the pin. The user should call - /// [Self::into_mode] to ensure the correct mode of the pin. - /// - /// # Safety - /// - /// Circumvents the HAL's safety guarantees. The caller must ensure that the pin is not - /// used cocurrently somewhere else. The caller might also want to call [Self::into_mode] - /// to ensure the correct desired state of the pin. It is recommended to create the pin using - /// [Pin::downgrade] instead. - pub const unsafe fn steal(id: DynPinId) -> Self { - DynPin { - id, - mode: DYN_FLOATING_INPUT, - } - } - - /// Return a copy of the pin ID - #[inline] - pub const fn id(&self) -> DynPinId { - self.id - } - - /// Return a copy of the pin mode - #[inline] - pub const fn mode(&self) -> DynPinMode { - self.mode - } - - /// Convert the pin to the requested [`DynPinMode`] - #[inline] - pub fn into_mode(&mut self, mode: DynPinMode) { - self.change_mode(mode); - self.mode = mode; - } - - #[inline] - pub fn is_input_pin(&self) -> bool { - matches!(self.mode, DynPinMode::Input(_)) - } - - #[inline] - pub fn is_output_pin(&self) -> bool { - matches!(self.mode, DynPinMode::Output(_)) - } - - #[inline] - pub fn into_funsel_1(&mut self) { - self.into_mode(DYN_ALT_FUNC_1); - } - - #[inline] - pub fn into_funsel_2(&mut self) { - self.into_mode(DYN_ALT_FUNC_2); - } - - #[inline] - pub fn into_funsel_3(&mut self) { - self.into_mode(DYN_ALT_FUNC_3); - } - - /// Configure the pin to operate as a floating input - #[inline] - pub fn into_floating_input(&mut self) { - self.into_mode(DYN_FLOATING_INPUT); - } - - /// Configure the pin to operate as a pulled down input - #[inline] - pub fn into_pull_down_input(&mut self) { - self.into_mode(DYN_PULL_DOWN_INPUT); - } - - /// Configure the pin to operate as a pulled up input - #[inline] - pub fn into_pull_up_input(&mut self) { - self.into_mode(DYN_PULL_UP_INPUT); - } - - /// Configure the pin to operate as a push-pull output - #[inline] - pub fn into_push_pull_output(&mut self) { - self.into_mode(DYN_PUSH_PULL_OUTPUT); - } - - /// Configure the pin to operate as a push-pull output - #[inline] - pub fn into_open_drain_output(&mut self) { - self.into_mode(DYN_OPEN_DRAIN_OUTPUT); - } - - /// Configure the pin to operate as a push-pull output - #[inline] - pub fn into_readable_push_pull_output(&mut self) { - self.into_mode(DYN_RD_PUSH_PULL_OUTPUT); - } - - /// Configure the pin to operate as a push-pull output - #[inline] - pub fn into_readable_open_drain_output(&mut self) { - self.into_mode(DYN_RD_OPEN_DRAIN_OUTPUT); - } - - #[inline(always)] - pub fn is_low(&self) -> Result { - self.read_internal().map(|v| !v) - } - - #[inline(always)] - pub fn is_high(&self) -> Result { - self.read_internal() - } - - #[inline(always)] - pub fn set_low(&mut self) -> Result<(), InvalidPinTypeError> { - self.write_internal(false) - } - - #[inline(always)] - pub fn set_high(&mut self) -> Result<(), InvalidPinTypeError> { - self.write_internal(true) - } - - /// Toggle the logic level of an output pin - #[inline(always)] - pub fn toggle(&mut self) -> Result<(), InvalidPinTypeError> { - if !self.is_output_pin() { - return Err(InvalidPinTypeError(self.mode)); - } - // Safety: TOGOUT is a "mask" register, and we only write the bit for - // this pin ID - unsafe { self.port_reg().togout().write(|w| w.bits(self.mask_32())) }; - Ok(()) - } - - pub fn enable_interrupt(&mut self, irq_cfg: crate::InterruptConfig) { - if irq_cfg.route { - self.configure_irqsel(irq_cfg.id); - } - if irq_cfg.enable_in_nvic { - unsafe { enable_nvic_interrupt(irq_cfg.id) }; - } - - // We only manipulate our own bit. - self.port_reg() - .irq_enb() - .modify(|r, w| unsafe { w.bits(r.bits() | self.mask_32()) }); - } - - pub fn disable_interrupt(&mut self, reset_irqsel: bool) { - if reset_irqsel { - self.reset_irqsel(); - } - // We only manipulate our own bit. - self.port_reg() - .irq_enb() - .modify(|r, w| unsafe { w.bits(r.bits() & !self.mask_32()) }); - } - - /// 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(self) -> Result, InvalidPinTypeError> { - if self.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(self.mode)) - } - - /// Convert the pin into an async pin. The pin can be converted back by calling - /// [InputDynPinAsync::release] - pub fn into_async_input( - self, - irq: crate::pac::Interrupt, - ) -> Result { - InputDynPinAsync::new(self, irq) - } - - /// Configure the IRQSEL peripheral for this particular pin with the given interrupt ID. - pub fn configure_irqsel(&mut self, id: pac::Interrupt) { - let mut syscfg = unsafe { pac::Sysconfig::steal() }; - let irqsel = unsafe { pac::Irqsel::steal() }; - crate::clock::enable_peripheral_clock(&mut syscfg, crate::clock::PeripheralClocks::Irqsel); - match self.id().port() { - // Set the correct interrupt number in the IRQSEL register - super::Port::A => { - irqsel - .porta0(self.id().num() as usize) - .write(|w| unsafe { w.bits(id as u32) }); - } - super::Port::B => { - irqsel - .portb0(self.id().num as usize) - .write(|w| unsafe { w.bits(id as u32) }); - } - } - } - - /// Reset the IRQSEL peripheral value for this particular pin. - pub fn reset_irqsel(&mut self) { - let mut syscfg = unsafe { pac::Sysconfig::steal() }; - let irqsel = unsafe { pac::Irqsel::steal() }; - crate::clock::enable_peripheral_clock(&mut syscfg, crate::clock::PeripheralClocks::Irqsel); - match self.id().port() { - // Set the correct interrupt number in the IRQSEL register - super::Port::A => { - irqsel - .porta0(self.id().num() as usize) - .write(|w| unsafe { w.bits(u32::MAX) }); - } - super::Port::B => { - irqsel - .portb0(self.id().num as usize) - .write(|w| unsafe { w.bits(u32::MAX) }); - } - } - } - - // Get DATAMASK bit for this particular pin - #[inline(always)] - pub fn datamask(&self) -> bool { - (self.port_reg().datamask().read().bits() >> self.id().num) == 1 - } - - /// Clear DATAMASK bit for this particular pin. This prevents access - /// of the corresponding bit for output and input operations - #[inline(always)] - pub fn clear_datamask(&self) { - self.port_reg() - .datamask() - .modify(|r, w| unsafe { w.bits(r.bits() & !self.mask_32()) }); - } - - /// Set DATAMASK bit for this particular pin. 1 is the default - /// state of the bit and allows access of the corresponding bit - #[inline(always)] - pub fn set_datamask(&self) { - self.port_reg() - .datamask() - .modify(|r, w| unsafe { w.bits(r.bits() | self.mask_32()) }); - } - - #[inline] - pub fn is_high_masked(&self) -> Result { - self.read_pin_masked() - } - - #[inline] - pub fn is_low_masked(&self) -> Result { - self.read_pin_masked().map(|v| !v) - } - - #[inline] - pub fn set_high_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> { - self.write_pin_masked(true) - } - - #[inline] - pub fn set_low_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> { - self.write_pin_masked(false) - } - - /// Possible delays in clock cycles: - /// - Delay 1: 1 - /// - Delay 2: 2 - /// - Delay 1 + Delay 2: 3 - #[inline] - pub fn configure_delay( - &mut self, - delay_1: bool, - delay_2: bool, - ) -> Result<(), InvalidPinTypeError> { - match self.mode { - DynPinMode::Output(_) => { - self.configure_delay_internal(delay_1, delay_2); - Ok(()) - } - _ => Err(InvalidPinTypeError(self.mode)), - } - } - - /// 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 - #[inline] - pub fn configure_pulse_mode( - &mut self, - enable: bool, - default_state: PinState, - ) -> Result<(), InvalidPinTypeError> { - match self.mode { - DynPinMode::Output(_) => { - self.configure_pulse_mode_internal(enable, default_state); - Ok(()) - } - _ => Err(InvalidPinTypeError(self.mode)), - } - } - - /// See p.37 and p.38 of the programmers guide for more information. - #[inline] - pub fn configure_filter_type( - &mut self, - filter: FilterType, - clksel: FilterClkSel, - ) -> Result<(), InvalidPinTypeError> { - match self.mode { - DynPinMode::Input(_) => { - self.configure_filter_type_internal(filter, clksel); - Ok(()) - } - _ => Err(InvalidPinTypeError(self.mode)), - } - } - - pub fn configure_edge_interrupt( - &mut self, - edge_type: InterruptEdge, - ) -> Result<(), InvalidPinTypeError> { - match self.mode { - DynPinMode::Input(_) | DynPinMode::Output(_) => { - self.configure_edge_interrupt_internal(edge_type); - Ok(()) - } - _ => Err(InvalidPinTypeError(self.mode)), - } - } - - pub fn configure_level_interrupt( - &mut self, - level_type: InterruptLevel, - ) -> Result<(), InvalidPinTypeError> { - match self.mode { - DynPinMode::Input(_) | DynPinMode::Output(_) => { - self.configure_level_interrupt_internal(level_type); - Ok(()) - } - _ => Err(InvalidPinTypeError(self.mode)), - } - } - - /// Change the pin mode - #[inline] - pub(crate) fn change_mode(&mut self, mode: DynPinMode) { - let ModeFields { - dir, - funsel, - opendrn, - pull_dir, - pull_en, - enb_input, - } = mode.into(); - let (portreg, iocfg) = (self.port_reg(), self.iocfg_port()); - iocfg.write(|w| { - w.opendrn().bit(opendrn); - w.pen().bit(pull_en); - w.plevel().bit(pull_dir); - w.iewo().bit(enb_input); - unsafe { w.funsel().bits(funsel) } - }); - let mask = self.mask_32(); - unsafe { - if dir { - portreg.dir().modify(|r, w| w.bits(r.bits() | mask)); - // Clear output - portreg.clrout().write(|w| w.bits(mask)); - } else { - portreg.dir().modify(|r, w| w.bits(r.bits() & !mask)); - } - } - } - - #[inline] - const fn port_reg(&self) -> &PortRegisterBlock { - match self.id().port() { - Port::A => unsafe { &(*pac::Porta::ptr()) }, - Port::B => unsafe { &(*pac::Portb::ptr()) }, - } - } - - #[inline] - const fn iocfg_port(&self) -> &PortReg { - let ioconfig = unsafe { va108xx::Ioconfig::ptr().as_ref().unwrap() }; - match self.id().port() { - Port::A => ioconfig.porta(self.id().num() as usize), - Port::B => ioconfig.portb0(self.id().num() as usize), - } - } - - #[inline(always)] - fn read_internal(&self) -> Result { - match self.mode { - DynPinMode::Input(_) | DYN_RD_OPEN_DRAIN_OUTPUT | DYN_RD_PUSH_PULL_OUTPUT => { - Ok(self.read_pin()) - } - _ => Err(InvalidPinTypeError(self.mode)), - } - } - - #[inline(always)] - fn write_internal(&mut self, bit: bool) -> Result<(), InvalidPinTypeError> { - match self.mode { - DynPinMode::Output(_) => { - self.write_pin(bit); - Ok(()) - } - _ => Err(InvalidPinTypeError(self.mode)), - } - } - - #[inline] - /// Read the logic level of an output pin - pub(crate) fn read_pin(&self) -> bool { - let portreg = self.port_reg(); - ((portreg.datainraw().read().bits() >> self.id().num) & 0x01) == 1 - } - - /// Read a pin but use the masked version but check whether the datamask for the pin is - /// cleared as well - #[inline(always)] - fn read_pin_masked(&self) -> Result { - if !self.datamask() { - Err(IsMaskedError) - } else { - Ok(((self.port_reg().datain().read().bits() >> self.id().num) & 0x01) == 1) - } - } - - /// Write the logic level of an output pin - #[inline(always)] - pub(crate) fn write_pin(&mut self, bit: bool) { - // Safety: SETOUT is a "mask" register, and we only write the bit for - // this pin ID - unsafe { - if bit { - self.port_reg().setout().write(|w| w.bits(self.mask_32())); - } else { - self.port_reg().clrout().write(|w| w.bits(self.mask_32())); - } - } - } - - /// Write the logic level of an output pin but check whether the datamask for the pin is - /// cleared as well - #[inline] - fn write_pin_masked(&mut self, bit: bool) -> Result<(), IsMaskedError> { - if !self.datamask() { - Err(IsMaskedError) - } else { - // Safety: SETOUT is a "mask" register, and we only write the bit for - // this pin ID - unsafe { - if bit { - self.port_reg().setout().write(|w| w.bits(self.mask_32())); - } else { - self.port_reg().clrout().write(|w| w.bits(self.mask_32())); - } - Ok(()) - } - } - } - - /// Toggle the logic level of an output pin - #[inline(always)] - pub fn toggle_with_togout_reg(&mut self) { - // Safety: TOGOUT is a "mask" register, and we only write the bit for - // this pin ID - unsafe { self.port_reg().togout().write(|w| w.bits(self.mask_32())) }; - } - - /// Only useful for interrupt pins. Configure whether to use edges or level as interrupt soure - /// When using edge mode, it is possible to generate interrupts on both edges as well - #[inline] - fn configure_edge_interrupt_internal(&mut self, edge_type: InterruptEdge) { - unsafe { - self.port_reg() - .irq_sen() - .modify(|r, w| w.bits(r.bits() & !self.mask_32())); - match edge_type { - InterruptEdge::HighToLow => { - self.port_reg() - .irq_evt() - .modify(|r, w| w.bits(r.bits() & !self.mask_32())); - } - InterruptEdge::LowToHigh => { - self.port_reg() - .irq_evt() - .modify(|r, w| w.bits(r.bits() | self.mask_32())); - } - InterruptEdge::BothEdges => { - self.port_reg() - .irq_edge() - .modify(|r, w| w.bits(r.bits() | self.mask_32())); - } - } - } - } - - /// Configure which edge or level type triggers an interrupt - #[inline] - fn configure_level_interrupt_internal(&mut self, level: InterruptLevel) { - unsafe { - self.port_reg() - .irq_sen() - .modify(|r, w| w.bits(r.bits() | self.mask_32())); - if level == InterruptLevel::Low { - self.port_reg() - .irq_evt() - .modify(|r, w| w.bits(r.bits() & !self.mask_32())); - } else { - self.port_reg() - .irq_evt() - .modify(|r, w| w.bits(r.bits() | self.mask_32())); - } - } - } - - /// Only useful for input pins - #[inline] - fn configure_filter_type_internal(&mut self, filter: FilterType, clksel: FilterClkSel) { - self.iocfg_port().modify(|_, w| { - // Safety: Only write to register for this Pin ID - unsafe { - w.flttype().bits(filter as u8); - w.fltclk().bits(clksel as u8) - } - }); - } - - #[inline] - fn configure_pulse_mode_internal(&mut self, enable: bool, default_state: PinState) { - let portreg = self.port_reg(); - unsafe { - if enable { - portreg - .pulse() - .modify(|r, w| w.bits(r.bits() | self.mask_32())); - } else { - portreg - .pulse() - .modify(|r, w| w.bits(r.bits() & !self.mask_32())); - } - if default_state == PinState::Low { - portreg - .pulsebase() - .modify(|r, w| w.bits(r.bits() & !self.mask_32())); - } else { - portreg - .pulsebase() - .modify(|r, w| w.bits(r.bits() | self.mask_32())); - } - } - } - - /// Only useful for output pins - #[inline] - fn configure_delay_internal(&mut self, delay_1: bool, delay_2: bool) { - let portreg = self.port_reg(); - unsafe { - if delay_1 { - portreg - .delay1() - .modify(|r, w| w.bits(r.bits() | self.mask_32())); - } else { - portreg - .delay1() - .modify(|r, w| w.bits(r.bits() & !self.mask_32())); - } - if delay_2 { - portreg - .delay2() - .modify(|r, w| w.bits(r.bits() | self.mask_32())); - } else { - portreg - .delay2() - .modify(|r, w| w.bits(r.bits() & !self.mask_32())); - } - } - } - - // Only serves disambiguation purposes for the Embedded HAL impl - #[inline(always)] - fn is_low_mut(&mut self) -> Result { - self.is_low() - } - - // Only serves disambiguation purposes for the Embedded HAL impl - #[inline(always)] - fn is_high_mut(&mut self) -> Result { - self.is_high() - } - - #[inline(always)] - const fn mask_32(&self) -> u32 { - 1 << self.id().num() - } -} - -//================================================================================================== -// Convert between Pin and DynPin -//================================================================================================== - -impl From> for DynPin { - /// Erase the type-level information in a [`Pin`] and return a value-level - /// [`DynPin`] - #[inline] - fn from(pin: Pin) -> Self { - pin.downgrade() - } -} - -impl TryFrom for Pin { - type Error = InvalidPinTypeError; - - /// 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] - fn try_from(pin: DynPin) -> Result { - pin.upgrade() - } -} - -//================================================================================================== -// Embedded HAL traits -//================================================================================================== - -impl embedded_hal::digital::ErrorType for DynPin { - type Error = InvalidPinTypeError; -} - -impl embedded_hal::digital::OutputPin for DynPin { - #[inline] - fn set_high(&mut self) -> Result<(), Self::Error> { - self.set_high() - } - #[inline] - fn set_low(&mut self) -> Result<(), Self::Error> { - self.set_low() - } -} - -impl embedded_hal::digital::InputPin for DynPin { - #[inline] - fn is_high(&mut self) -> Result { - self.is_high_mut() - } - #[inline] - fn is_low(&mut self) -> Result { - self.is_low_mut() - } -} - -impl embedded_hal::digital::StatefulOutputPin for DynPin { - #[inline] - fn is_set_high(&mut self) -> Result { - self.is_high_mut() - } - - #[inline] - fn is_set_low(&mut self) -> Result { - self.is_low_mut() - } - - #[inline] - fn toggle(&mut self) -> Result<(), Self::Error> { - self.toggle() - } -} diff --git a/va108xx-hal/src/gpio_tmp/mod.rs b/va108xx-hal/src/gpio_tmp/mod.rs deleted file mode 100644 index 6c95ae0..0000000 --- a/va108xx-hal/src/gpio_tmp/mod.rs +++ /dev/null @@ -1,74 +0,0 @@ -//! # API for the GPIO peripheral -//! -//! The implementation of this GPIO module is heavily based on the -//! [ATSAMD HAL implementation](https://docs.rs/atsamd-hal/latest/atsamd_hal/gpio/index.html). -//! -//! This API provides two different submodules, [pin] and [dynpin], -//! representing two different ways to handle GPIO pins. The default, [pin], -//! is a type-level API that tracks the state of each pin at compile-time. The -//! alternative, [dynpin] is a type-erased, value-level API that tracks the -//! state of each pin at run-time. -//! -//! The type-level API is strongly preferred. By representing the state of each -//! pin within the type system, the compiler can detect logic errors at -//! compile-time. Furthermore, the type-level API has absolutely zero run-time -//! cost. -//! -//! If needed, [dynpin] can be used to erase the type-level differences -//! between pins. However, by doing so, pins must now be tracked at run-time, -//! and each pin has a non-zero memory footprint. -//! -//! ## Examples -//! -//! - [Blinky example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/blinky.rs) - -//================================================================================================== -// Errors, Definitions and Constants -//================================================================================================== - -pub const NUM_PINS_PORT_A: usize = 32; -pub const NUM_PINS_PORT_B: usize = 24; -pub const NUM_GPIO_PINS: usize = NUM_PINS_PORT_A + NUM_PINS_PORT_B; - -#[derive(Debug, PartialEq, Eq, thiserror::Error)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[error("The pin is masked")] -pub struct IsMaskedError; - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Port { - A, - B, -} - -#[derive(Debug, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum InterruptEdge { - HighToLow, - LowToHigh, - BothEdges, -} - -#[derive(Debug, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum InterruptLevel { - Low = 0, - High = 1, -} - -#[derive(Debug, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum PinState { - Low = 0, - High = 1, -} - -pub mod dynpin; -pub use dynpin::*; - -pub mod pin; -pub use pin::*; - -pub mod asynch; -pub use asynch::*; diff --git a/va108xx-hal/src/gpio_tmp/pin.rs b/va108xx-hal/src/gpio_tmp/pin.rs deleted file mode 100644 index 8575f2e..0000000 --- a/va108xx-hal/src/gpio_tmp/pin.rs +++ /dev/null @@ -1,823 +0,0 @@ -//! # Type-level module for GPIO pins -//! -//! This documentation is strongly based on the -//! [atsamd documentation](https://docs.rs/atsamd-hal/latest/atsamd_hal/gpio/pin/index.html). -//! -//! This module provides a type-level API for GPIO pins. It uses the type system -//! to track the state of pins at compile-time. Representing GPIO pins in this -//! manner incurs no run-time overhead. Each [`Pin`] struct is zero-sized, so -//! there is no data to copy around. Instead, real code is generated as a side -//! effect of type transformations, and the resulting assembly is nearly -//! identical to the equivalent, hand-written C. -//! -//! To track the state of pins at compile-time, this module uses traits to -//! represent [type classes] and types as instances of those type classes. For -//! example, the trait [`InputConfig`] acts as a [type-level enum] of the -//! available input configurations, and the types [`Floating`], [`PullDown`] and -//! [`PullUp`] are its type-level variants. -//! -//! Type-level [`Pin`]s are parameterized by two type-level enums, [`PinId`] and -//! [`PinMode`]. -//! -//! ``` -//! pub struct Pin -//! where -//! I: PinId, -//! M: PinMode, -//! { -//! // ... -//! } -//! ``` -//! -//! A [PinId] identifies a pin by it's group (A or B) and pin number. Each -//! [PinId] instance is named according to its datasheet identifier, e.g. -//! [PA2]. -//! -//! A [PinMode] represents the various pin modes. The available [PinMode] -//! variants are [`Input`], [`Output`] and [`Alternate`], each with its own -//! corresponding configurations. -//! -//! It is not possible for users to create new instances of a [`Pin`]. Singleton -//! instances of each pin are made available to users through the PinsX -//! struct. -//! -//! Example for the pins of PORT A: -//! -//! To create the [PinsA] struct, users must supply the PAC -//! [Port](crate::pac::Porta) peripheral. The [PinsA] struct takes -//! ownership of the [Porta] and provides the corresponding pins. Each [`Pin`] -//! within the [PinsA] struct can be moved out and used individually. -//! -//! -//! ``` -//! let mut peripherals = Peripherals::take().unwrap(); -//! let pinsa = PinsA::new(peripherals.PORT); -//! ``` -//! -//! Pins can be converted between modes using several different methods. -//! -//! ```no_run -//! // Use one of the literal function names -//! let pa0 = pinsa.pa0.into_floating_input(); -//! // Use a generic method and one of the `PinMode` variant types -//! let pa0 = pinsa.pa0.into_mode::(); -//! // Specify the target type and use `From`/`Into` -//! let pa0: Pin = pinsa.pa27.into(); -//! ``` -//! -//! # Embedded HAL traits -//! -//! This module implements all of the embedded HAL GPIO traits for each [`Pin`] -//! in the corresponding [`PinMode`]s, namely: [embedded_hal::digital::InputPin], -//! [embedded_hal::digital::OutputPin] and [embedded_hal::digital::StatefulOutputPin]. -use super::dynpin::{DynAlternate, DynInput, DynOutput, DynPinId, DynPinMode}; -use super::{DynPin, InputPinAsync, InterruptEdge, InterruptLevel, PinState, Port}; -use crate::{ - pac::{Porta, Portb}, - typelevel::Sealed, -}; -use core::convert::Infallible; -use core::marker::PhantomData; -use core::mem::transmute; -use paste::paste; - -//================================================================================================== -// Input configuration -//================================================================================================== - -/// Type-level enum for input configurations -/// -/// The valid options are [Floating], [PullDown] and [PullUp]. -pub trait InputConfig: Sealed { - /// Corresponding [DynInput] - const DYN: DynInput; -} - -#[derive(Debug)] -pub enum Floating {} -#[derive(Debug)] -pub enum PullDown {} -#[derive(Debug)] -pub enum PullUp {} - -impl InputConfig for Floating { - const DYN: DynInput = DynInput::Floating; -} -impl InputConfig for PullDown { - const DYN: DynInput = DynInput::PullDown; -} -impl InputConfig for PullUp { - const DYN: DynInput = DynInput::PullUp; -} - -impl Sealed for Floating {} -impl Sealed for PullDown {} -impl Sealed for PullUp {} - -/// Type-level variant of [`PinMode`] for floating input mode -pub type InputFloating = Input; -/// Type-level variant of [`PinMode`] for pull-down input mode -pub type InputPullDown = Input; -/// Type-level variant of [`PinMode`] for pull-up input mode -pub type InputPullUp = Input; - -/// Type-level variant of [`PinMode`] for input modes -/// -/// Type `C` is one of three input configurations: [`Floating`], [`PullDown`] or -/// [`PullUp`] -#[derive(Debug)] -pub struct Input { - cfg: PhantomData, -} - -impl Sealed for Input {} - -#[derive(Debug, PartialEq, Eq)] -pub enum FilterType { - SystemClock = 0, - DirectInputWithSynchronization = 1, - FilterOneClockCycle = 2, - FilterTwoClockCycles = 3, - FilterThreeClockCycles = 4, - FilterFourClockCycles = 5, -} - -pub use crate::clock::FilterClkSel; - -//================================================================================================== -// Output configuration -//================================================================================================== - -pub trait OutputConfig: Sealed { - const DYN: DynOutput; -} - -pub trait ReadableOutput: Sealed {} - -/// Type-level variant of [`OutputConfig`] for a push-pull configuration -#[derive(Debug)] -pub enum PushPull {} -/// Type-level variant of [`OutputConfig`] for an open drain configuration -#[derive(Debug)] -pub enum OpenDrain {} - -/// Type-level variant of [`OutputConfig`] for a readable push-pull configuration -#[derive(Debug)] -pub enum ReadablePushPull {} -/// Type-level variant of [`OutputConfig`] for a readable open-drain configuration -#[derive(Debug)] -pub enum ReadableOpenDrain {} - -impl Sealed for PushPull {} -impl Sealed for OpenDrain {} -impl Sealed for ReadableOpenDrain {} -impl Sealed for ReadablePushPull {} -impl ReadableOutput for ReadableOpenDrain {} -impl ReadableOutput for ReadablePushPull {} - -impl OutputConfig for PushPull { - const DYN: DynOutput = DynOutput::PushPull; -} -impl OutputConfig for OpenDrain { - const DYN: DynOutput = DynOutput::OpenDrain; -} -impl OutputConfig for ReadablePushPull { - const DYN: DynOutput = DynOutput::ReadablePushPull; -} -impl OutputConfig for ReadableOpenDrain { - const DYN: DynOutput = DynOutput::ReadableOpenDrain; -} - -/// Type-level variant of [`PinMode`] for output modes -/// -/// Type `C` is one of four output configurations: [`PushPull`], [`OpenDrain`] or -/// their respective readable versions -#[derive(Debug)] -pub struct Output { - cfg: PhantomData, -} - -impl Sealed for Output {} - -/// Type-level variant of [`PinMode`] for push-pull output mode -pub type PushPullOutput = Output; -/// Type-level variant of [`PinMode`] for open drain output mode -pub type OutputOpenDrain = Output; - -pub type OutputReadablePushPull = Output; -pub type OutputReadableOpenDrain = Output; - -//================================================================================================== -// Alternate configurations -//================================================================================================== - -/// Type-level enum for alternate peripheral function configurations -pub trait AlternateConfig: Sealed { - const DYN: DynAlternate; -} - -pub enum Funsel1 {} -pub enum Funsel2 {} -pub enum Funsel3 {} - -impl AlternateConfig for Funsel1 { - const DYN: DynAlternate = DynAlternate::Sel1; -} -impl AlternateConfig for Funsel2 { - const DYN: DynAlternate = DynAlternate::Sel2; -} -impl AlternateConfig for Funsel3 { - const DYN: DynAlternate = DynAlternate::Sel3; -} - -impl Sealed for Funsel1 {} -impl Sealed for Funsel2 {} -impl Sealed for Funsel3 {} - -/// Type-level variant of [`PinMode`] for alternate peripheral functions -/// -/// Type `C` is an [`AlternateConfig`] -pub struct Alternate { - cfg: PhantomData, -} - -impl Sealed for Alternate {} - -pub type AltFunc1 = Alternate; -pub type AltFunc2 = Alternate; -pub type AltFunc3 = Alternate; - -/// Type alias for the [`PinMode`] at reset -pub type Reset = InputFloating; - -//================================================================================================== -// Pin modes -//================================================================================================== - -/// Type-level enum representing pin modes -/// -/// The valid options are [Input], [Output] and [Alternate]. -pub trait PinMode: Sealed { - /// Corresponding [DynPinMode] - const DYN: DynPinMode; -} - -impl PinMode for Input { - const DYN: DynPinMode = DynPinMode::Input(C::DYN); -} -impl PinMode for Output { - const DYN: DynPinMode = DynPinMode::Output(C::DYN); -} -impl PinMode for Alternate { - const DYN: DynPinMode = DynPinMode::Alternate(C::DYN); -} - -//================================================================================================== -// Pin IDs -//================================================================================================== - -/// Type-level enum for pin IDs -pub trait PinId: Sealed { - /// Corresponding [DynPinId] - const DYN: DynPinId; -} - -macro_rules! pin_id { - ($Group:ident, $Id:ident, $NUM:literal) => { - // Need paste macro to use ident in doc attribute - paste! { - #[doc = "Pin ID representing pin " $Id] - #[derive(Debug)] - pub enum $Id {} - impl Sealed for $Id {} - impl PinId for $Id { - const DYN: DynPinId = DynPinId::new(Port::$Group, $NUM); - } - } - }; -} - -//================================================================================================== -// Pin -//================================================================================================== - -/// A type-level GPIO pin, parameterized by [PinId] and [PinMode] types -#[derive(Debug)] -pub struct Pin { - inner: DynPin, - phantom: PhantomData<(I, M)>, -} - -impl Pin { - /// Create a new [Pin] - /// - /// # Safety - /// - /// Each [Pin] must be a singleton. For a given [PinId], there must be - /// at most one corresponding [Pin] in existence at any given time. - /// Violating this requirement is `unsafe`. - #[inline] - pub(crate) const unsafe fn new() -> Pin { - Pin { - inner: DynPin::new(I::DYN, M::DYN), - phantom: PhantomData, - } - } - - #[inline] - pub const fn id(&self) -> DynPinId { - self.inner.id() - } - - /// Convert the pin to the requested [`PinMode`] - #[inline] - pub fn into_mode(mut self) -> Pin { - // Only modify registers if we are actually changing pin mode - // This check should compile away - if N::DYN != M::DYN { - self.inner.change_mode(N::DYN); - } - // Safe because we drop the existing Pin - unsafe { Pin::new() } - } - - /// Configure the pin for function select 1. See Programmer Guide p.40 for the function table - #[inline] - pub fn into_funsel_1(self) -> Pin { - self.into_mode() - } - - /// Configure the pin for function select 2. See Programmer Guide p.40 for the function table - #[inline] - pub fn into_funsel_2(self) -> Pin { - self.into_mode() - } - - /// Configure the pin for function select 3. See Programmer Guide p.40 for the function table - #[inline] - pub fn into_funsel_3(self) -> Pin { - self.into_mode() - } - - /// Configure the pin to operate as a floating input - #[inline] - pub fn into_floating_input(self) -> Pin { - self.into_mode() - } - - /// Configure the pin to operate as a pulled down input - #[inline] - pub fn into_pull_down_input(self) -> Pin { - self.into_mode() - } - - /// Configure the pin to operate as a pulled up input - #[inline] - pub fn into_pull_up_input(self) -> Pin { - self.into_mode() - } - - /// Configure the pin to operate as a push-pull output - #[inline] - pub fn into_push_pull_output(self) -> Pin { - self.into_mode() - } - - /// Configure the pin to operate as a readable push-pull output - #[inline] - pub fn into_readable_push_pull_output(self) -> Pin { - self.into_mode() - } - - /// Configure the pin to operate as a readable open-drain output - #[inline] - pub fn into_readable_open_drain_output(self) -> Pin { - self.into_mode() - } - - #[inline] - pub fn is_low(&self) -> bool { - !self.inner.read_pin() - } - - #[inline] - pub fn is_high(&self) -> bool { - self.inner.read_pin() - } - - #[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 { - self.inner.is_high_masked() - } - - #[inline] - pub fn is_low_masked(&self) -> Result { - self.inner.is_low_masked() - } - - #[inline] - pub fn downgrade(self) -> DynPin { - self.inner - } - - // Those only serve for the embedded HAL implementations which have different mutability. - - #[inline] - fn is_low_mut(&mut self) -> bool { - self.is_low() - } - - #[inline] - fn is_high_mut(&mut self) -> bool { - self.is_high() - } - - #[inline] - pub fn enable_interrupt(&mut self, irq_cfg: crate::InterruptConfig) { - self.inner.enable_interrupt(irq_cfg); - } - - #[inline] - pub fn disable_interrupt(&mut self, reset_irqsel: bool) { - self.inner.disable_interrupt(reset_irqsel); - } - - /// Configure the pin for an edge interrupt but does not enable the interrupt. - pub fn configure_edge_interrupt(&mut self, edge_type: InterruptEdge) { - self.inner.configure_edge_interrupt(edge_type).unwrap(); - } - - /// Configure the pin for a level interrupt but does not enable the interrupt. - pub fn configure_level_interrupt(&mut self, level_type: InterruptLevel) { - self.inner.configure_level_interrupt(level_type).unwrap(); - } -} - -//============================================================================== -// AnyPin -//============================================================================== - -/// Type class for [`Pin`] types -/// -/// This trait uses the [`AnyKind`] trait pattern to create a [type class] for -/// [`Pin`] types. See the `AnyKind` documentation for more details on the -/// pattern. -/// -/// ## `v1` Compatibility -/// -/// Normally, this trait would use `Is>` as a super -/// trait. But doing so would restrict implementations to only the `v2` `Pin` -/// type in this module. To aid in backwards compatibility, we want to implement -/// `AnyPin` for the `v1` `Pin` type as well. This is possible for a few -/// reasons. First, both structs are zero-sized, so there is no meaningful -/// memory layout to begin with. And even if there were, the `v1` `Pin` type is -/// a newtype wrapper around a `v2` `Pin`, and single-field structs are -/// guaranteed to have the same layout as the field, even for `repr(Rust)`. -/// -/// [`AnyKind`]: crate::typelevel#anykind-trait-pattern -/// [type class]: crate::typelevel#type-classes -pub trait AnyPin -where - Self: Sealed, - Self: From>, - Self: Into>, - Self: AsRef>, - Self: AsMut>, -{ - /// [`PinId`] of the corresponding [`Pin`] - type Id: PinId; - /// [`PinMode`] of the corresponding [`Pin`] - type Mode: PinMode; -} - -impl Sealed for Pin -where - I: PinId, - M: PinMode, -{ -} - -impl AnyPin for Pin -where - I: PinId, - M: PinMode, -{ - type Id = I; - type Mode = M; -} - -/// Type alias to recover the specific [`Pin`] type from an implementation of -/// [`AnyPin`] -/// -/// See the [`AnyKind`] documentation for more details on the pattern. -/// -/// [`AnyKind`]: crate::typelevel#anykind-trait-pattern -pub type SpecificPin

= Pin<

::Id,

::Mode>; - -impl AsRef

for SpecificPin

{ - #[inline] - fn as_ref(&self) -> &P { - // SAFETY: This is guaranteed to be safe, because P == SpecificPin

- // Transmuting between `v1` and `v2` `Pin` types is also safe, because - // both are zero-sized, and single-field, newtype structs are guaranteed - // to have the same layout as the field anyway, even for repr(Rust). - unsafe { transmute(self) } - } -} - -impl AsMut

for SpecificPin

{ - #[inline] - fn as_mut(&mut self) -> &mut P { - // SAFETY: This is guaranteed to be safe, because P == SpecificPin

- // Transmuting between `v1` and `v2` `Pin` types is also safe, because - // both are zero-sized, and single-field, newtype structs are guaranteed - // to have the same layout as the field anyway, even for repr(Rust). - unsafe { transmute(self) } - } -} - -//================================================================================================== -// Additional functionality -//================================================================================================== - -impl Pin> { - /// Convert the pin into an async pin. The pin can be converted back by calling - /// [InputPinAsync::release] - pub fn into_async_input(self, irq: crate::pac::Interrupt) -> InputPinAsync { - InputPinAsync::new(self, irq) - } -} - -impl Pin> { - #[inline] - pub fn set_high(&mut self) { - self.inner.write_pin(true) - } - - #[inline] - pub fn set_low(&mut self) { - self.inner.write_pin(false) - } - - #[inline] - pub fn toggle(&mut self) { - self.inner.toggle().unwrap() - } - - #[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() - } - - /// See p.53 of the programmers guide for more information. - /// Possible delays in clock cycles: - /// - Delay 1: 1 - /// - Delay 2: 2 - /// - Delay 1 + Delay 2: 3 - #[inline] - pub fn configure_delay(&mut self, delay_1: bool, delay_2: bool) { - self.inner.configure_delay(delay_1, delay_2).unwrap(); - } - - /// 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 - /// one clock cycle before returning to the configured default state - pub fn configure_pulse_mode(&mut self, enable: bool, default_state: PinState) { - self.inner - .configure_pulse_mode(enable, default_state) - .unwrap(); - } -} - -impl Pin> { - /// See p.37 and p.38 of the programmers guide for more information. - #[inline] - pub fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) { - self.inner.configure_filter_type(filter, clksel).unwrap(); - } -} - -//================================================================================================== -// Embedded HAL traits -//================================================================================================== - -impl embedded_hal::digital::ErrorType for Pin -where - I: PinId, - M: PinMode, -{ - type Error = Infallible; -} - -impl embedded_hal::digital::OutputPin for Pin> { - #[inline] - fn set_high(&mut self) -> Result<(), Self::Error> { - self.set_high(); - Ok(()) - } - - #[inline] - fn set_low(&mut self) -> Result<(), Self::Error> { - self.set_low(); - Ok(()) - } -} - -impl embedded_hal::digital::InputPin for Pin> -where - I: PinId, - C: InputConfig, -{ - #[inline] - fn is_high(&mut self) -> Result { - Ok(self.is_high_mut()) - } - #[inline] - fn is_low(&mut self) -> Result { - Ok(self.is_low_mut()) - } -} - -impl embedded_hal::digital::StatefulOutputPin for Pin> -where - I: PinId, - C: OutputConfig + ReadableOutput, -{ - #[inline] - fn is_set_high(&mut self) -> Result { - Ok(self.is_high()) - } - #[inline] - fn is_set_low(&mut self) -> Result { - Ok(self.is_low()) - } - - #[inline] - fn toggle(&mut self) -> Result<(), Self::Error> { - self.toggle(); - Ok(()) - } -} - -//================================================================================================== -// Pin definitions -//================================================================================================== - -macro_rules! pins { - ( - $Port:ident, $PinsName:ident, $($Id:ident,)+, - ) => { - paste!( - /// Collection of all the individual [`Pin`]s for a given port (PORTA or PORTB) - #[derive(Debug)] - pub struct $PinsName { - port: $Port, - $( - #[doc = "Pin " $Id] - pub [<$Id:lower>]: Pin<$Id, Reset>, - )+ - } - - impl $PinsName { - /// Create a new struct containing all the Pins. Passing the IOCONFIG peripheral - /// is optional because it might be required to create pin definitions for both - /// ports. - #[inline] - pub fn new( - syscfg: &mut va108xx::Sysconfig, - port: $Port - ) -> $PinsName { - syscfg.peripheral_clk_enable().modify(|_, w| { - w.[<$Port:lower>]().set_bit(); - w.gpio().set_bit(); - w.ioconfig().set_bit() - }); - $PinsName { - //iocfg, - port, - // Safe because we only create one `Pin` per `PinId` - $( - [<$Id:lower>]: unsafe { Pin::new() }, - )+ - } - } - - /// Get the peripheral ID - /// Safety: Read-only register - pub fn get_perid() -> u32 { - let port = unsafe { &(*$Port::ptr()) }; - port.perid().read().bits() - } - - /// Consumes the Pins struct and returns the port definitions - pub fn release(self) -> $Port { - self.port - } - } - ); - } -} - -macro_rules! declare_pins { - ( - $Group:ident, $PinsName:ident, $Port:ident, [$(($Id:ident, $NUM:literal),)+] - ) => { - pins!($Port, $PinsName, $($Id,)+,); - $( - pin_id!($Group, $Id, $NUM); - )+ - } -} - -declare_pins!( - A, - PinsA, - Porta, - [ - (PA0, 0), - (PA1, 1), - (PA2, 2), - (PA3, 3), - (PA4, 4), - (PA5, 5), - (PA6, 6), - (PA7, 7), - (PA8, 8), - (PA9, 9), - (PA10, 10), - (PA11, 11), - (PA12, 12), - (PA13, 13), - (PA14, 14), - (PA15, 15), - (PA16, 16), - (PA17, 17), - (PA18, 18), - (PA19, 19), - (PA20, 20), - (PA21, 21), - (PA22, 22), - (PA23, 23), - (PA24, 24), - (PA25, 25), - (PA26, 26), - (PA27, 27), - (PA28, 28), - (PA29, 29), - (PA30, 30), - (PA31, 31), - ] -); - -declare_pins!( - B, - PinsB, - Portb, - [ - (PB0, 0), - (PB1, 1), - (PB2, 2), - (PB3, 3), - (PB4, 4), - (PB5, 5), - (PB6, 6), - (PB7, 7), - (PB8, 8), - (PB9, 9), - (PB10, 10), - (PB11, 11), - (PB12, 12), - (PB13, 13), - (PB14, 14), - (PB15, 15), - (PB16, 16), - (PB17, 17), - (PB18, 18), - (PB19, 19), - (PB20, 20), - (PB21, 21), - (PB22, 22), - (PB23, 23), - ] -); diff --git a/va108xx-hal/src/i2c.rs b/va108xx-hal/src/i2c.rs index 83668be..55eec0f 100644 --- a/va108xx-hal/src/i2c.rs +++ b/va108xx-hal/src/i2c.rs @@ -15,6 +15,13 @@ const CLK_100K: Hertz = Hertz::from_raw(100_000); const CLK_400K: Hertz = Hertz::from_raw(400_000); const MIN_CLK_400K: Hertz = Hertz::from_raw(8_000_000); +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum I2cId { + A = 0, + B = 1, +} + #[derive(Debug, PartialEq, Eq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum FifoEmptyMode { @@ -111,16 +118,18 @@ pub type I2cRegBlock = pac::i2ca::RegisterBlock; /// Common trait implemented by all PAC peripheral access structures. The register block /// format is the same for all SPI blocks. -pub trait Instance: Deref { - const IDX: u8; +pub trait I2cMarker: Deref { + const ID: I2cId; const PERIPH_SEL: PeripheralSelect; + const PTR: *const I2cRegBlock; fn ptr() -> *const I2cRegBlock; } -impl Instance for pac::I2ca { - const IDX: u8 = 0; +impl I2cMarker for pac::I2ca { + const ID: I2cId = I2cId::A; const PERIPH_SEL: PeripheralSelect = PeripheralSelect::I2c0; + const PTR: *const I2cRegBlock = Self::PTR; #[inline(always)] fn ptr() -> *const I2cRegBlock { @@ -128,9 +137,10 @@ impl Instance for pac::I2ca { } } -impl Instance for pac::I2cb { - const IDX: u8 = 1; +impl I2cMarker for pac::I2cb { + const ID: I2cId = I2cId::B; const PERIPH_SEL: PeripheralSelect = PeripheralSelect::I2c1; + const PTR: *const I2cRegBlock = Self::PTR; #[inline(always)] fn ptr() -> *const I2cRegBlock { @@ -290,32 +300,27 @@ impl Sealed for SlaveConfig {} // I2C Base //================================================================================================== -pub struct I2cBase { - i2c: I2C, +pub struct I2cCommon { + id: I2cId, + reg_block: *const I2cRegBlock, sys_clk: Hertz, } -impl I2cBase { - #[inline] - fn unwrap_addr(addr: I2cAddress) -> (u16, u32) { - match addr { - I2cAddress::Regular(addr) => (addr as u16, 0 << 15), - I2cAddress::TenBit(addr) => (addr, 1 << 15), - } - } -} - -impl I2cBase { - pub fn new( +impl I2cCommon { + pub fn new( sys_clk: Hertz, - i2c: I2c, + _i2c: I2c, speed_mode: I2cSpeed, ms_cfg: Option<&MasterConfig>, sl_cfg: Option<&SlaveConfig>, ) -> Result { enable_peripheral_clock(I2c::PERIPH_SEL); - let mut i2c_base = I2cBase { i2c, sys_clk }; + let mut i2c_base = I2cCommon { + id: I2c::ID, + reg_block: I2c::PTR, + sys_clk, + }; if let Some(ms_cfg) = ms_cfg { i2c_base.cfg_master(ms_cfg); } @@ -327,6 +332,32 @@ impl I2cBase { Ok(i2c_base) } + pub fn id(&self) -> I2cId { + self.id + } + + // Returns the address and the address mode bit. + #[inline] + fn unwrap_addr(addr: I2cAddress) -> (u16, u32) { + match addr { + I2cAddress::Regular(addr) => (addr as u16, 0 << 15), + I2cAddress::TenBit(addr) => (addr, 1 << 15), + } + } + + /// Retrieve the raw register block. + /// + /// # Safety + /// + /// Circumvents safety guarantees by the HAL. + pub const unsafe fn regs(&self) -> &'static I2cRegBlock { + self.regs_priv() + } + + const fn regs_priv(&self) -> &'static I2cRegBlock { + unsafe { &*self.reg_block } + } + fn cfg_master(&mut self, ms_cfg: &MasterConfig) { let (txfemd, rxfemd) = match (ms_cfg.tx_fe_mode, ms_cfg.rx_fe_mode) { (FifoEmptyMode::Stall, FifoEmptyMode::Stall) => (false, false), @@ -334,18 +365,17 @@ impl I2cBase { (FifoEmptyMode::EndTransaction, FifoEmptyMode::Stall) => (true, false), (FifoEmptyMode::EndTransaction, FifoEmptyMode::EndTransaction) => (true, true), }; - self.i2c.ctrl().modify(|_, w| { + let regs = self.regs_priv(); + regs.ctrl().modify(|_, w| { w.txfemd().bit(txfemd); w.rxffmd().bit(rxfemd); w.dlgfilter().bit(ms_cfg.dlg_filt); w.algfilter().bit(ms_cfg.alg_filt) }); if let Some(ref tm_cfg) = ms_cfg.tm_cfg { - self.i2c - .tmconfig() - .write(|w| unsafe { w.bits(tm_cfg.reg()) }); + regs.tmconfig().write(|w| unsafe { w.bits(tm_cfg.reg()) }); } - self.i2c.fifo_clr().write(|w| { + regs.fifo_clr().write(|w| { w.rxfifo().set_bit(); w.txfifo().set_bit() }); @@ -358,47 +388,43 @@ impl I2cBase { (FifoEmptyMode::EndTransaction, FifoEmptyMode::Stall) => (true, false), (FifoEmptyMode::EndTransaction, FifoEmptyMode::EndTransaction) => (true, true), }; - self.i2c.s0_ctrl().modify(|_, w| { + let regs = self.regs_priv(); + regs.s0_ctrl().modify(|_, w| { w.txfemd().bit(txfemd); w.rxffmd().bit(rxfemd) }); - self.i2c.s0_fifo_clr().write(|w| { + regs.s0_fifo_clr().write(|w| { w.rxfifo().set_bit(); w.txfifo().set_bit() }); let max_words = sl_cfg.max_words; if let Some(max_words) = max_words { - self.i2c - .s0_maxwords() + regs.s0_maxwords() .write(|w| unsafe { w.bits((1 << 31) | max_words as u32) }); } let (addr, addr_mode_mask) = Self::unwrap_addr(sl_cfg.addr); // The first bit is the read/write value. Normally, both read and write are matched // using the RWMASK bit of the address mask register - self.i2c - .s0_address() + regs.s0_address() .write(|w| unsafe { w.bits((addr << 1) as u32 | addr_mode_mask) }); if let Some(addr_mask) = sl_cfg.addr_mask { - self.i2c - .s0_addressmask() + regs.s0_addressmask() .write(|w| unsafe { w.bits((addr_mask << 1) as u32) }); } if let Some(addr_b) = sl_cfg.addr_b { let (addr, addr_mode_mask) = Self::unwrap_addr(addr_b); - self.i2c - .s0_addressb() + regs.s0_addressb() .write(|w| unsafe { w.bits((addr << 1) as u32 | addr_mode_mask) }); } if let Some(addr_b_mask) = sl_cfg.addr_b_mask { - self.i2c - .s0_addressmaskb() + regs.s0_addressmaskb() .write(|w| unsafe { w.bits((addr_b_mask << 1) as u32) }); } } #[inline] pub fn filters(&mut self, digital_filt: bool, analog_filt: bool) { - self.i2c.ctrl().modify(|_, w| { + self.regs_priv().ctrl().modify(|_, w| { w.dlgfilter().bit(digital_filt); w.algfilter().bit(analog_filt) }); @@ -406,7 +432,7 @@ impl I2cBase { #[inline] pub fn fifo_empty_mode(&mut self, rx: FifoEmptyMode, tx: FifoEmptyMode) { - self.i2c.ctrl().modify(|_, w| { + self.regs_priv().ctrl().modify(|_, w| { w.txfemd().bit(tx as u8 != 0); w.rxffmd().bit(rx as u8 != 0) }); @@ -429,7 +455,7 @@ impl I2cBase { speed_mode: I2cSpeed, ) -> Result<(), ClockTooSlowForFastI2cError> { let clk_div = self.calc_clk_div(speed_mode)?; - self.i2c + self.regs_priv() .clkscale() .write(|w| unsafe { w.bits(((speed_mode as u32) << 31) | clk_div as u32) }); Ok(()) @@ -437,14 +463,14 @@ impl I2cBase { pub fn load_address(&mut self, addr: u16) { // Load address - self.i2c + self.regs_priv() .address() .write(|w| unsafe { w.bits((addr << 1) as u32) }); } #[inline] fn stop_cmd(&mut self) { - self.i2c + self.regs_priv() .cmd() .write(|w| unsafe { w.bits(I2cCmd::Stop as u32) }); } @@ -454,20 +480,20 @@ impl I2cBase { // I2C Master //================================================================================================== -pub struct I2cMaster { - i2c_base: I2cBase, +pub struct I2cMaster { + inner: I2cCommon, addr: PhantomData, } -impl I2cMaster { - pub fn new( +impl I2cMaster { + pub fn new( sysclk: Hertz, i2c: I2c, cfg: MasterConfig, speed_mode: I2cSpeed, ) -> Result { Ok(I2cMaster { - i2c_base: I2cBase::new(sysclk, i2c, speed_mode, Some(&cfg), None)?, + inner: I2cCommon::new(sysclk, i2c, speed_mode, Some(&cfg), None)?, addr: PhantomData, } .enable_master()) @@ -475,32 +501,41 @@ impl I2cMaster { #[inline] pub fn cancel_transfer(&self) { - self.i2c_base - .i2c + self.inner + .regs_priv() .cmd() .write(|w| unsafe { w.bits(I2cCmd::Cancel as u32) }); } #[inline] pub fn clear_tx_fifo(&self) { - self.i2c_base.i2c.fifo_clr().write(|w| w.txfifo().set_bit()); + self.inner + .regs_priv() + .fifo_clr() + .write(|w| w.txfifo().set_bit()); } #[inline] pub fn clear_rx_fifo(&self) { - self.i2c_base.i2c.fifo_clr().write(|w| w.rxfifo().set_bit()); + self.inner + .regs_priv() + .fifo_clr() + .write(|w| w.rxfifo().set_bit()); } #[inline] pub fn enable_master(self) -> Self { - self.i2c_base.i2c.ctrl().modify(|_, w| w.enable().set_bit()); + self.inner + .regs_priv() + .ctrl() + .modify(|_, w| w.enable().set_bit()); self } #[inline] pub fn disable_master(self) -> Self { - self.i2c_base - .i2c + self.inner + .regs_priv() .ctrl() .modify(|_, w| w.enable().clear_bit()); self @@ -508,21 +543,21 @@ impl I2cMaster { #[inline(always)] fn load_fifo(&self, word: u8) { - self.i2c_base - .i2c + self.inner + .regs_priv() .data() .write(|w| unsafe { w.bits(word as u32) }); } #[inline(always)] fn read_fifo(&self) -> u8 { - self.i2c_base.i2c.data().read().bits() as u8 + self.inner.regs_priv().data().read().bits() as u8 } fn error_handler_write(&mut self, init_cmd: &I2cCmd) { self.clear_tx_fifo(); if *init_cmd == I2cCmd::Start { - self.i2c_base.stop_cmd() + self.inner.stop_cmd() } } @@ -534,13 +569,13 @@ impl I2cMaster { ) -> Result<(), Error> { let mut iter = bytes.into_iter(); // Load address - let (addr, addr_mode_bit) = I2cBase::::unwrap_addr(addr); - self.i2c_base.i2c.address().write(|w| unsafe { + let (addr, addr_mode_bit) = I2cCommon::unwrap_addr(addr); + self.inner.regs_priv().address().write(|w| unsafe { w.bits(I2cDirection::Send as u32 | (addr << 1) as u32 | addr_mode_bit) }); - self.i2c_base - .i2c + self.inner + .regs_priv() .cmd() .write(|w| unsafe { w.bits(init_cmd as u32) }); let mut load_if_next_available = || { @@ -549,7 +584,7 @@ impl I2cMaster { } }; loop { - let status_reader = self.i2c_base.i2c.status().read(); + let status_reader = self.inner.regs_priv().status().read(); if status_reader.arblost().bit_is_set() { self.error_handler_write(&init_cmd); return Err(Error::ArbitrationLost); @@ -584,8 +619,8 @@ impl I2cMaster { return Err(Error::DataTooLarge); } // Load number of words - self.i2c_base - .i2c + self.inner + .regs_priv() .words() .write(|w| unsafe { w.bits(len as u32) }); let mut bytes = output.iter(); @@ -614,8 +649,8 @@ impl I2cMaster { self.clear_rx_fifo(); // Load number of words - self.i2c_base - .i2c + self.inner + .regs_priv() .words() .write(|w| unsafe { w.bits(len as u32) }); let (addr, addr_mode_bit) = match addr { @@ -623,15 +658,15 @@ impl I2cMaster { I2cAddress::TenBit(addr) => (addr, 1 << 15), }; // Load address - self.i2c_base.i2c.address().write(|w| unsafe { + self.inner.regs_priv().address().write(|w| unsafe { w.bits(I2cDirection::Read as u32 | (addr << 1) as u32 | addr_mode_bit) }); let mut buf_iter = buffer.iter_mut(); let mut read_bytes = 0; // Start receive transfer - self.i2c_base - .i2c + self.inner + .regs_priv() .cmd() .write(|w| unsafe { w.bits(I2cCmd::StartWithStop as u32) }); let mut read_if_next_available = || { @@ -640,7 +675,7 @@ impl I2cMaster { } }; loop { - let status_reader = self.i2c_base.i2c.status().read(); + let status_reader = self.inner.regs_priv().status().read(); if status_reader.arblost().bit_is_set() { self.clear_rx_fifo(); return Err(Error::ArbitrationLost); @@ -664,11 +699,11 @@ impl I2cMaster { // Embedded HAL I2C implementations //====================================================================================== -impl embedded_hal::i2c::ErrorType for I2cMaster { +impl embedded_hal::i2c::ErrorType for I2cMaster { type Error = Error; } -impl embedded_hal::i2c::I2c for I2cMaster { +impl embedded_hal::i2c::I2c for I2cMaster { fn transaction( &mut self, address: SevenBitAddress, @@ -688,11 +723,11 @@ impl embedded_hal::i2c::I2c for I2cMaster { } } -impl embedded_hal::i2c::ErrorType for I2cMaster { +impl embedded_hal::i2c::ErrorType for I2cMaster { type Error = Error; } -impl embedded_hal::i2c::I2c for I2cMaster { +impl embedded_hal::i2c::I2c for I2cMaster { fn transaction( &mut self, address: TenBitAddress, @@ -714,20 +749,20 @@ impl embedded_hal::i2c::I2c for I2cMaster { - i2c_base: I2cBase, +pub struct I2cSlave { + inner: I2cCommon, addr: PhantomData, } -impl I2cSlave { - fn new_generic( +impl I2cSlave { + fn new_generic( sys_clk: Hertz, i2c: I2c, cfg: SlaveConfig, speed_mode: I2cSpeed, ) -> Result { Ok(I2cSlave { - i2c_base: I2cBase::new(sys_clk, i2c, speed_mode, None, Some(&cfg))?, + inner: I2cCommon::new(sys_clk, i2c, speed_mode, None, Some(&cfg))?, addr: PhantomData, } .enable_slave()) @@ -735,8 +770,8 @@ impl I2cSlave { #[inline] pub fn enable_slave(self) -> Self { - self.i2c_base - .i2c + self.inner + .regs_priv() .s0_ctrl() .modify(|_, w| w.enable().set_bit()); self @@ -744,8 +779,8 @@ impl I2cSlave { #[inline] pub fn disable_slave(self) -> Self { - self.i2c_base - .i2c + self.inner + .regs_priv() .s0_ctrl() .modify(|_, w| w.enable().clear_bit()); self @@ -753,29 +788,29 @@ impl I2cSlave { #[inline(always)] fn load_fifo(&self, word: u8) { - self.i2c_base - .i2c + self.inner + .regs_priv() .s0_data() .write(|w| unsafe { w.bits(word as u32) }); } #[inline(always)] fn read_fifo(&self) -> u8 { - self.i2c_base.i2c.s0_data().read().bits() as u8 + self.inner.regs_priv().s0_data().read().bits() as u8 } #[inline] fn clear_tx_fifo(&self) { - self.i2c_base - .i2c + self.inner + .regs_priv() .s0_fifo_clr() .write(|w| w.txfifo().set_bit()); } #[inline] fn clear_rx_fifo(&self) { - self.i2c_base - .i2c + self.inner + .regs_priv() .s0_fifo_clr() .write(|w| w.rxfifo().set_bit()); } @@ -783,7 +818,7 @@ impl I2cSlave { /// Get the last address that was matched by the slave control and the corresponding /// master direction pub fn last_address(&self) -> (I2cDirection, u32) { - let bits = self.i2c_base.i2c.s0_lastaddress().read().bits(); + let bits = self.inner.regs_priv().s0_lastaddress().read().bits(); match bits & 0x01 { 0 => (I2cDirection::Send, bits >> 1), 1 => (I2cDirection::Read, bits >> 1), @@ -810,7 +845,7 @@ impl I2cSlave { self.load_fifo(*bytes.next().unwrap()); } - let status_reader = self.i2c_base.i2c.s0_status().read(); + let status_reader = self.inner.regs_priv().s0_status().read(); let mut load_if_next_available = || { if let Some(next_byte) = bytes.next() { self.load_fifo(*next_byte); @@ -850,7 +885,7 @@ impl I2cSlave { } }; loop { - let status_reader = self.i2c_base.i2c.s0_status().read(); + let status_reader = self.inner.regs_priv().s0_status().read(); if status_reader.idle().bit_is_set() { if read_bytes != len { return Err(Error::InsufficientDataReceived); @@ -864,9 +899,9 @@ impl I2cSlave { } } -impl I2cSlave { +impl I2cSlave { /// Create a new I2C slave for seven bit addresses - pub fn new( + pub fn new( sys_clk: Hertz, i2c: I2c, cfg: SlaveConfig, @@ -879,8 +914,8 @@ impl I2cSlave { } } -impl I2cSlave { - pub fn new_ten_bit_addr( +impl I2cSlave { + pub fn new_ten_bit_addr( sys_clk: Hertz, i2c: I2c, cfg: SlaveConfig, diff --git a/va108xx-hal/src/pwm.rs b/va108xx-hal/src/pwm.rs index 70e6ba6..e51d0ca 100644 --- a/va108xx-hal/src/pwm.rs +++ b/va108xx-hal/src/pwm.rs @@ -8,6 +8,7 @@ use core::convert::Infallible; use core::marker::PhantomData; +use vorago_shared_periphs::gpio::IoPeriphPin; use vorago_shared_periphs::PeripheralSelect; use crate::clock::enable_peripheral_clock; @@ -60,7 +61,7 @@ impl PwmPin { pub fn new( sys_clk: Hertz, pin_and_tim: (Pin, Tim), - initial_period: impl Into + Copy, + initial_frequency: Hertz, ) -> Result { if Pin::TIM_ID != Tim::ID { return Err(TimMissmatchError { @@ -68,11 +69,12 @@ impl PwmPin { tim_id: Tim::ID, }); } + IoPeriphPin::new(Pin::PIN_ID, Pin::FUN_SEL, None); let mut pin = PwmPin { tim_id: Tim::ID, current_duty: 0, current_lower_limit: 0, - current_period: initial_period.into(), + current_period: initial_frequency, current_rst_val: 0, sys_clk, mode: PhantomData, @@ -84,7 +86,7 @@ impl PwmPin { .tim_clk_enable() .modify(|r, w| unsafe { w.bits(r.bits() | pin_and_tim.1.mask_32()) }); pin.enable_pwm_a(); - pin.set_period(initial_period); + pin.set_period(initial_frequency); Ok(pin) } diff --git a/va108xx-hal/src/spi/mod.rs b/va108xx-hal/src/spi/mod.rs index 018f622..3340209 100644 --- a/va108xx-hal/src/spi/mod.rs +++ b/va108xx-hal/src/spi/mod.rs @@ -92,6 +92,7 @@ pub type SpiRegBlock = pac::spia::RegisterBlock; pub trait SpiMarker: Deref + Sealed { const ID: SpiId; const PERIPH_SEL: PeripheralSelect; + const PTR: *const SpiRegBlock; fn ptr() -> *const SpiRegBlock; @@ -104,6 +105,7 @@ pub trait SpiMarker: Deref + Sealed { impl SpiMarker for pac::Spia { const ID: SpiId = SpiId::A; const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi0; + const PTR: *const SpiRegBlock = Self::PTR; #[inline(always)] fn ptr() -> *const SpiRegBlock { @@ -115,6 +117,7 @@ impl Sealed for pac::Spia {} impl SpiMarker for pac::Spib { const ID: SpiId = SpiId::B; const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi1; + const PTR: *const SpiRegBlock = Self::PTR; #[inline(always)] fn ptr() -> *const SpiRegBlock { @@ -126,6 +129,7 @@ impl Sealed for pac::Spib {} impl SpiMarker for pac::Spic { const ID: SpiId = SpiId::C; const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi2; + const PTR: *const SpiRegBlock = Self::PTR; #[inline(always)] fn ptr() -> *const SpiRegBlock { @@ -445,7 +449,7 @@ pub struct SpiIdMissmatchError; /// SPI peripheral driver structure. pub struct Spi { id: SpiId, - reg_block: *mut SpiRegBlock, + reg_block: *const SpiRegBlock, cfg: SpiConfig, sys_clk: Hertz, /// Fill word for read-only SPI transactions. @@ -535,7 +539,7 @@ where spi.ctrl1().modify(|_, w| w.enable().set_bit()); Spi { id: SpiI::ID, - reg_block: spi.reg_block(), + reg_block: SpiI::PTR, cfg: spi_cfg, sys_clk, fill_word: Default::default(), @@ -545,11 +549,6 @@ where } } - #[inline(always)] - pub fn reg_block_mut(&mut self) -> &'static mut SpiRegBlock { - unsafe { &mut *(self.reg_block) } - } - #[inline(always)] pub fn reg_block(&self) -> &'static SpiRegBlock { unsafe { &*(self.reg_block) } @@ -612,7 +611,7 @@ where /// corresponding [HwChipSelectId]. #[inline] pub fn cfg_hw_cs(&mut self, hw_cs: HwChipSelectId) { - self.reg_block_mut().ctrl1().modify(|_, w| { + self.reg_block().ctrl1().modify(|_, w| { w.sod().clear_bit(); unsafe { w.ss().bits(hw_cs as u8); @@ -659,8 +658,8 @@ where } fn flush_internal(&mut self) { - let reg_block_mut = self.reg_block_mut(); - let mut status_reg = reg_block_mut.status().read(); + let reg_block = self.reg_block(); + let mut status_reg = reg_block.status().read(); while status_reg.tfe().bit_is_clear() || status_reg.rne().bit_is_set() || status_reg.busy().bit_is_set() @@ -668,7 +667,7 @@ where if status_reg.rne().bit_is_set() { self.read_fifo_unchecked(); } - status_reg = reg_block_mut.status().read(); + status_reg = reg_block.status().read(); } } @@ -683,9 +682,9 @@ where // The FIFO can hold a guaranteed amount of data, so we can pump it on transfer // initialization. Returns the amount of written bytes. fn initial_send_fifo_pumping_with_words(&mut self, words: &[Word]) -> usize { - let reg_block_mut = self.reg_block_mut(); + let reg_block = self.reg_block(); if self.blockmode { - reg_block_mut.ctrl1().modify(|_, w| w.mtxpause().set_bit()); + reg_block.ctrl1().modify(|_, w| w.mtxpause().set_bit()); } // Fill the first half of the write FIFO let mut current_write_idx = 0; @@ -699,7 +698,7 @@ where current_write_idx += 1; } if self.blockmode { - reg_block_mut + reg_block .ctrl1() .modify(|_, w| w.mtxpause().clear_bit()); } @@ -709,9 +708,9 @@ where // The FIFO can hold a guaranteed amount of data, so we can pump it on transfer // initialization. fn initial_send_fifo_pumping_with_fill_words(&mut self, send_len: usize) -> usize { - let reg_block_mut = self.reg_block_mut(); + let reg_block = self.reg_block(); if self.blockmode { - reg_block_mut.ctrl1().modify(|_, w| w.mtxpause().set_bit()); + reg_block.ctrl1().modify(|_, w| w.mtxpause().set_bit()); } // Fill the first half of the write FIFO let mut current_write_idx = 0; @@ -725,7 +724,7 @@ where current_write_idx += 1; } if self.blockmode { - reg_block_mut + reg_block .ctrl1() .modify(|_, w| w.mtxpause().clear_bit()); } @@ -739,7 +738,7 @@ where { #[inline(always)] fn write_fifo(&mut self, data: u32) -> nb::Result<(), Infallible> { - if self.reg_block_mut().status().read().tnf().bit_is_clear() { + if self.reg_block().status().read().tnf().bit_is_clear() { return Err(nb::Error::WouldBlock); } self.write_fifo_unchecked(data); @@ -748,14 +747,14 @@ where #[inline(always)] fn write_fifo_unchecked(&mut self, data: u32) { - self.reg_block_mut() + self.reg_block() .data() .write(|w| unsafe { w.bits(data) }); } #[inline(always)] fn read_fifo(&mut self) -> nb::Result { - if self.reg_block_mut().status().read().rne().bit_is_clear() { + if self.reg_block().status().read().rne().bit_is_clear() { return Err(nb::Error::WouldBlock); } Ok(self.read_fifo_unchecked()) @@ -763,7 +762,7 @@ where #[inline(always)] fn read_fifo_unchecked(&mut self) -> u32 { - self.reg_block_mut().data().read().bits() + self.reg_block().data().read().bits() } } diff --git a/va108xx-hal/src/timer.rs b/va108xx-hal/src/timer.rs index aae37df..4a9f672 100644 --- a/va108xx-hal/src/timer.rs +++ b/va108xx-hal/src/timer.rs @@ -18,10 +18,10 @@ use crate::{ }; use fugit::RateExtU32; use vorago_shared_periphs::{ - gpio::{Pin, PinIdProvider}, + gpio::{Pin, PinId, PinIdProvider}, ioconfig::regs::FunSel, sysconfig::enable_peripheral_clock, - PeripheralSelect, Port, + PeripheralSelect, }; /// Get the peripheral block of a TIM peripheral given the index. @@ -161,8 +161,7 @@ impl CascadeSource { //================================================================================================== pub trait TimPin: Sealed { - const PORT: Port; - const OFFSET: usize; + const PIN_ID: PinId; const FUN_SEL: FunSel; const TIM_ID: TimId; } @@ -221,8 +220,7 @@ macro_rules! pin_and_tim { where $Px: PinIdProvider, { - const PORT: Port = $Px::ID.port(); - const OFFSET: usize = $Px::ID.offset(); + const PIN_ID: PinId = $Px::ID; const FUN_SEL: FunSel = $FunSel; const TIM_ID: TimId = TimId($ID); } diff --git a/vorago-reb1/src/temp_sensor.rs b/vorago-reb1/src/temp_sensor.rs index 23aba34..3bc2a4a 100644 --- a/vorago-reb1/src/temp_sensor.rs +++ b/vorago-reb1/src/temp_sensor.rs @@ -15,7 +15,7 @@ use va108xx_hal::{ const ADT75_I2C_ADDR: u8 = 0b1001000; pub struct Adt75TempSensor { - sensor_if: I2cMaster, + sensor_if: I2cMaster, cmd_buf: [u8; 1], current_reg: RegAddresses, } diff --git a/vorago-shared-periphs/src/gpio/asynch.rs b/vorago-shared-periphs/src/gpio/asynch.rs index 277e76a..6f9c607 100644 --- a/vorago-shared-periphs/src/gpio/asynch.rs +++ b/vorago-shared-periphs/src/gpio/asynch.rs @@ -6,10 +6,6 @@ //! which must be provided for async support to work. However, it provides the //! [on_interrupt_for_async_gpio_for_port] generic interrupt handler. This should be called in all //! IRQ functions which handle any GPIO interrupts with the corresponding [Port] argument. -//! -//! # Example -//! -//! - [Async GPIO example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/embassy/src/bin/async-gpio.rs) use core::future::Future; use embassy_sync::waitqueue::AtomicWaker; diff --git a/vscode/launch.json b/vscode/launch.json index 2d41b88..a57fb55 100644 --- a/vscode/launch.json +++ b/vscode/launch.json @@ -62,34 +62,6 @@ ] } }, - { - "type": "cortex-debug", - "request": "launch", - "name": "Debug RTT", - "servertype": "jlink", - "cwd": "${workspaceRoot}", - "device": "Cortex-M0", - "svdFile": "./va108xx/svd/va108xx.svd.patched", - "preLaunchTask": "rust: cargo build rtt", - "serverArgs": [ - "-jtagconf", - "-1,-1" - ], - "executable": "${workspaceFolder}/target/thumbv6m-none-eabi/debug/examples/rtt-log", - "interface": "jtag", - "runToEntryPoint": "main", - "rttConfig": { - "enabled": true, - "address": "auto", - "decoders": [ - { - "port": 0, - "timestamp": true, - "type": "console" - } - ] - } - }, { "type": "cortex-debug", "request": "launch", diff --git a/vscode/tasks.json b/vscode/tasks.json index 595a42c..5b26aec 100644 --- a/vscode/tasks.json +++ b/vscode/tasks.json @@ -31,20 +31,6 @@ "isDefault": true } }, - { - "label": "rust: cargo build rtt", - "type": "shell", - "command": "~/.cargo/bin/cargo", // note: full path to the cargo - "args": [ - "build", - "--example", - "rtt-log" - ], - "group": { - "kind": "build", - "isDefault": true - } - }, { "label": "rust: cargo build systick", "type": "shell", @@ -319,4 +305,4 @@ ] } ] -} +} \ No newline at end of file