update-gpio-impl #48
@ -26,6 +26,7 @@ defmt = { version = "0.3", optional = true }
|
|||||||
fugit = "0.3"
|
fugit = "0.3"
|
||||||
delegate = "0.12"
|
delegate = "0.12"
|
||||||
void = { version = "1", default-features = false }
|
void = { version = "1", default-features = false }
|
||||||
|
thiserror = { version = "2", default-features = false }
|
||||||
|
|
||||||
[dependencies.va416xx]
|
[dependencies.va416xx]
|
||||||
default-features = false
|
default-features = false
|
||||||
|
@ -30,12 +30,6 @@ rustup target add thumbv7em-none-eabihf
|
|||||||
|
|
||||||
After that, you can use `cargo build` to build the development version of the crate.
|
After that, you can use `cargo build` to build the development version of the crate.
|
||||||
|
|
||||||
If you have not done this yet, it is recommended to read some of the excellent resources
|
|
||||||
available to learn Rust:
|
|
||||||
|
|
||||||
- [Rust Embedded Book](https://docs.rust-embedded.org/book/)
|
|
||||||
- [Rust Discovery Book](https://docs.rust-embedded.org/discovery/)
|
|
||||||
|
|
||||||
## Setting up your own binary crate
|
## Setting up your own binary crate
|
||||||
|
|
||||||
If you have a custom board, you might be interested in setting up a new binary crate for your
|
If you have a custom board, you might be interested in setting up a new binary crate for your
|
||||||
@ -71,3 +65,11 @@ is contained within the
|
|||||||
|
|
||||||
7. Flashing the board might work differently for different boards and there is usually
|
7. Flashing the board might work differently for different boards and there is usually
|
||||||
more than one way. You can find example instructions in primary README.
|
more than one way. You can find example instructions in primary README.
|
||||||
|
|
||||||
|
## Embedded Rust
|
||||||
|
|
||||||
|
If you have not done this yet, it is recommended to read some of the excellent resources
|
||||||
|
available to learn Rust:
|
||||||
|
|
||||||
|
- [Rust Embedded Book](https://docs.rust-embedded.org/book/)
|
||||||
|
- [Rust Discovery Book](https://docs.rust-embedded.org/discovery/)
|
||||||
|
3
va416xx-hal/docs.sh
Executable file
3
va416xx-hal/docs.sh
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
export RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options"
|
||||||
|
cargo +nightly doc --all-features --open
|
@ -1,4 +1,61 @@
|
|||||||
use embedded_hal::digital::{ErrorKind, ErrorType, InputPin, OutputPin, StatefulOutputPin};
|
//! # 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, FloatingInput> = 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 embedded_hal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
reg::RegisterInterface, FilterClkSel, FilterType, InterruptEdge, InterruptLevel, Pin, PinId,
|
reg::RegisterInterface, FilterClkSel, FilterType, InterruptEdge, InterruptLevel, Pin, PinId,
|
||||||
@ -10,7 +67,8 @@ use super::{
|
|||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
/// Value-level `enum` for disabled configurations
|
/// Value-level `enum` for disabled configurations
|
||||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::format))]
|
||||||
pub enum DynDisabled {
|
pub enum DynDisabled {
|
||||||
Floating,
|
Floating,
|
||||||
PullDown,
|
PullDown,
|
||||||
@ -18,7 +76,8 @@ pub enum DynDisabled {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Value-level `enum` for input configurations
|
/// Value-level `enum` for input configurations
|
||||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::format))]
|
||||||
pub enum DynInput {
|
pub enum DynInput {
|
||||||
Floating,
|
Floating,
|
||||||
PullDown,
|
PullDown,
|
||||||
@ -26,7 +85,8 @@ pub enum DynInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Value-level `enum` for output configurations
|
/// Value-level `enum` for output configurations
|
||||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::format))]
|
||||||
pub enum DynOutput {
|
pub enum DynOutput {
|
||||||
PushPull,
|
PushPull,
|
||||||
OpenDrain,
|
OpenDrain,
|
||||||
@ -36,12 +96,32 @@ pub enum DynOutput {
|
|||||||
|
|
||||||
pub type DynAlternate = crate::FunSel;
|
pub type DynAlternate = crate::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
|
// DynPinMode
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
/// Value-level `enum` representing pin modes
|
/// Value-level `enum` representing pin modes
|
||||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::format))]
|
||||||
pub enum DynPinMode {
|
pub enum DynPinMode {
|
||||||
Input(DynInput),
|
Input(DynInput),
|
||||||
Output(DynOutput),
|
Output(DynOutput),
|
||||||
@ -76,7 +156,8 @@ pub const DYN_ALT_FUNC_3: DynPinMode = DynPinMode::Alternate(DynAlternate::Sel3)
|
|||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
/// Value-level `enum` for pin groups
|
/// Value-level `enum` for pin groups
|
||||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::format))]
|
||||||
pub enum DynGroup {
|
pub enum DynGroup {
|
||||||
A,
|
A,
|
||||||
B,
|
B,
|
||||||
@ -88,7 +169,8 @@ pub enum DynGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Value-level `struct` representing pin IDs
|
/// Value-level `struct` representing pin IDs
|
||||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::format))]
|
||||||
pub struct DynPinId {
|
pub struct DynPinId {
|
||||||
pub group: DynGroup,
|
pub group: DynGroup,
|
||||||
pub num: u8,
|
pub num: u8,
|
||||||
@ -102,16 +184,16 @@ pub struct DynPinId {
|
|||||||
///
|
///
|
||||||
/// This `struct` takes ownership of a [`DynPinId`] and provides an API to
|
/// This `struct` takes ownership of a [`DynPinId`] and provides an API to
|
||||||
/// access the corresponding regsiters.
|
/// access the corresponding regsiters.
|
||||||
struct DynRegisters {
|
#[derive(Debug)]
|
||||||
id: DynPinId,
|
#[cfg_attr(feature = "defmt", derive(defmt::format))]
|
||||||
}
|
pub(crate) struct DynRegisters(DynPinId);
|
||||||
|
|
||||||
// [`DynRegisters`] takes ownership of the [`DynPinId`], and [`DynPin`]
|
// [`DynRegisters`] takes ownership of the [`DynPinId`], and [`DynPin`]
|
||||||
// guarantees that each pin is a singleton, so this implementation is safe.
|
// guarantees that each pin is a singleton, so this implementation is safe.
|
||||||
unsafe impl RegisterInterface for DynRegisters {
|
unsafe impl RegisterInterface for DynRegisters {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn id(&self) -> DynPinId {
|
fn id(&self) -> DynPinId {
|
||||||
self.id
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,25 +206,7 @@ impl DynRegisters {
|
|||||||
/// the same [`DynPinId`]
|
/// the same [`DynPinId`]
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn new(id: DynPinId) -> Self {
|
unsafe fn new(id: DynPinId) -> Self {
|
||||||
DynRegisters { id }
|
DynRegisters(id)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//==============================================================================
|
|
||||||
// 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)]
|
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
|
||||||
pub struct InvalidPinTypeError(pub(crate) ());
|
|
||||||
|
|
||||||
impl embedded_hal::digital::Error for InvalidPinTypeError {
|
|
||||||
fn kind(&self) -> embedded_hal::digital::ErrorKind {
|
|
||||||
ErrorKind::Other
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,8 +218,10 @@ impl embedded_hal::digital::Error for InvalidPinTypeError {
|
|||||||
///
|
///
|
||||||
/// This type acts as a type-erased version of [`Pin`]. Every pin is represented
|
/// This type acts as a type-erased version of [`Pin`]. Every pin is represented
|
||||||
/// by the same type, and pins are tracked and distinguished at run-time.
|
/// by the same type, and pins are tracked and distinguished at run-time.
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::format))]
|
||||||
pub struct DynPin {
|
pub struct DynPin {
|
||||||
regs: DynRegisters,
|
pub(crate) regs: DynRegisters,
|
||||||
mode: DynPinMode,
|
mode: DynPinMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +234,7 @@ impl DynPin {
|
|||||||
/// must be at most one corresponding [`DynPin`] in existence at any given
|
/// must be at most one corresponding [`DynPin`] in existence at any given
|
||||||
/// time. Violating this requirement is `unsafe`.
|
/// time. Violating this requirement is `unsafe`.
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn new(id: DynPinId, mode: DynPinMode) -> Self {
|
pub(crate) unsafe fn new(id: DynPinId, mode: DynPinMode) -> Self {
|
||||||
DynPin {
|
DynPin {
|
||||||
regs: DynRegisters::new(id),
|
regs: DynRegisters::new(id),
|
||||||
mode,
|
mode,
|
||||||
@ -178,7 +244,7 @@ impl DynPin {
|
|||||||
/// Return a copy of the pin ID
|
/// Return a copy of the pin ID
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn id(&self) -> DynPinId {
|
pub fn id(&self) -> DynPinId {
|
||||||
self.regs.id
|
self.regs.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a copy of the pin mode
|
/// Return a copy of the pin mode
|
||||||
@ -254,7 +320,45 @@ impl DynPin {
|
|||||||
self.into_mode(DYN_RD_OPEN_DRAIN_OUTPUT);
|
self.into_mode(DYN_RD_OPEN_DRAIN_OUTPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
common_reg_if_functions!();
|
#[inline]
|
||||||
|
pub fn datamask(&self) -> bool {
|
||||||
|
self.regs.datamask()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clear_datamask(&mut self) {
|
||||||
|
self.regs.clear_datamask();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_datamask(&mut self) {
|
||||||
|
self.regs.set_datamask();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_high_masked(&self) -> Result<bool, crate::gpio::IsMaskedError> {
|
||||||
|
self.regs.read_pin_masked()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_low_masked(&self) -> Result<bool, crate::gpio::IsMaskedError> {
|
||||||
|
self.regs.read_pin_masked().map(|v| !v)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_high_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> {
|
||||||
|
self.regs.write_pin_masked(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_low_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> {
|
||||||
|
self.regs.write_pin_masked(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn irq_enb(&mut self) {
|
||||||
|
self.regs.enable_irq();
|
||||||
|
}
|
||||||
|
|
||||||
/// See p.53 of the programmers guide for more information.
|
/// See p.53 of the programmers guide for more information.
|
||||||
/// Possible delays in clock cycles:
|
/// Possible delays in clock cycles:
|
||||||
@ -262,71 +366,78 @@ impl DynPin {
|
|||||||
/// - Delay 2: 2
|
/// - Delay 2: 2
|
||||||
/// - Delay 1 + Delay 2: 3
|
/// - Delay 1 + Delay 2: 3
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn delay(self, delay_1: bool, delay_2: bool) -> Result<Self, InvalidPinTypeError> {
|
pub fn configure_delay(
|
||||||
|
&mut self,
|
||||||
|
delay_1: bool,
|
||||||
|
delay_2: bool,
|
||||||
|
) -> Result<(), InvalidPinTypeError> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
DynPinMode::Output(_) => {
|
DynPinMode::Output(_) => {
|
||||||
self.regs.delay(delay_1, delay_2);
|
self.regs.configure_delay(delay_1, delay_2);
|
||||||
Ok(self)
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => Err(InvalidPinTypeError(())),
|
_ => Err(InvalidPinTypeError(self.mode)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See p.52 of the programmers guide for more information.
|
/// See p.52 of the programmers guide for more information.
|
||||||
/// When configured for pulse mode, a given pin will set the non-default state for exactly
|
/// When configured for pulse mode, a given pin will set the non-default state for exactly
|
||||||
/// one clock cycle before returning to the configured default state
|
/// one clock cycle before returning to the configured default state
|
||||||
pub fn pulse_mode(
|
pub fn configure_pulse_mode(
|
||||||
self,
|
&mut self,
|
||||||
enable: bool,
|
enable: bool,
|
||||||
default_state: PinState,
|
default_state: PinState,
|
||||||
) -> Result<Self, InvalidPinTypeError> {
|
) -> Result<(), InvalidPinTypeError> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
DynPinMode::Output(_) => {
|
DynPinMode::Output(_) => {
|
||||||
self.regs.pulse_mode(enable, default_state);
|
self.regs.configure_pulse_mode(enable, default_state);
|
||||||
Ok(self)
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => Err(InvalidPinTypeError(())),
|
_ => Err(InvalidPinTypeError(self.mode)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See p.37 and p.38 of the programmers guide for more information.
|
/// See p.37 and p.38 of the programmers guide for more information.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn filter_type(
|
pub fn configure_filter_type(
|
||||||
self,
|
&mut self,
|
||||||
filter: FilterType,
|
filter: FilterType,
|
||||||
clksel: FilterClkSel,
|
clksel: FilterClkSel,
|
||||||
) -> Result<Self, InvalidPinTypeError> {
|
) -> Result<(), InvalidPinTypeError> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
DynPinMode::Input(_) => {
|
DynPinMode::Input(_) => {
|
||||||
self.regs.filter_type(filter, clksel);
|
self.regs.configure_filter_type(filter, clksel);
|
||||||
Ok(self)
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => Err(InvalidPinTypeError(())),
|
_ => Err(InvalidPinTypeError(self.mode)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interrupt_edge(mut self, edge_type: InterruptEdge) -> Result<Self, InvalidPinTypeError> {
|
pub fn configure_edge_interrupt(
|
||||||
|
&mut self,
|
||||||
|
edge_type: InterruptEdge,
|
||||||
|
) -> Result<(), InvalidPinTypeError> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
DynPinMode::Input(_) | DynPinMode::Output(_) => {
|
DynPinMode::Input(_) | DynPinMode::Output(_) => {
|
||||||
self.regs.interrupt_edge(edge_type);
|
self.regs.configure_edge_interrupt(edge_type);
|
||||||
self.irq_enb();
|
self.irq_enb();
|
||||||
Ok(self)
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => Err(InvalidPinTypeError(())),
|
_ => Err(InvalidPinTypeError(self.mode)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interrupt_level(
|
pub fn configure_level_interrupt(
|
||||||
mut self,
|
&mut self,
|
||||||
level_type: InterruptLevel,
|
level_type: InterruptLevel,
|
||||||
) -> Result<Self, InvalidPinTypeError> {
|
) -> Result<(), InvalidPinTypeError> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
DynPinMode::Input(_) | DynPinMode::Output(_) => {
|
DynPinMode::Input(_) | DynPinMode::Output(_) => {
|
||||||
self.regs.interrupt_level(level_type);
|
self.regs.configure_level_interrupt(level_type);
|
||||||
self.irq_enb();
|
self.irq_enb();
|
||||||
Ok(self)
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => Err(InvalidPinTypeError(())),
|
_ => Err(InvalidPinTypeError(self.mode)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,7 +447,7 @@ impl DynPin {
|
|||||||
DynPinMode::Input(_) | DYN_RD_OPEN_DRAIN_OUTPUT | DYN_RD_PUSH_PULL_OUTPUT => {
|
DynPinMode::Input(_) | DYN_RD_OPEN_DRAIN_OUTPUT | DYN_RD_PUSH_PULL_OUTPUT => {
|
||||||
Ok(self.regs.read_pin())
|
Ok(self.regs.read_pin())
|
||||||
}
|
}
|
||||||
_ => Err(InvalidPinTypeError(())),
|
_ => Err(InvalidPinTypeError(self.mode)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -346,7 +457,7 @@ impl DynPin {
|
|||||||
self.regs.write_pin(bit);
|
self.regs.write_pin(bit);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => Err(InvalidPinTypeError(())),
|
_ => Err(InvalidPinTypeError(self.mode)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,6 +477,21 @@ impl DynPin {
|
|||||||
fn _set_high(&mut self) -> Result<(), InvalidPinTypeError> {
|
fn _set_high(&mut self) -> Result<(), InvalidPinTypeError> {
|
||||||
self._write(true)
|
self._write(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try to recreate a type-level [`Pin`] from a value-level [`DynPin`]
|
||||||
|
///
|
||||||
|
/// There is no way for the compiler to know if the conversion will be
|
||||||
|
/// successful at compile-time. We must verify the conversion at run-time
|
||||||
|
/// or refuse to perform it.
|
||||||
|
#[inline]
|
||||||
|
pub fn upgrade<I: PinId, M: PinMode>(self) -> Result<Pin<I, M>, InvalidPinTypeError> {
|
||||||
|
if self.regs.0 == 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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
@ -380,10 +506,8 @@ where
|
|||||||
/// Erase the type-level information in a [`Pin`] and return a value-level
|
/// Erase the type-level information in a [`Pin`] and return a value-level
|
||||||
/// [`DynPin`]
|
/// [`DynPin`]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(_pin: Pin<I, M>) -> Self {
|
fn from(pin: Pin<I, M>) -> Self {
|
||||||
// The `Pin` is consumed, so it is safe to replace it with the
|
pin.downgrade()
|
||||||
// corresponding `DynPin`
|
|
||||||
unsafe { DynPin::new(I::DYN, M::DYN) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,13 +525,7 @@ where
|
|||||||
/// or refuse to perform it.
|
/// or refuse to perform it.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn try_from(pin: DynPin) -> Result<Self, Self::Error> {
|
fn try_from(pin: DynPin) -> Result<Self, Self::Error> {
|
||||||
if pin.regs.id == I::DYN && pin.mode == M::DYN {
|
pin.upgrade()
|
||||||
// The `DynPin` is consumed, so it is safe to replace it with the
|
|
||||||
// corresponding `Pin`
|
|
||||||
Ok(unsafe { Self::new() })
|
|
||||||
} else {
|
|
||||||
Err(InvalidPinTypeError(()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,57 +21,11 @@
|
|||||||
//! ## Examples
|
//! ## Examples
|
||||||
//!
|
//!
|
||||||
//! - [Blinky example](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/examples/simple/examples/blinky.rs)
|
//! - [Blinky example](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/examples/simple/examples/blinky.rs)
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
#[error("pin is masked")]
|
||||||
pub struct IsMaskedError;
|
pub struct IsMaskedError;
|
||||||
|
|
||||||
macro_rules! common_reg_if_functions {
|
|
||||||
() => {
|
|
||||||
paste::paste!(
|
|
||||||
#[inline]
|
|
||||||
pub fn datamask(&self) -> bool {
|
|
||||||
self.regs.datamask()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn clear_datamask(self) -> Self {
|
|
||||||
self.regs.clear_datamask();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn set_datamask(self) -> Self {
|
|
||||||
self.regs.set_datamask();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn is_high_masked(&self) -> Result<bool, crate::gpio::IsMaskedError> {
|
|
||||||
self.regs.read_pin_masked()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn is_low_masked(&self) -> Result<bool, crate::gpio::IsMaskedError> {
|
|
||||||
self.regs.read_pin_masked().map(|v| !v)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn set_high_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> {
|
|
||||||
self.regs.write_pin_masked(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn set_low_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> {
|
|
||||||
self.regs.write_pin_masked(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn irq_enb(&mut self) {
|
|
||||||
self.regs.enable_irq();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod pin;
|
pub mod pin;
|
||||||
pub use pin::*;
|
pub use pin::*;
|
||||||
|
|
||||||
|
@ -78,7 +78,8 @@ use embedded_hal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin};
|
|||||||
use va416xx::{Porta, Portb, Portc, Portd, Porte, Portf, Portg};
|
use va416xx::{Porta, Portb, Portc, Portd, Porte, Portf, Portg};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
reg::RegisterInterface, DynAlternate, DynGroup, DynInput, DynOutput, DynPinId, DynPinMode,
|
reg::RegisterInterface, DynAlternate, DynGroup, DynInput, DynOutput, DynPin, DynPinId,
|
||||||
|
DynPinMode,
|
||||||
};
|
};
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
@ -86,6 +87,7 @@ use super::{
|
|||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum InterruptEdge {
|
pub enum InterruptEdge {
|
||||||
HighToLow,
|
HighToLow,
|
||||||
LowToHigh,
|
LowToHigh,
|
||||||
@ -93,12 +95,14 @@ pub enum InterruptEdge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum InterruptLevel {
|
pub enum InterruptLevel {
|
||||||
Low = 0,
|
Low = 0,
|
||||||
High = 1,
|
High = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum PinState {
|
pub enum PinState {
|
||||||
Low = 0,
|
Low = 0,
|
||||||
High = 1,
|
High = 1,
|
||||||
@ -321,9 +325,10 @@ macro_rules! pin_id {
|
|||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
/// A type-level GPIO pin, parameterized by [`PinId`] and [`PinMode`] types
|
/// A type-level GPIO pin, parameterized by [`PinId`] and [`PinMode`] types
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Pin<I: PinId, M: PinMode> {
|
pub struct Pin<I: PinId, M: PinMode> {
|
||||||
pub(in crate::gpio) regs: Registers<I>,
|
inner: DynPin,
|
||||||
mode: PhantomData<M>,
|
mode: PhantomData<(I, M)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: PinId, M: PinMode> Pin<I, M> {
|
impl<I: PinId, M: PinMode> Pin<I, M> {
|
||||||
@ -337,18 +342,23 @@ impl<I: PinId, M: PinMode> Pin<I, M> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) unsafe fn new() -> Pin<I, M> {
|
pub(crate) unsafe fn new() -> Pin<I, M> {
|
||||||
Pin {
|
Pin {
|
||||||
regs: Registers::new(),
|
inner: DynPin::new(I::DYN, M::DYN),
|
||||||
mode: PhantomData,
|
mode: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn id(&self) -> DynPinId {
|
||||||
|
self.inner.id()
|
||||||
|
}
|
||||||
|
|
||||||
/// Convert the pin to the requested [`PinMode`]
|
/// Convert the pin to the requested [`PinMode`]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn into_mode<N: PinMode>(mut self) -> Pin<I, N> {
|
pub fn into_mode<N: PinMode>(mut self) -> Pin<I, N> {
|
||||||
// Only modify registers if we are actually changing pin mode
|
// Only modify registers if we are actually changing pin mode
|
||||||
// This check should compile away
|
// This check should compile away
|
||||||
if N::DYN != M::DYN {
|
if N::DYN != M::DYN {
|
||||||
self.regs.change_mode::<N>();
|
self.inner.regs.change_mode(N::DYN);
|
||||||
}
|
}
|
||||||
// Safe because we drop the existing Pin
|
// Safe because we drop the existing Pin
|
||||||
unsafe { Pin::new() }
|
unsafe { Pin::new() }
|
||||||
@ -408,26 +418,68 @@ impl<I: PinId, M: PinMode> Pin<I, M> {
|
|||||||
self.into_mode()
|
self.into_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
common_reg_if_functions!();
|
#[inline]
|
||||||
|
pub fn datamask(&self) -> bool {
|
||||||
|
self.inner.datamask()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clear_datamask(&mut self) {
|
||||||
|
self.inner.clear_datamask()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_datamask(&mut self) {
|
||||||
|
self.inner.set_datamask()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_high_masked(&self) -> Result<bool, crate::gpio::IsMaskedError> {
|
||||||
|
self.inner.is_high_masked()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_low_masked(&self) -> Result<bool, crate::gpio::IsMaskedError> {
|
||||||
|
self.inner.is_low_masked()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_high_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> {
|
||||||
|
self.inner.set_high_masked()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_low_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> {
|
||||||
|
self.inner.set_low_masked()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn downgrade(self) -> DynPin {
|
||||||
|
self.inner
|
||||||
|
}
|
||||||
|
|
||||||
|
fn irq_enb(&mut self) {
|
||||||
|
self.inner.irq_enb();
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn _set_high(&mut self) {
|
pub(crate) fn _set_high(&mut self) {
|
||||||
self.regs.write_pin(true)
|
self.inner.regs.write_pin(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn _set_low(&mut self) {
|
pub(crate) fn _set_low(&mut self) {
|
||||||
self.regs.write_pin(false)
|
self.inner.regs.write_pin(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn _is_low(&self) -> bool {
|
pub(crate) fn _is_low(&self) -> bool {
|
||||||
!self.regs.read_pin()
|
!self.inner.regs.read_pin()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn _is_high(&self) -> bool {
|
pub(crate) fn _is_high(&self) -> bool {
|
||||||
self.regs.read_pin()
|
self.inner.regs.read_pin()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -519,16 +571,14 @@ impl<P: AnyPin> AsMut<P> for SpecificPin<P> {
|
|||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
||||||
pub fn interrupt_edge(mut self, edge_type: InterruptEdge) -> Self {
|
pub fn configure_edge_interrupt(&mut self, edge_type: InterruptEdge) {
|
||||||
self.regs.interrupt_edge(edge_type);
|
self.inner.regs.configure_edge_interrupt(edge_type);
|
||||||
self.irq_enb();
|
self.irq_enb();
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interrupt_level(mut self, level_type: InterruptLevel) -> Self {
|
pub fn configure_interrupt_level(&mut self, level_type: InterruptLevel) {
|
||||||
self.regs.interrupt_level(level_type);
|
self.inner.regs.configure_level_interrupt(level_type);
|
||||||
self.irq_enb();
|
self.irq_enb();
|
||||||
self
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -539,38 +589,38 @@ impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
|
|||||||
/// - Delay 2: 2
|
/// - Delay 2: 2
|
||||||
/// - Delay 1 + Delay 2: 3
|
/// - Delay 1 + Delay 2: 3
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn delay(self, delay_1: bool, delay_2: bool) -> Self {
|
pub fn configure_delay(&mut self, delay_1: bool, delay_2: bool) {
|
||||||
self.regs.delay(delay_1, delay_2);
|
self.inner.regs.configure_delay(delay_1, delay_2);
|
||||||
self
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn toggle_with_toggle_reg(&mut self) {
|
||||||
|
self.inner.regs.toggle()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See p.52 of the programmers guide for more information.
|
/// See p.52 of the programmers guide for more information.
|
||||||
/// When configured for pulse mode, a given pin will set the non-default state for exactly
|
/// When configured for pulse mode, a given pin will set the non-default state for exactly
|
||||||
/// one clock cycle before returning to the configured default state
|
/// one clock cycle before returning to the configured default state
|
||||||
pub fn pulse_mode(self, enable: bool, default_state: PinState) -> Self {
|
pub fn configure_pulse_mode(&mut self, enable: bool, default_state: PinState) {
|
||||||
self.regs.pulse_mode(enable, default_state);
|
self.inner.regs.configure_pulse_mode(enable, default_state);
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interrupt_edge(mut self, edge_type: InterruptEdge) -> Self {
|
pub fn configure_edge_interrupt(&mut self, edge_type: InterruptEdge) {
|
||||||
self.regs.interrupt_edge(edge_type);
|
self.inner.regs.configure_edge_interrupt(edge_type);
|
||||||
self.irq_enb();
|
self.irq_enb();
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interrupt_level(mut self, level_type: InterruptLevel) -> Self {
|
pub fn configure_level_interrupt(&mut self, level_type: InterruptLevel) {
|
||||||
self.regs.interrupt_level(level_type);
|
self.inner.regs.configure_level_interrupt(level_type);
|
||||||
self.irq_enb();
|
self.irq_enb();
|
||||||
self
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
||||||
/// See p.37 and p.38 of the programmers guide for more information.
|
/// See p.37 and p.38 of the programmers guide for more information.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn filter_type(self, filter: FilterType, clksel: FilterClkSel) -> Self {
|
pub fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
|
||||||
self.regs.filter_type(filter, clksel);
|
self.inner.regs.configure_filter_type(filter, clksel);
|
||||||
self
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -646,47 +696,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
|
||||||
// Registers
|
|
||||||
//==================================================================================================
|
|
||||||
|
|
||||||
/// Provide a safe register interface for [`Pin`]s
|
|
||||||
///
|
|
||||||
/// This `struct` takes ownership of a [`PinId`] and provides an API to
|
|
||||||
/// access the corresponding registers.
|
|
||||||
pub(in crate::gpio) struct Registers<I: PinId> {
|
|
||||||
id: PhantomData<I>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// [`Registers`] takes ownership of the [`PinId`], and [`Pin`] guarantees that
|
|
||||||
// each pin is a singleton, so this implementation is safe.
|
|
||||||
unsafe impl<I: PinId> RegisterInterface for Registers<I> {
|
|
||||||
#[inline]
|
|
||||||
fn id(&self) -> DynPinId {
|
|
||||||
I::DYN
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: PinId> Registers<I> {
|
|
||||||
/// Create a new instance of [`Registers`]
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// Users must never create two simultaneous instances of this `struct` with
|
|
||||||
/// the same [`PinId`]
|
|
||||||
#[inline]
|
|
||||||
unsafe fn new() -> Self {
|
|
||||||
Registers { id: PhantomData }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Provide a type-level equivalent for the
|
|
||||||
/// [`RegisterInterface::change_mode`] method.
|
|
||||||
#[inline]
|
|
||||||
pub(in crate::gpio) fn change_mode<M: PinMode>(&mut self) {
|
|
||||||
RegisterInterface::change_mode(self, M::DYN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Pin definitions
|
// Pin definitions
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
@ -745,8 +754,6 @@ macro_rules! pins {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//$Group:ident, $PinsName:ident, $Port:ident, [$(($Id:ident, $NUM:literal $(, $meta:meta)?)),+]
|
|
||||||
//$Group:ident, $PinsName:ident, $Port:ident, [$(($Id:ident, $NUM:literal, $meta: meta),)+]
|
|
||||||
macro_rules! declare_pins {
|
macro_rules! declare_pins {
|
||||||
(
|
(
|
||||||
$Group:ident, $PinsName:ident, $Port:ident, [$(($Id:ident, $NUM:literal $(, $meta:meta)?)),+]
|
$Group:ident, $PinsName:ident, $Port:ident, [$(($Id:ident, $NUM:literal $(, $meta:meta)?)),+]
|
||||||
|
@ -144,7 +144,7 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
fn port_reg(&self) -> &PortRegisterBlock {
|
fn port_reg(&self) -> &PortRegisterBlock {
|
||||||
match self.id().group {
|
match self.id().group {
|
||||||
DynGroup::A => unsafe { &(*Porta::ptr()) },
|
DynGroup::A => unsafe { &(*Porta::ptr()) },
|
||||||
@ -157,6 +157,7 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn iocfg_port(&self) -> &PortReg {
|
fn iocfg_port(&self) -> &PortReg {
|
||||||
let ioconfig = unsafe { Ioconfig::ptr().as_ref().unwrap() };
|
let ioconfig = unsafe { Ioconfig::ptr().as_ref().unwrap() };
|
||||||
match self.id().group {
|
match self.id().group {
|
||||||
@ -170,12 +171,12 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
fn mask_32(&self) -> u32 {
|
fn mask_32(&self) -> u32 {
|
||||||
1 << self.id().num
|
1 << self.id().num
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
fn enable_irq(&self) {
|
fn enable_irq(&self) {
|
||||||
self.port_reg()
|
self.port_reg()
|
||||||
.irq_enb()
|
.irq_enb()
|
||||||
@ -241,10 +242,18 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Toggle the logic level of an output pin
|
||||||
|
#[inline(always)]
|
||||||
|
fn toggle(&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
|
/// 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
|
/// When using edge mode, it is possible to generate interrupts on both edges as well
|
||||||
#[inline]
|
#[inline]
|
||||||
fn interrupt_edge(&mut self, edge_type: InterruptEdge) {
|
fn configure_edge_interrupt(&mut self, edge_type: InterruptEdge) {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.port_reg()
|
self.port_reg()
|
||||||
.irq_sen()
|
.irq_sen()
|
||||||
@ -271,7 +280,7 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
|
|
||||||
/// Configure which edge or level type triggers an interrupt
|
/// Configure which edge or level type triggers an interrupt
|
||||||
#[inline]
|
#[inline]
|
||||||
fn interrupt_level(&mut self, level: InterruptLevel) {
|
fn configure_level_interrupt(&mut self, level: InterruptLevel) {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.port_reg()
|
self.port_reg()
|
||||||
.irq_sen()
|
.irq_sen()
|
||||||
@ -290,7 +299,7 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
|
|
||||||
/// Only useful for input pins
|
/// Only useful for input pins
|
||||||
#[inline]
|
#[inline]
|
||||||
fn filter_type(&self, filter: FilterType, clksel: FilterClkSel) {
|
fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
|
||||||
self.iocfg_port().modify(|_, w| {
|
self.iocfg_port().modify(|_, w| {
|
||||||
// Safety: Only write to register for this Pin ID
|
// Safety: Only write to register for this Pin ID
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -328,7 +337,7 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
/// See p.52 of the programmers guide for more information.
|
/// See p.52 of the programmers guide for more information.
|
||||||
/// When configured for pulse mode, a given pin will set the non-default state for exactly
|
/// When configured for pulse mode, a given pin will set the non-default state for exactly
|
||||||
/// one clock cycle before returning to the configured default state
|
/// one clock cycle before returning to the configured default state
|
||||||
fn pulse_mode(&self, enable: bool, default_state: PinState) {
|
fn configure_pulse_mode(&mut self, enable: bool, default_state: PinState) {
|
||||||
let portreg = self.port_reg();
|
let portreg = self.port_reg();
|
||||||
unsafe {
|
unsafe {
|
||||||
if enable {
|
if enable {
|
||||||
@ -353,7 +362,7 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Only useful for output pins
|
/// Only useful for output pins
|
||||||
fn delay(&self, delay_1: bool, delay_2: bool) {
|
fn configure_delay(&mut self, delay_1: bool, delay_2: bool) {
|
||||||
let portreg = self.port_reg();
|
let portreg = self.port_reg();
|
||||||
unsafe {
|
unsafe {
|
||||||
if delay_1 {
|
if delay_1 {
|
||||||
|
@ -30,7 +30,7 @@ pub enum FifoEmptyMode {
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct ClockTooSlowForFastI2c;
|
pub struct ClockTooSlowForFastI2cError;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
@ -52,11 +52,11 @@ pub enum InitError {
|
|||||||
/// Wrong address used in constructor
|
/// Wrong address used in constructor
|
||||||
WrongAddrMode,
|
WrongAddrMode,
|
||||||
/// APB1 clock is too slow for fast I2C mode.
|
/// APB1 clock is too slow for fast I2C mode.
|
||||||
ClkTooSlow(ClockTooSlowForFastI2c),
|
ClkTooSlow(ClockTooSlowForFastI2cError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ClockTooSlowForFastI2c> for InitError {
|
impl From<ClockTooSlowForFastI2cError> for InitError {
|
||||||
fn from(value: ClockTooSlowForFastI2c) -> Self {
|
fn from(value: ClockTooSlowForFastI2cError) -> Self {
|
||||||
Self::ClkTooSlow(value)
|
Self::ClkTooSlow(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -318,7 +318,7 @@ impl<I2c: Instance> I2cBase<I2c> {
|
|||||||
speed_mode: I2cSpeed,
|
speed_mode: I2cSpeed,
|
||||||
ms_cfg: Option<&MasterConfig>,
|
ms_cfg: Option<&MasterConfig>,
|
||||||
sl_cfg: Option<&SlaveConfig>,
|
sl_cfg: Option<&SlaveConfig>,
|
||||||
) -> Result<Self, ClockTooSlowForFastI2c> {
|
) -> Result<Self, ClockTooSlowForFastI2cError> {
|
||||||
syscfg.enable_peripheral_clock(I2c::PERIPH_SEL);
|
syscfg.enable_peripheral_clock(I2c::PERIPH_SEL);
|
||||||
|
|
||||||
let mut i2c_base = I2cBase {
|
let mut i2c_base = I2cBase {
|
||||||
@ -421,19 +421,19 @@ impl<I2c: Instance> I2cBase<I2c> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calc_clk_div(&self, speed_mode: I2cSpeed) -> Result<u8, ClockTooSlowForFastI2c> {
|
fn calc_clk_div(&self, speed_mode: I2cSpeed) -> Result<u8, ClockTooSlowForFastI2cError> {
|
||||||
if speed_mode == I2cSpeed::Regular100khz {
|
if speed_mode == I2cSpeed::Regular100khz {
|
||||||
Ok(((self.clock.raw() / CLK_100K.raw() / 20) - 1) as u8)
|
Ok(((self.clock.raw() / CLK_100K.raw() / 20) - 1) as u8)
|
||||||
} else {
|
} else {
|
||||||
if self.clock.raw() < MIN_CLK_400K.raw() {
|
if self.clock.raw() < MIN_CLK_400K.raw() {
|
||||||
return Err(ClockTooSlowForFastI2c);
|
return Err(ClockTooSlowForFastI2cError);
|
||||||
}
|
}
|
||||||
Ok(((self.clock.raw() / CLK_400K.raw() / 25) - 1) as u8)
|
Ok(((self.clock.raw() / CLK_400K.raw() / 25) - 1) as u8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configures the clock scale for a given speed mode setting
|
/// Configures the clock scale for a given speed mode setting
|
||||||
pub fn cfg_clk_scale(&mut self, speed_mode: I2cSpeed) -> Result<(), ClockTooSlowForFastI2c> {
|
pub fn cfg_clk_scale(&mut self, speed_mode: I2cSpeed) -> Result<(), ClockTooSlowForFastI2cError> {
|
||||||
let clk_div = self.calc_clk_div(speed_mode)?;
|
let clk_div = self.calc_clk_div(speed_mode)?;
|
||||||
self.i2c
|
self.i2c
|
||||||
.clkscale()
|
.clkscale()
|
||||||
@ -472,7 +472,7 @@ impl<I2c: Instance, Addr> I2cMaster<I2c, Addr> {
|
|||||||
cfg: MasterConfig,
|
cfg: MasterConfig,
|
||||||
clocks: &Clocks,
|
clocks: &Clocks,
|
||||||
speed_mode: I2cSpeed,
|
speed_mode: I2cSpeed,
|
||||||
) -> Result<Self, ClockTooSlowForFastI2c> {
|
) -> Result<Self, ClockTooSlowForFastI2cError> {
|
||||||
Ok(I2cMaster {
|
Ok(I2cMaster {
|
||||||
i2c_base: I2cBase::new(i2c, sys_cfg, clocks, speed_mode, Some(&cfg), None)?,
|
i2c_base: I2cBase::new(i2c, sys_cfg, clocks, speed_mode, Some(&cfg), None)?,
|
||||||
addr: PhantomData,
|
addr: PhantomData,
|
||||||
@ -733,7 +733,7 @@ impl<I2c: Instance, Addr> I2cSlave<I2c, Addr> {
|
|||||||
cfg: SlaveConfig,
|
cfg: SlaveConfig,
|
||||||
clocks: &Clocks,
|
clocks: &Clocks,
|
||||||
speed_mode: I2cSpeed,
|
speed_mode: I2cSpeed,
|
||||||
) -> Result<Self, ClockTooSlowForFastI2c> {
|
) -> Result<Self, ClockTooSlowForFastI2cError> {
|
||||||
Ok(I2cSlave {
|
Ok(I2cSlave {
|
||||||
i2c_base: I2cBase::new(i2c, sys_cfg, clocks, speed_mode, None, Some(&cfg))?,
|
i2c_base: I2cBase::new(i2c, sys_cfg, clocks, speed_mode, None, Some(&cfg))?,
|
||||||
addr: PhantomData,
|
addr: PhantomData,
|
||||||
@ -895,7 +895,7 @@ impl<I2c: Instance> I2cSlave<I2c, TenBitAddress> {
|
|||||||
cfg: SlaveConfig,
|
cfg: SlaveConfig,
|
||||||
clocks: &Clocks,
|
clocks: &Clocks,
|
||||||
speed_mode: I2cSpeed,
|
speed_mode: I2cSpeed,
|
||||||
) -> Result<Self, ClockTooSlowForFastI2c> {
|
) -> Result<Self, ClockTooSlowForFastI2cError> {
|
||||||
Self::new_generic(i2c, sys_cfg, cfg, clocks, speed_mode)
|
Self::new_generic(i2c, sys_cfg, cfg, clocks, speed_mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -275,7 +275,7 @@ impl IrqContextTimeoutOrMaxSize {
|
|||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct IrqResult {
|
pub struct IrqResult {
|
||||||
pub bytes_read: usize,
|
pub bytes_read: usize,
|
||||||
pub errors: Option<IrqUartError>,
|
pub errors: Option<UartErrors>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This struct is used to return the default IRQ handler result to the user
|
/// This struct is used to return the default IRQ handler result to the user
|
||||||
@ -283,7 +283,7 @@ pub struct IrqResult {
|
|||||||
pub struct IrqResultMaxSizeOrTimeout {
|
pub struct IrqResultMaxSizeOrTimeout {
|
||||||
complete: bool,
|
complete: bool,
|
||||||
timeout: bool,
|
timeout: bool,
|
||||||
pub errors: Option<IrqUartError>,
|
pub errors: Option<UartErrors>,
|
||||||
pub bytes_read: usize,
|
pub bytes_read: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,14 +336,14 @@ enum IrqReceptionMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Copy, Clone)]
|
#[derive(Default, Debug, Copy, Clone)]
|
||||||
pub struct IrqUartError {
|
pub struct UartErrors {
|
||||||
overflow: bool,
|
overflow: bool,
|
||||||
framing: bool,
|
framing: bool,
|
||||||
parity: bool,
|
parity: bool,
|
||||||
other: bool,
|
other: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IrqUartError {
|
impl UartErrors {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn overflow(&self) -> bool {
|
pub fn overflow(&self) -> bool {
|
||||||
self.overflow
|
self.overflow
|
||||||
@ -365,7 +365,7 @@ impl IrqUartError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IrqUartError {
|
impl UartErrors {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn error(&self) -> bool {
|
pub fn error(&self) -> bool {
|
||||||
self.overflow || self.framing || self.parity
|
self.overflow || self.framing || self.parity
|
||||||
@ -405,10 +405,10 @@ impl Instance for Uart0 {
|
|||||||
const IRQ_TX: pac::Interrupt = pac::Interrupt::UART0_TX;
|
const IRQ_TX: pac::Interrupt = pac::Interrupt::UART0_TX;
|
||||||
|
|
||||||
unsafe fn steal() -> Self {
|
unsafe fn steal() -> Self {
|
||||||
pac::Peripherals::steal().uart0
|
Self::steal()
|
||||||
}
|
}
|
||||||
fn ptr() -> *const uart_base::RegisterBlock {
|
fn ptr() -> *const uart_base::RegisterBlock {
|
||||||
Uart0::ptr() as *const _
|
Self::ptr() as *const _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,10 +419,10 @@ impl Instance for Uart1 {
|
|||||||
const IRQ_TX: pac::Interrupt = pac::Interrupt::UART1_TX;
|
const IRQ_TX: pac::Interrupt = pac::Interrupt::UART1_TX;
|
||||||
|
|
||||||
unsafe fn steal() -> Self {
|
unsafe fn steal() -> Self {
|
||||||
pac::Peripherals::steal().uart1
|
Self::steal()
|
||||||
}
|
}
|
||||||
fn ptr() -> *const uart_base::RegisterBlock {
|
fn ptr() -> *const uart_base::RegisterBlock {
|
||||||
Uart1::ptr() as *const _
|
Self::ptr() as *const _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,10 +433,10 @@ impl Instance for Uart2 {
|
|||||||
const IRQ_TX: pac::Interrupt = pac::Interrupt::UART2_TX;
|
const IRQ_TX: pac::Interrupt = pac::Interrupt::UART2_TX;
|
||||||
|
|
||||||
unsafe fn steal() -> Self {
|
unsafe fn steal() -> Self {
|
||||||
pac::Peripherals::steal().uart2
|
Self::steal()
|
||||||
}
|
}
|
||||||
fn ptr() -> *const uart_base::RegisterBlock {
|
fn ptr() -> *const uart_base::RegisterBlock {
|
||||||
Uart2::ptr() as *const _
|
Self::ptr() as *const _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1164,7 +1164,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
|
|
||||||
fn read_handler(
|
fn read_handler(
|
||||||
&self,
|
&self,
|
||||||
errors: &mut Option<IrqUartError>,
|
errors: &mut Option<UartErrors>,
|
||||||
read_res: &nb::Result<u8, RxError>,
|
read_res: &nb::Result<u8, RxError>,
|
||||||
) -> Option<u8> {
|
) -> Option<u8> {
|
||||||
match read_res {
|
match read_res {
|
||||||
@ -1172,7 +1172,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
Err(nb::Error::WouldBlock) => None,
|
Err(nb::Error::WouldBlock) => None,
|
||||||
Err(nb::Error::Other(e)) => {
|
Err(nb::Error::Other(e)) => {
|
||||||
// Ensure `errors` is Some(IrqUartError), initializing if it's None
|
// Ensure `errors` is Some(IrqUartError), initializing if it's None
|
||||||
let err = errors.get_or_insert(IrqUartError::default());
|
let err = errors.get_or_insert(UartErrors::default());
|
||||||
|
|
||||||
// Now we can safely modify fields inside `err`
|
// Now we can safely modify fields inside `err`
|
||||||
match e {
|
match e {
|
||||||
@ -1185,14 +1185,14 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_for_errors(&self, errors: &mut Option<IrqUartError>) {
|
fn check_for_errors(&self, errors: &mut Option<UartErrors>) {
|
||||||
let rx_status = self.uart().rxstatus().read();
|
let rx_status = self.uart().rxstatus().read();
|
||||||
|
|
||||||
if rx_status.rxovr().bit_is_set()
|
if rx_status.rxovr().bit_is_set()
|
||||||
|| rx_status.rxfrm().bit_is_set()
|
|| rx_status.rxfrm().bit_is_set()
|
||||||
|| rx_status.rxpar().bit_is_set()
|
|| rx_status.rxpar().bit_is_set()
|
||||||
{
|
{
|
||||||
let err = errors.get_or_insert(IrqUartError::default());
|
let err = errors.get_or_insert(UartErrors::default());
|
||||||
|
|
||||||
if rx_status.rxovr().bit_is_set() {
|
if rx_status.rxovr().bit_is_set() {
|
||||||
err.overflow = true;
|
err.overflow = true;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user