delete old GPIO module
This commit is contained in:
parent
5f88f094ca
commit
81eaf8127c
@ -12,6 +12,11 @@
|
|||||||
//!
|
//!
|
||||||
//! The [crate::pins] module exposes singletons to access the [Pin]s required by this module
|
//! The [crate::pins] module exposes singletons to access the [Pin]s required by this module
|
||||||
//! in a type-safe way.
|
//! 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::*;
|
||||||
|
|
||||||
pub use vorago_shared_periphs::gpio::asynch;
|
pub use vorago_shared_periphs::gpio::asynch;
|
||||||
|
@ -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, 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 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<DynPinMode> 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<bool, InvalidPinTypeError> {
|
|
||||||
self.read_internal().map(|v| !v)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_high(&self) -> Result<bool, InvalidPinTypeError> {
|
|
||||||
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<I: PinId, M: PinMode>(self) -> Result<Pin<I, M>, 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, InvalidPinTypeError> {
|
|
||||||
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<bool, crate::gpio::IsMaskedError> {
|
|
||||||
self.read_pin_masked()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn is_low_masked(&self) -> Result<bool, crate::gpio::IsMaskedError> {
|
|
||||||
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<bool, InvalidPinTypeError> {
|
|
||||||
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<bool, IsMaskedError> {
|
|
||||||
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<bool, InvalidPinTypeError> {
|
|
||||||
self.is_low()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only serves disambiguation purposes for the Embedded HAL impl
|
|
||||||
#[inline(always)]
|
|
||||||
fn is_high_mut(&mut self) -> Result<bool, InvalidPinTypeError> {
|
|
||||||
self.is_high()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
const fn mask_32(&self) -> u32 {
|
|
||||||
1 << self.id().num()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//==================================================================================================
|
|
||||||
// Convert between Pin and DynPin
|
|
||||||
//==================================================================================================
|
|
||||||
|
|
||||||
impl<I: PinId, M: PinMode> From<Pin<I, M>> for DynPin {
|
|
||||||
/// Erase the type-level information in a [`Pin`] and return a value-level
|
|
||||||
/// [`DynPin`]
|
|
||||||
#[inline]
|
|
||||||
fn from(pin: Pin<I, M>) -> Self {
|
|
||||||
pin.downgrade()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: PinId, M: PinMode> TryFrom<DynPin> for Pin<I, M> {
|
|
||||||
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<Self, Self::Error> {
|
|
||||||
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<bool, Self::Error> {
|
|
||||||
self.is_high_mut()
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn is_low(&mut self) -> Result<bool, Self::Error> {
|
|
||||||
self.is_low_mut()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl embedded_hal::digital::StatefulOutputPin for DynPin {
|
|
||||||
#[inline]
|
|
||||||
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
|
|
||||||
self.is_high_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
|
|
||||||
self.is_low_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn toggle(&mut self) -> Result<(), Self::Error> {
|
|
||||||
self.toggle()
|
|
||||||
}
|
|
||||||
}
|
|
@ -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::*;
|
|
@ -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<I, M>
|
|
||||||
//! 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::<FloatingInput>();
|
|
||||||
//! // Specify the target type and use `From`/`Into`
|
|
||||||
//! let pa0: Pin<PA0, FloatingInput> = 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<Floating>;
|
|
||||||
/// Type-level variant of [`PinMode`] for pull-down input mode
|
|
||||||
pub type InputPullDown = Input<PullDown>;
|
|
||||||
/// Type-level variant of [`PinMode`] for pull-up input mode
|
|
||||||
pub type InputPullUp = Input<PullUp>;
|
|
||||||
|
|
||||||
/// 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<C: InputConfig> {
|
|
||||||
cfg: PhantomData<C>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C: InputConfig> Sealed for Input<C> {}
|
|
||||||
|
|
||||||
#[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<C: OutputConfig> {
|
|
||||||
cfg: PhantomData<C>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C: OutputConfig> Sealed for Output<C> {}
|
|
||||||
|
|
||||||
/// Type-level variant of [`PinMode`] for push-pull output mode
|
|
||||||
pub type PushPullOutput = Output<PushPull>;
|
|
||||||
/// Type-level variant of [`PinMode`] for open drain output mode
|
|
||||||
pub type OutputOpenDrain = Output<OpenDrain>;
|
|
||||||
|
|
||||||
pub type OutputReadablePushPull = Output<ReadablePushPull>;
|
|
||||||
pub type OutputReadableOpenDrain = Output<ReadableOpenDrain>;
|
|
||||||
|
|
||||||
//==================================================================================================
|
|
||||||
// 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<C: AlternateConfig> {
|
|
||||||
cfg: PhantomData<C>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C: AlternateConfig> Sealed for Alternate<C> {}
|
|
||||||
|
|
||||||
pub type AltFunc1 = Alternate<Funsel1>;
|
|
||||||
pub type AltFunc2 = Alternate<Funsel2>;
|
|
||||||
pub type AltFunc3 = Alternate<Funsel3>;
|
|
||||||
|
|
||||||
/// 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<C: InputConfig> PinMode for Input<C> {
|
|
||||||
const DYN: DynPinMode = DynPinMode::Input(C::DYN);
|
|
||||||
}
|
|
||||||
impl<C: OutputConfig> PinMode for Output<C> {
|
|
||||||
const DYN: DynPinMode = DynPinMode::Output(C::DYN);
|
|
||||||
}
|
|
||||||
impl<C: AlternateConfig> PinMode for Alternate<C> {
|
|
||||||
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<I: PinId, M: PinMode> {
|
|
||||||
inner: DynPin,
|
|
||||||
phantom: PhantomData<(I, M)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: PinId, M: PinMode> Pin<I, M> {
|
|
||||||
/// 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<I, M> {
|
|
||||||
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<N: PinMode>(mut self) -> Pin<I, N> {
|
|
||||||
// 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<I, AltFunc1> {
|
|
||||||
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<I, AltFunc2> {
|
|
||||||
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<I, AltFunc3> {
|
|
||||||
self.into_mode()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Configure the pin to operate as a floating input
|
|
||||||
#[inline]
|
|
||||||
pub fn into_floating_input(self) -> Pin<I, InputFloating> {
|
|
||||||
self.into_mode()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Configure the pin to operate as a pulled down input
|
|
||||||
#[inline]
|
|
||||||
pub fn into_pull_down_input(self) -> Pin<I, InputPullDown> {
|
|
||||||
self.into_mode()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Configure the pin to operate as a pulled up input
|
|
||||||
#[inline]
|
|
||||||
pub fn into_pull_up_input(self) -> Pin<I, InputPullUp> {
|
|
||||||
self.into_mode()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Configure the pin to operate as a push-pull output
|
|
||||||
#[inline]
|
|
||||||
pub fn into_push_pull_output(self) -> Pin<I, PushPullOutput> {
|
|
||||||
self.into_mode()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Configure the pin to operate as a readable push-pull output
|
|
||||||
#[inline]
|
|
||||||
pub fn into_readable_push_pull_output(self) -> Pin<I, OutputReadablePushPull> {
|
|
||||||
self.into_mode()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Configure the pin to operate as a readable open-drain output
|
|
||||||
#[inline]
|
|
||||||
pub fn into_readable_open_drain_output(self) -> Pin<I, OutputReadableOpenDrain> {
|
|
||||||
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<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 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<Type = SpecificPin<Self>>` 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<SpecificPin<Self>>,
|
|
||||||
Self: Into<SpecificPin<Self>>,
|
|
||||||
Self: AsRef<SpecificPin<Self>>,
|
|
||||||
Self: AsMut<SpecificPin<Self>>,
|
|
||||||
{
|
|
||||||
/// [`PinId`] of the corresponding [`Pin`]
|
|
||||||
type Id: PinId;
|
|
||||||
/// [`PinMode`] of the corresponding [`Pin`]
|
|
||||||
type Mode: PinMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, M> Sealed for Pin<I, M>
|
|
||||||
where
|
|
||||||
I: PinId,
|
|
||||||
M: PinMode,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, M> AnyPin for Pin<I, M>
|
|
||||||
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<P> = Pin<<P as AnyPin>::Id, <P as AnyPin>::Mode>;
|
|
||||||
|
|
||||||
impl<P: AnyPin> AsRef<P> for SpecificPin<P> {
|
|
||||||
#[inline]
|
|
||||||
fn as_ref(&self) -> &P {
|
|
||||||
// SAFETY: This is guaranteed to be safe, because P == SpecificPin<P>
|
|
||||||
// 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<P: AnyPin> AsMut<P> for SpecificPin<P> {
|
|
||||||
#[inline]
|
|
||||||
fn as_mut(&mut self) -> &mut P {
|
|
||||||
// SAFETY: This is guaranteed to be safe, because P == SpecificPin<P>
|
|
||||||
// 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<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
|
||||||
/// 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<I, C> {
|
|
||||||
InputPinAsync::new(self, irq)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
|
|
||||||
#[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<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
|
||||||
/// 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<I, M> embedded_hal::digital::ErrorType for Pin<I, M>
|
|
||||||
where
|
|
||||||
I: PinId,
|
|
||||||
M: PinMode,
|
|
||||||
{
|
|
||||||
type Error = Infallible;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: PinId, C: OutputConfig> embedded_hal::digital::OutputPin for Pin<I, Output<C>> {
|
|
||||||
#[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<I, C> embedded_hal::digital::InputPin for Pin<I, Input<C>>
|
|
||||||
where
|
|
||||||
I: PinId,
|
|
||||||
C: InputConfig,
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn is_high(&mut self) -> Result<bool, Self::Error> {
|
|
||||||
Ok(self.is_high_mut())
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn is_low(&mut self) -> Result<bool, Self::Error> {
|
|
||||||
Ok(self.is_low_mut())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, C> embedded_hal::digital::StatefulOutputPin for Pin<I, Output<C>>
|
|
||||||
where
|
|
||||||
I: PinId,
|
|
||||||
C: OutputConfig + ReadableOutput,
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
|
|
||||||
Ok(self.is_high())
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
|
|
||||||
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),
|
|
||||||
]
|
|
||||||
);
|
|
@ -15,6 +15,13 @@ const CLK_100K: Hertz = Hertz::from_raw(100_000);
|
|||||||
const CLK_400K: Hertz = Hertz::from_raw(400_000);
|
const CLK_400K: Hertz = Hertz::from_raw(400_000);
|
||||||
const MIN_CLK_400K: Hertz = Hertz::from_raw(8_000_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)]
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum FifoEmptyMode {
|
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
|
/// Common trait implemented by all PAC peripheral access structures. The register block
|
||||||
/// format is the same for all SPI blocks.
|
/// format is the same for all SPI blocks.
|
||||||
pub trait Instance: Deref<Target = I2cRegBlock> {
|
pub trait I2cMarker: Deref<Target = I2cRegBlock> {
|
||||||
const IDX: u8;
|
const ID: I2cId;
|
||||||
const PERIPH_SEL: PeripheralSelect;
|
const PERIPH_SEL: PeripheralSelect;
|
||||||
|
const PTR: *const I2cRegBlock;
|
||||||
|
|
||||||
fn ptr() -> *const I2cRegBlock;
|
fn ptr() -> *const I2cRegBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instance for pac::I2ca {
|
impl I2cMarker for pac::I2ca {
|
||||||
const IDX: u8 = 0;
|
const ID: I2cId = I2cId::A;
|
||||||
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::I2c0;
|
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::I2c0;
|
||||||
|
const PTR: *const I2cRegBlock = Self::PTR;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn ptr() -> *const I2cRegBlock {
|
fn ptr() -> *const I2cRegBlock {
|
||||||
@ -128,9 +137,10 @@ impl Instance for pac::I2ca {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instance for pac::I2cb {
|
impl I2cMarker for pac::I2cb {
|
||||||
const IDX: u8 = 1;
|
const ID: I2cId = I2cId::B;
|
||||||
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::I2c1;
|
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::I2c1;
|
||||||
|
const PTR: *const I2cRegBlock = Self::PTR;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn ptr() -> *const I2cRegBlock {
|
fn ptr() -> *const I2cRegBlock {
|
||||||
@ -290,32 +300,27 @@ impl Sealed for SlaveConfig {}
|
|||||||
// I2C Base
|
// I2C Base
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
pub struct I2cBase<I2C> {
|
pub struct I2cCommon {
|
||||||
i2c: I2C,
|
id: I2cId,
|
||||||
|
reg_block: *const I2cRegBlock,
|
||||||
sys_clk: Hertz,
|
sys_clk: Hertz,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I2C> I2cBase<I2C> {
|
impl I2cCommon {
|
||||||
#[inline]
|
pub fn new<I2c: I2cMarker>(
|
||||||
fn unwrap_addr(addr: I2cAddress) -> (u16, u32) {
|
|
||||||
match addr {
|
|
||||||
I2cAddress::Regular(addr) => (addr as u16, 0 << 15),
|
|
||||||
I2cAddress::TenBit(addr) => (addr, 1 << 15),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I2c: Instance> I2cBase<I2c> {
|
|
||||||
pub fn new(
|
|
||||||
sys_clk: Hertz,
|
sys_clk: Hertz,
|
||||||
i2c: I2c,
|
_i2c: 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, ClockTooSlowForFastI2cError> {
|
) -> Result<Self, ClockTooSlowForFastI2cError> {
|
||||||
enable_peripheral_clock(I2c::PERIPH_SEL);
|
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 {
|
if let Some(ms_cfg) = ms_cfg {
|
||||||
i2c_base.cfg_master(ms_cfg);
|
i2c_base.cfg_master(ms_cfg);
|
||||||
}
|
}
|
||||||
@ -327,6 +332,32 @@ impl<I2c: Instance> I2cBase<I2c> {
|
|||||||
Ok(i2c_base)
|
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) {
|
fn cfg_master(&mut self, ms_cfg: &MasterConfig) {
|
||||||
let (txfemd, rxfemd) = match (ms_cfg.tx_fe_mode, ms_cfg.rx_fe_mode) {
|
let (txfemd, rxfemd) = match (ms_cfg.tx_fe_mode, ms_cfg.rx_fe_mode) {
|
||||||
(FifoEmptyMode::Stall, FifoEmptyMode::Stall) => (false, false),
|
(FifoEmptyMode::Stall, FifoEmptyMode::Stall) => (false, false),
|
||||||
@ -334,18 +365,17 @@ impl<I2c: Instance> I2cBase<I2c> {
|
|||||||
(FifoEmptyMode::EndTransaction, FifoEmptyMode::Stall) => (true, false),
|
(FifoEmptyMode::EndTransaction, FifoEmptyMode::Stall) => (true, false),
|
||||||
(FifoEmptyMode::EndTransaction, FifoEmptyMode::EndTransaction) => (true, true),
|
(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.txfemd().bit(txfemd);
|
||||||
w.rxffmd().bit(rxfemd);
|
w.rxffmd().bit(rxfemd);
|
||||||
w.dlgfilter().bit(ms_cfg.dlg_filt);
|
w.dlgfilter().bit(ms_cfg.dlg_filt);
|
||||||
w.algfilter().bit(ms_cfg.alg_filt)
|
w.algfilter().bit(ms_cfg.alg_filt)
|
||||||
});
|
});
|
||||||
if let Some(ref tm_cfg) = ms_cfg.tm_cfg {
|
if let Some(ref tm_cfg) = ms_cfg.tm_cfg {
|
||||||
self.i2c
|
regs.tmconfig().write(|w| unsafe { w.bits(tm_cfg.reg()) });
|
||||||
.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.rxfifo().set_bit();
|
||||||
w.txfifo().set_bit()
|
w.txfifo().set_bit()
|
||||||
});
|
});
|
||||||
@ -358,47 +388,43 @@ impl<I2c: Instance> I2cBase<I2c> {
|
|||||||
(FifoEmptyMode::EndTransaction, FifoEmptyMode::Stall) => (true, false),
|
(FifoEmptyMode::EndTransaction, FifoEmptyMode::Stall) => (true, false),
|
||||||
(FifoEmptyMode::EndTransaction, FifoEmptyMode::EndTransaction) => (true, true),
|
(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.txfemd().bit(txfemd);
|
||||||
w.rxffmd().bit(rxfemd)
|
w.rxffmd().bit(rxfemd)
|
||||||
});
|
});
|
||||||
self.i2c.s0_fifo_clr().write(|w| {
|
regs.s0_fifo_clr().write(|w| {
|
||||||
w.rxfifo().set_bit();
|
w.rxfifo().set_bit();
|
||||||
w.txfifo().set_bit()
|
w.txfifo().set_bit()
|
||||||
});
|
});
|
||||||
let max_words = sl_cfg.max_words;
|
let max_words = sl_cfg.max_words;
|
||||||
if let Some(max_words) = max_words {
|
if let Some(max_words) = max_words {
|
||||||
self.i2c
|
regs.s0_maxwords()
|
||||||
.s0_maxwords()
|
|
||||||
.write(|w| unsafe { w.bits((1 << 31) | max_words as u32) });
|
.write(|w| unsafe { w.bits((1 << 31) | max_words as u32) });
|
||||||
}
|
}
|
||||||
let (addr, addr_mode_mask) = Self::unwrap_addr(sl_cfg.addr);
|
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
|
// The first bit is the read/write value. Normally, both read and write are matched
|
||||||
// using the RWMASK bit of the address mask register
|
// using the RWMASK bit of the address mask register
|
||||||
self.i2c
|
regs.s0_address()
|
||||||
.s0_address()
|
|
||||||
.write(|w| unsafe { w.bits((addr << 1) as u32 | addr_mode_mask) });
|
.write(|w| unsafe { w.bits((addr << 1) as u32 | addr_mode_mask) });
|
||||||
if let Some(addr_mask) = sl_cfg.addr_mask {
|
if let Some(addr_mask) = sl_cfg.addr_mask {
|
||||||
self.i2c
|
regs.s0_addressmask()
|
||||||
.s0_addressmask()
|
|
||||||
.write(|w| unsafe { w.bits((addr_mask << 1) as u32) });
|
.write(|w| unsafe { w.bits((addr_mask << 1) as u32) });
|
||||||
}
|
}
|
||||||
if let Some(addr_b) = sl_cfg.addr_b {
|
if let Some(addr_b) = sl_cfg.addr_b {
|
||||||
let (addr, addr_mode_mask) = Self::unwrap_addr(addr_b);
|
let (addr, addr_mode_mask) = Self::unwrap_addr(addr_b);
|
||||||
self.i2c
|
regs.s0_addressb()
|
||||||
.s0_addressb()
|
|
||||||
.write(|w| unsafe { w.bits((addr << 1) as u32 | addr_mode_mask) });
|
.write(|w| unsafe { w.bits((addr << 1) as u32 | addr_mode_mask) });
|
||||||
}
|
}
|
||||||
if let Some(addr_b_mask) = sl_cfg.addr_b_mask {
|
if let Some(addr_b_mask) = sl_cfg.addr_b_mask {
|
||||||
self.i2c
|
regs.s0_addressmaskb()
|
||||||
.s0_addressmaskb()
|
|
||||||
.write(|w| unsafe { w.bits((addr_b_mask << 1) as u32) });
|
.write(|w| unsafe { w.bits((addr_b_mask << 1) as u32) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn filters(&mut self, digital_filt: bool, analog_filt: bool) {
|
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.dlgfilter().bit(digital_filt);
|
||||||
w.algfilter().bit(analog_filt)
|
w.algfilter().bit(analog_filt)
|
||||||
});
|
});
|
||||||
@ -406,7 +432,7 @@ impl<I2c: Instance> I2cBase<I2c> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn fifo_empty_mode(&mut self, rx: FifoEmptyMode, tx: FifoEmptyMode) {
|
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.txfemd().bit(tx as u8 != 0);
|
||||||
w.rxffmd().bit(rx as u8 != 0)
|
w.rxffmd().bit(rx as u8 != 0)
|
||||||
});
|
});
|
||||||
@ -429,7 +455,7 @@ impl<I2c: Instance> I2cBase<I2c> {
|
|||||||
speed_mode: I2cSpeed,
|
speed_mode: I2cSpeed,
|
||||||
) -> Result<(), ClockTooSlowForFastI2cError> {
|
) -> Result<(), ClockTooSlowForFastI2cError> {
|
||||||
let clk_div = self.calc_clk_div(speed_mode)?;
|
let clk_div = self.calc_clk_div(speed_mode)?;
|
||||||
self.i2c
|
self.regs_priv()
|
||||||
.clkscale()
|
.clkscale()
|
||||||
.write(|w| unsafe { w.bits(((speed_mode as u32) << 31) | clk_div as u32) });
|
.write(|w| unsafe { w.bits(((speed_mode as u32) << 31) | clk_div as u32) });
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -437,14 +463,14 @@ impl<I2c: Instance> I2cBase<I2c> {
|
|||||||
|
|
||||||
pub fn load_address(&mut self, addr: u16) {
|
pub fn load_address(&mut self, addr: u16) {
|
||||||
// Load address
|
// Load address
|
||||||
self.i2c
|
self.regs_priv()
|
||||||
.address()
|
.address()
|
||||||
.write(|w| unsafe { w.bits((addr << 1) as u32) });
|
.write(|w| unsafe { w.bits((addr << 1) as u32) });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn stop_cmd(&mut self) {
|
fn stop_cmd(&mut self) {
|
||||||
self.i2c
|
self.regs_priv()
|
||||||
.cmd()
|
.cmd()
|
||||||
.write(|w| unsafe { w.bits(I2cCmd::Stop as u32) });
|
.write(|w| unsafe { w.bits(I2cCmd::Stop as u32) });
|
||||||
}
|
}
|
||||||
@ -454,20 +480,20 @@ impl<I2c: Instance> I2cBase<I2c> {
|
|||||||
// I2C Master
|
// I2C Master
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
pub struct I2cMaster<I2c, Addr = SevenBitAddress> {
|
pub struct I2cMaster<Addr = SevenBitAddress> {
|
||||||
i2c_base: I2cBase<I2c>,
|
inner: I2cCommon,
|
||||||
addr: PhantomData<Addr>,
|
addr: PhantomData<Addr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I2c: Instance, Addr> I2cMaster<I2c, Addr> {
|
impl<Addr> I2cMaster<Addr> {
|
||||||
pub fn new(
|
pub fn new<I2c: I2cMarker>(
|
||||||
sysclk: Hertz,
|
sysclk: Hertz,
|
||||||
i2c: I2c,
|
i2c: I2c,
|
||||||
cfg: MasterConfig,
|
cfg: MasterConfig,
|
||||||
speed_mode: I2cSpeed,
|
speed_mode: I2cSpeed,
|
||||||
) -> Result<Self, ClockTooSlowForFastI2cError> {
|
) -> Result<Self, ClockTooSlowForFastI2cError> {
|
||||||
Ok(I2cMaster {
|
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,
|
addr: PhantomData,
|
||||||
}
|
}
|
||||||
.enable_master())
|
.enable_master())
|
||||||
@ -475,32 +501,41 @@ impl<I2c: Instance, Addr> I2cMaster<I2c, Addr> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn cancel_transfer(&self) {
|
pub fn cancel_transfer(&self) {
|
||||||
self.i2c_base
|
self.inner
|
||||||
.i2c
|
.regs_priv()
|
||||||
.cmd()
|
.cmd()
|
||||||
.write(|w| unsafe { w.bits(I2cCmd::Cancel as u32) });
|
.write(|w| unsafe { w.bits(I2cCmd::Cancel as u32) });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn clear_tx_fifo(&self) {
|
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]
|
#[inline]
|
||||||
pub fn clear_rx_fifo(&self) {
|
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]
|
#[inline]
|
||||||
pub fn enable_master(self) -> Self {
|
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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn disable_master(self) -> Self {
|
pub fn disable_master(self) -> Self {
|
||||||
self.i2c_base
|
self.inner
|
||||||
.i2c
|
.regs_priv()
|
||||||
.ctrl()
|
.ctrl()
|
||||||
.modify(|_, w| w.enable().clear_bit());
|
.modify(|_, w| w.enable().clear_bit());
|
||||||
self
|
self
|
||||||
@ -508,21 +543,21 @@ impl<I2c: Instance, Addr> I2cMaster<I2c, Addr> {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn load_fifo(&self, word: u8) {
|
fn load_fifo(&self, word: u8) {
|
||||||
self.i2c_base
|
self.inner
|
||||||
.i2c
|
.regs_priv()
|
||||||
.data()
|
.data()
|
||||||
.write(|w| unsafe { w.bits(word as u32) });
|
.write(|w| unsafe { w.bits(word as u32) });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn read_fifo(&self) -> u8 {
|
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) {
|
fn error_handler_write(&mut self, init_cmd: &I2cCmd) {
|
||||||
self.clear_tx_fifo();
|
self.clear_tx_fifo();
|
||||||
if *init_cmd == I2cCmd::Start {
|
if *init_cmd == I2cCmd::Start {
|
||||||
self.i2c_base.stop_cmd()
|
self.inner.stop_cmd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,13 +569,13 @@ impl<I2c: Instance, Addr> I2cMaster<I2c, Addr> {
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut iter = bytes.into_iter();
|
let mut iter = bytes.into_iter();
|
||||||
// Load address
|
// Load address
|
||||||
let (addr, addr_mode_bit) = I2cBase::<I2c>::unwrap_addr(addr);
|
let (addr, addr_mode_bit) = I2cCommon::unwrap_addr(addr);
|
||||||
self.i2c_base.i2c.address().write(|w| unsafe {
|
self.inner.regs_priv().address().write(|w| unsafe {
|
||||||
w.bits(I2cDirection::Send as u32 | (addr << 1) as u32 | addr_mode_bit)
|
w.bits(I2cDirection::Send as u32 | (addr << 1) as u32 | addr_mode_bit)
|
||||||
});
|
});
|
||||||
|
|
||||||
self.i2c_base
|
self.inner
|
||||||
.i2c
|
.regs_priv()
|
||||||
.cmd()
|
.cmd()
|
||||||
.write(|w| unsafe { w.bits(init_cmd as u32) });
|
.write(|w| unsafe { w.bits(init_cmd as u32) });
|
||||||
let mut load_if_next_available = || {
|
let mut load_if_next_available = || {
|
||||||
@ -549,7 +584,7 @@ impl<I2c: Instance, Addr> I2cMaster<I2c, Addr> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
loop {
|
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() {
|
if status_reader.arblost().bit_is_set() {
|
||||||
self.error_handler_write(&init_cmd);
|
self.error_handler_write(&init_cmd);
|
||||||
return Err(Error::ArbitrationLost);
|
return Err(Error::ArbitrationLost);
|
||||||
@ -584,8 +619,8 @@ impl<I2c: Instance, Addr> I2cMaster<I2c, Addr> {
|
|||||||
return Err(Error::DataTooLarge);
|
return Err(Error::DataTooLarge);
|
||||||
}
|
}
|
||||||
// Load number of words
|
// Load number of words
|
||||||
self.i2c_base
|
self.inner
|
||||||
.i2c
|
.regs_priv()
|
||||||
.words()
|
.words()
|
||||||
.write(|w| unsafe { w.bits(len as u32) });
|
.write(|w| unsafe { w.bits(len as u32) });
|
||||||
let mut bytes = output.iter();
|
let mut bytes = output.iter();
|
||||||
@ -614,8 +649,8 @@ impl<I2c: Instance, Addr> I2cMaster<I2c, Addr> {
|
|||||||
self.clear_rx_fifo();
|
self.clear_rx_fifo();
|
||||||
|
|
||||||
// Load number of words
|
// Load number of words
|
||||||
self.i2c_base
|
self.inner
|
||||||
.i2c
|
.regs_priv()
|
||||||
.words()
|
.words()
|
||||||
.write(|w| unsafe { w.bits(len as u32) });
|
.write(|w| unsafe { w.bits(len as u32) });
|
||||||
let (addr, addr_mode_bit) = match addr {
|
let (addr, addr_mode_bit) = match addr {
|
||||||
@ -623,15 +658,15 @@ impl<I2c: Instance, Addr> I2cMaster<I2c, Addr> {
|
|||||||
I2cAddress::TenBit(addr) => (addr, 1 << 15),
|
I2cAddress::TenBit(addr) => (addr, 1 << 15),
|
||||||
};
|
};
|
||||||
// Load address
|
// 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)
|
w.bits(I2cDirection::Read as u32 | (addr << 1) as u32 | addr_mode_bit)
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut buf_iter = buffer.iter_mut();
|
let mut buf_iter = buffer.iter_mut();
|
||||||
let mut read_bytes = 0;
|
let mut read_bytes = 0;
|
||||||
// Start receive transfer
|
// Start receive transfer
|
||||||
self.i2c_base
|
self.inner
|
||||||
.i2c
|
.regs_priv()
|
||||||
.cmd()
|
.cmd()
|
||||||
.write(|w| unsafe { w.bits(I2cCmd::StartWithStop as u32) });
|
.write(|w| unsafe { w.bits(I2cCmd::StartWithStop as u32) });
|
||||||
let mut read_if_next_available = || {
|
let mut read_if_next_available = || {
|
||||||
@ -640,7 +675,7 @@ impl<I2c: Instance, Addr> I2cMaster<I2c, Addr> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
loop {
|
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() {
|
if status_reader.arblost().bit_is_set() {
|
||||||
self.clear_rx_fifo();
|
self.clear_rx_fifo();
|
||||||
return Err(Error::ArbitrationLost);
|
return Err(Error::ArbitrationLost);
|
||||||
@ -664,11 +699,11 @@ impl<I2c: Instance, Addr> I2cMaster<I2c, Addr> {
|
|||||||
// Embedded HAL I2C implementations
|
// Embedded HAL I2C implementations
|
||||||
//======================================================================================
|
//======================================================================================
|
||||||
|
|
||||||
impl<I2c> embedded_hal::i2c::ErrorType for I2cMaster<I2c, SevenBitAddress> {
|
impl embedded_hal::i2c::ErrorType for I2cMaster<SevenBitAddress> {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I2c: Instance> embedded_hal::i2c::I2c for I2cMaster<I2c, SevenBitAddress> {
|
impl embedded_hal::i2c::I2c for I2cMaster<SevenBitAddress> {
|
||||||
fn transaction(
|
fn transaction(
|
||||||
&mut self,
|
&mut self,
|
||||||
address: SevenBitAddress,
|
address: SevenBitAddress,
|
||||||
@ -688,11 +723,11 @@ impl<I2c: Instance> embedded_hal::i2c::I2c for I2cMaster<I2c, SevenBitAddress> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I2c> embedded_hal::i2c::ErrorType for I2cMaster<I2c, TenBitAddress> {
|
impl embedded_hal::i2c::ErrorType for I2cMaster<TenBitAddress> {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I2c: Instance> embedded_hal::i2c::I2c<TenBitAddress> for I2cMaster<I2c, TenBitAddress> {
|
impl embedded_hal::i2c::I2c<TenBitAddress> for I2cMaster<TenBitAddress> {
|
||||||
fn transaction(
|
fn transaction(
|
||||||
&mut self,
|
&mut self,
|
||||||
address: TenBitAddress,
|
address: TenBitAddress,
|
||||||
@ -714,20 +749,20 @@ impl<I2c: Instance> embedded_hal::i2c::I2c<TenBitAddress> for I2cMaster<I2c, Ten
|
|||||||
// I2C Slave
|
// I2C Slave
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
pub struct I2cSlave<I2c, Addr = SevenBitAddress> {
|
pub struct I2cSlave<Addr = SevenBitAddress> {
|
||||||
i2c_base: I2cBase<I2c>,
|
inner: I2cCommon,
|
||||||
addr: PhantomData<Addr>,
|
addr: PhantomData<Addr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I2c: Instance, Addr> I2cSlave<I2c, Addr> {
|
impl<Addr> I2cSlave<Addr> {
|
||||||
fn new_generic(
|
fn new_generic<I2c: I2cMarker>(
|
||||||
sys_clk: Hertz,
|
sys_clk: Hertz,
|
||||||
i2c: I2c,
|
i2c: I2c,
|
||||||
cfg: SlaveConfig,
|
cfg: SlaveConfig,
|
||||||
speed_mode: I2cSpeed,
|
speed_mode: I2cSpeed,
|
||||||
) -> Result<Self, ClockTooSlowForFastI2cError> {
|
) -> Result<Self, ClockTooSlowForFastI2cError> {
|
||||||
Ok(I2cSlave {
|
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,
|
addr: PhantomData,
|
||||||
}
|
}
|
||||||
.enable_slave())
|
.enable_slave())
|
||||||
@ -735,8 +770,8 @@ impl<I2c: Instance, Addr> I2cSlave<I2c, Addr> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn enable_slave(self) -> Self {
|
pub fn enable_slave(self) -> Self {
|
||||||
self.i2c_base
|
self.inner
|
||||||
.i2c
|
.regs_priv()
|
||||||
.s0_ctrl()
|
.s0_ctrl()
|
||||||
.modify(|_, w| w.enable().set_bit());
|
.modify(|_, w| w.enable().set_bit());
|
||||||
self
|
self
|
||||||
@ -744,8 +779,8 @@ impl<I2c: Instance, Addr> I2cSlave<I2c, Addr> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn disable_slave(self) -> Self {
|
pub fn disable_slave(self) -> Self {
|
||||||
self.i2c_base
|
self.inner
|
||||||
.i2c
|
.regs_priv()
|
||||||
.s0_ctrl()
|
.s0_ctrl()
|
||||||
.modify(|_, w| w.enable().clear_bit());
|
.modify(|_, w| w.enable().clear_bit());
|
||||||
self
|
self
|
||||||
@ -753,29 +788,29 @@ impl<I2c: Instance, Addr> I2cSlave<I2c, Addr> {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn load_fifo(&self, word: u8) {
|
fn load_fifo(&self, word: u8) {
|
||||||
self.i2c_base
|
self.inner
|
||||||
.i2c
|
.regs_priv()
|
||||||
.s0_data()
|
.s0_data()
|
||||||
.write(|w| unsafe { w.bits(word as u32) });
|
.write(|w| unsafe { w.bits(word as u32) });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn read_fifo(&self) -> u8 {
|
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]
|
#[inline]
|
||||||
fn clear_tx_fifo(&self) {
|
fn clear_tx_fifo(&self) {
|
||||||
self.i2c_base
|
self.inner
|
||||||
.i2c
|
.regs_priv()
|
||||||
.s0_fifo_clr()
|
.s0_fifo_clr()
|
||||||
.write(|w| w.txfifo().set_bit());
|
.write(|w| w.txfifo().set_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clear_rx_fifo(&self) {
|
fn clear_rx_fifo(&self) {
|
||||||
self.i2c_base
|
self.inner
|
||||||
.i2c
|
.regs_priv()
|
||||||
.s0_fifo_clr()
|
.s0_fifo_clr()
|
||||||
.write(|w| w.rxfifo().set_bit());
|
.write(|w| w.rxfifo().set_bit());
|
||||||
}
|
}
|
||||||
@ -783,7 +818,7 @@ impl<I2c: Instance, Addr> I2cSlave<I2c, Addr> {
|
|||||||
/// Get the last address that was matched by the slave control and the corresponding
|
/// Get the last address that was matched by the slave control and the corresponding
|
||||||
/// master direction
|
/// master direction
|
||||||
pub fn last_address(&self) -> (I2cDirection, u32) {
|
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 {
|
match bits & 0x01 {
|
||||||
0 => (I2cDirection::Send, bits >> 1),
|
0 => (I2cDirection::Send, bits >> 1),
|
||||||
1 => (I2cDirection::Read, bits >> 1),
|
1 => (I2cDirection::Read, bits >> 1),
|
||||||
@ -810,7 +845,7 @@ impl<I2c: Instance, Addr> I2cSlave<I2c, Addr> {
|
|||||||
self.load_fifo(*bytes.next().unwrap());
|
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 = || {
|
let mut load_if_next_available = || {
|
||||||
if let Some(next_byte) = bytes.next() {
|
if let Some(next_byte) = bytes.next() {
|
||||||
self.load_fifo(*next_byte);
|
self.load_fifo(*next_byte);
|
||||||
@ -850,7 +885,7 @@ impl<I2c: Instance, Addr> I2cSlave<I2c, Addr> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
loop {
|
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 status_reader.idle().bit_is_set() {
|
||||||
if read_bytes != len {
|
if read_bytes != len {
|
||||||
return Err(Error::InsufficientDataReceived);
|
return Err(Error::InsufficientDataReceived);
|
||||||
@ -864,9 +899,9 @@ impl<I2c: Instance, Addr> I2cSlave<I2c, Addr> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I2c: Instance> I2cSlave<I2c, SevenBitAddress> {
|
impl I2cSlave<SevenBitAddress> {
|
||||||
/// Create a new I2C slave for seven bit addresses
|
/// Create a new I2C slave for seven bit addresses
|
||||||
pub fn new(
|
pub fn new<I2c: I2cMarker>(
|
||||||
sys_clk: Hertz,
|
sys_clk: Hertz,
|
||||||
i2c: I2c,
|
i2c: I2c,
|
||||||
cfg: SlaveConfig,
|
cfg: SlaveConfig,
|
||||||
@ -879,8 +914,8 @@ impl<I2c: Instance> I2cSlave<I2c, SevenBitAddress> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I2c: Instance> I2cSlave<I2c, TenBitAddress> {
|
impl I2cSlave<TenBitAddress> {
|
||||||
pub fn new_ten_bit_addr(
|
pub fn new_ten_bit_addr<I2c: I2cMarker>(
|
||||||
sys_clk: Hertz,
|
sys_clk: Hertz,
|
||||||
i2c: I2c,
|
i2c: I2c,
|
||||||
cfg: SlaveConfig,
|
cfg: SlaveConfig,
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
use core::convert::Infallible;
|
use core::convert::Infallible;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use vorago_shared_periphs::gpio::IoPeriphPin;
|
||||||
use vorago_shared_periphs::PeripheralSelect;
|
use vorago_shared_periphs::PeripheralSelect;
|
||||||
|
|
||||||
use crate::clock::enable_peripheral_clock;
|
use crate::clock::enable_peripheral_clock;
|
||||||
@ -60,7 +61,7 @@ impl<Mode> PwmPin<Mode> {
|
|||||||
pub fn new<Pin: TimPin, Tim: TimMarker + TimRegInterface>(
|
pub fn new<Pin: TimPin, Tim: TimMarker + TimRegInterface>(
|
||||||
sys_clk: Hertz,
|
sys_clk: Hertz,
|
||||||
pin_and_tim: (Pin, Tim),
|
pin_and_tim: (Pin, Tim),
|
||||||
initial_period: impl Into<Hertz> + Copy,
|
initial_frequency: Hertz,
|
||||||
) -> Result<Self, TimMissmatchError> {
|
) -> Result<Self, TimMissmatchError> {
|
||||||
if Pin::TIM_ID != Tim::ID {
|
if Pin::TIM_ID != Tim::ID {
|
||||||
return Err(TimMissmatchError {
|
return Err(TimMissmatchError {
|
||||||
@ -68,11 +69,12 @@ impl<Mode> PwmPin<Mode> {
|
|||||||
tim_id: Tim::ID,
|
tim_id: Tim::ID,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
IoPeriphPin::new(Pin::PIN_ID, Pin::FUN_SEL, None);
|
||||||
let mut pin = PwmPin {
|
let mut pin = PwmPin {
|
||||||
tim_id: Tim::ID,
|
tim_id: Tim::ID,
|
||||||
current_duty: 0,
|
current_duty: 0,
|
||||||
current_lower_limit: 0,
|
current_lower_limit: 0,
|
||||||
current_period: initial_period.into(),
|
current_period: initial_frequency,
|
||||||
current_rst_val: 0,
|
current_rst_val: 0,
|
||||||
sys_clk,
|
sys_clk,
|
||||||
mode: PhantomData,
|
mode: PhantomData,
|
||||||
@ -84,7 +86,7 @@ impl<Mode> PwmPin<Mode> {
|
|||||||
.tim_clk_enable()
|
.tim_clk_enable()
|
||||||
.modify(|r, w| unsafe { w.bits(r.bits() | pin_and_tim.1.mask_32()) });
|
.modify(|r, w| unsafe { w.bits(r.bits() | pin_and_tim.1.mask_32()) });
|
||||||
pin.enable_pwm_a();
|
pin.enable_pwm_a();
|
||||||
pin.set_period(initial_period);
|
pin.set_period(initial_frequency);
|
||||||
Ok(pin)
|
Ok(pin)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +92,7 @@ pub type SpiRegBlock = pac::spia::RegisterBlock;
|
|||||||
pub trait SpiMarker: Deref<Target = SpiRegBlock> + Sealed {
|
pub trait SpiMarker: Deref<Target = SpiRegBlock> + Sealed {
|
||||||
const ID: SpiId;
|
const ID: SpiId;
|
||||||
const PERIPH_SEL: PeripheralSelect;
|
const PERIPH_SEL: PeripheralSelect;
|
||||||
|
const PTR: *const SpiRegBlock;
|
||||||
|
|
||||||
fn ptr() -> *const SpiRegBlock;
|
fn ptr() -> *const SpiRegBlock;
|
||||||
|
|
||||||
@ -104,6 +105,7 @@ pub trait SpiMarker: Deref<Target = SpiRegBlock> + Sealed {
|
|||||||
impl SpiMarker for pac::Spia {
|
impl SpiMarker for pac::Spia {
|
||||||
const ID: SpiId = SpiId::A;
|
const ID: SpiId = SpiId::A;
|
||||||
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi0;
|
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi0;
|
||||||
|
const PTR: *const SpiRegBlock = Self::PTR;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn ptr() -> *const SpiRegBlock {
|
fn ptr() -> *const SpiRegBlock {
|
||||||
@ -115,6 +117,7 @@ impl Sealed for pac::Spia {}
|
|||||||
impl SpiMarker for pac::Spib {
|
impl SpiMarker for pac::Spib {
|
||||||
const ID: SpiId = SpiId::B;
|
const ID: SpiId = SpiId::B;
|
||||||
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi1;
|
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi1;
|
||||||
|
const PTR: *const SpiRegBlock = Self::PTR;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn ptr() -> *const SpiRegBlock {
|
fn ptr() -> *const SpiRegBlock {
|
||||||
@ -126,6 +129,7 @@ impl Sealed for pac::Spib {}
|
|||||||
impl SpiMarker for pac::Spic {
|
impl SpiMarker for pac::Spic {
|
||||||
const ID: SpiId = SpiId::C;
|
const ID: SpiId = SpiId::C;
|
||||||
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi2;
|
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi2;
|
||||||
|
const PTR: *const SpiRegBlock = Self::PTR;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn ptr() -> *const SpiRegBlock {
|
fn ptr() -> *const SpiRegBlock {
|
||||||
@ -445,7 +449,7 @@ pub struct SpiIdMissmatchError;
|
|||||||
/// SPI peripheral driver structure.
|
/// SPI peripheral driver structure.
|
||||||
pub struct Spi<Word = u8> {
|
pub struct Spi<Word = u8> {
|
||||||
id: SpiId,
|
id: SpiId,
|
||||||
reg_block: *mut SpiRegBlock,
|
reg_block: *const SpiRegBlock,
|
||||||
cfg: SpiConfig,
|
cfg: SpiConfig,
|
||||||
sys_clk: Hertz,
|
sys_clk: Hertz,
|
||||||
/// Fill word for read-only SPI transactions.
|
/// Fill word for read-only SPI transactions.
|
||||||
@ -535,7 +539,7 @@ where
|
|||||||
spi.ctrl1().modify(|_, w| w.enable().set_bit());
|
spi.ctrl1().modify(|_, w| w.enable().set_bit());
|
||||||
Spi {
|
Spi {
|
||||||
id: SpiI::ID,
|
id: SpiI::ID,
|
||||||
reg_block: spi.reg_block(),
|
reg_block: SpiI::PTR,
|
||||||
cfg: spi_cfg,
|
cfg: spi_cfg,
|
||||||
sys_clk,
|
sys_clk,
|
||||||
fill_word: Default::default(),
|
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)]
|
#[inline(always)]
|
||||||
pub fn reg_block(&self) -> &'static SpiRegBlock {
|
pub fn reg_block(&self) -> &'static SpiRegBlock {
|
||||||
unsafe { &*(self.reg_block) }
|
unsafe { &*(self.reg_block) }
|
||||||
@ -612,7 +611,7 @@ where
|
|||||||
/// corresponding [HwChipSelectId].
|
/// corresponding [HwChipSelectId].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn cfg_hw_cs(&mut self, hw_cs: HwChipSelectId) {
|
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();
|
w.sod().clear_bit();
|
||||||
unsafe {
|
unsafe {
|
||||||
w.ss().bits(hw_cs as u8);
|
w.ss().bits(hw_cs as u8);
|
||||||
@ -659,8 +658,8 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn flush_internal(&mut self) {
|
fn flush_internal(&mut self) {
|
||||||
let reg_block_mut = self.reg_block_mut();
|
let reg_block = self.reg_block();
|
||||||
let mut status_reg = reg_block_mut.status().read();
|
let mut status_reg = reg_block.status().read();
|
||||||
while status_reg.tfe().bit_is_clear()
|
while status_reg.tfe().bit_is_clear()
|
||||||
|| status_reg.rne().bit_is_set()
|
|| status_reg.rne().bit_is_set()
|
||||||
|| status_reg.busy().bit_is_set()
|
|| status_reg.busy().bit_is_set()
|
||||||
@ -668,7 +667,7 @@ where
|
|||||||
if status_reg.rne().bit_is_set() {
|
if status_reg.rne().bit_is_set() {
|
||||||
self.read_fifo_unchecked();
|
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
|
// The FIFO can hold a guaranteed amount of data, so we can pump it on transfer
|
||||||
// initialization. Returns the amount of written bytes.
|
// initialization. Returns the amount of written bytes.
|
||||||
fn initial_send_fifo_pumping_with_words(&mut self, words: &[Word]) -> usize {
|
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 {
|
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
|
// Fill the first half of the write FIFO
|
||||||
let mut current_write_idx = 0;
|
let mut current_write_idx = 0;
|
||||||
@ -699,7 +698,7 @@ where
|
|||||||
current_write_idx += 1;
|
current_write_idx += 1;
|
||||||
}
|
}
|
||||||
if self.blockmode {
|
if self.blockmode {
|
||||||
reg_block_mut
|
reg_block
|
||||||
.ctrl1()
|
.ctrl1()
|
||||||
.modify(|_, w| w.mtxpause().clear_bit());
|
.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
|
// The FIFO can hold a guaranteed amount of data, so we can pump it on transfer
|
||||||
// initialization.
|
// initialization.
|
||||||
fn initial_send_fifo_pumping_with_fill_words(&mut self, send_len: usize) -> usize {
|
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 {
|
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
|
// Fill the first half of the write FIFO
|
||||||
let mut current_write_idx = 0;
|
let mut current_write_idx = 0;
|
||||||
@ -725,7 +724,7 @@ where
|
|||||||
current_write_idx += 1;
|
current_write_idx += 1;
|
||||||
}
|
}
|
||||||
if self.blockmode {
|
if self.blockmode {
|
||||||
reg_block_mut
|
reg_block
|
||||||
.ctrl1()
|
.ctrl1()
|
||||||
.modify(|_, w| w.mtxpause().clear_bit());
|
.modify(|_, w| w.mtxpause().clear_bit());
|
||||||
}
|
}
|
||||||
@ -739,7 +738,7 @@ where
|
|||||||
{
|
{
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn write_fifo(&mut self, data: u32) -> nb::Result<(), Infallible> {
|
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);
|
return Err(nb::Error::WouldBlock);
|
||||||
}
|
}
|
||||||
self.write_fifo_unchecked(data);
|
self.write_fifo_unchecked(data);
|
||||||
@ -748,14 +747,14 @@ where
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn write_fifo_unchecked(&mut self, data: u32) {
|
fn write_fifo_unchecked(&mut self, data: u32) {
|
||||||
self.reg_block_mut()
|
self.reg_block()
|
||||||
.data()
|
.data()
|
||||||
.write(|w| unsafe { w.bits(data) });
|
.write(|w| unsafe { w.bits(data) });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn read_fifo(&mut self) -> nb::Result<u32, Infallible> {
|
fn read_fifo(&mut self) -> nb::Result<u32, Infallible> {
|
||||||
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);
|
return Err(nb::Error::WouldBlock);
|
||||||
}
|
}
|
||||||
Ok(self.read_fifo_unchecked())
|
Ok(self.read_fifo_unchecked())
|
||||||
@ -763,7 +762,7 @@ where
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn read_fifo_unchecked(&mut self) -> u32 {
|
fn read_fifo_unchecked(&mut self) -> u32 {
|
||||||
self.reg_block_mut().data().read().bits()
|
self.reg_block().data().read().bits()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,10 +18,10 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use fugit::RateExtU32;
|
use fugit::RateExtU32;
|
||||||
use vorago_shared_periphs::{
|
use vorago_shared_periphs::{
|
||||||
gpio::{Pin, PinIdProvider},
|
gpio::{Pin, PinId, PinIdProvider},
|
||||||
ioconfig::regs::FunSel,
|
ioconfig::regs::FunSel,
|
||||||
sysconfig::enable_peripheral_clock,
|
sysconfig::enable_peripheral_clock,
|
||||||
PeripheralSelect, Port,
|
PeripheralSelect,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Get the peripheral block of a TIM peripheral given the index.
|
/// Get the peripheral block of a TIM peripheral given the index.
|
||||||
@ -161,8 +161,7 @@ impl CascadeSource {
|
|||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
pub trait TimPin: Sealed {
|
pub trait TimPin: Sealed {
|
||||||
const PORT: Port;
|
const PIN_ID: PinId;
|
||||||
const OFFSET: usize;
|
|
||||||
const FUN_SEL: FunSel;
|
const FUN_SEL: FunSel;
|
||||||
const TIM_ID: TimId;
|
const TIM_ID: TimId;
|
||||||
}
|
}
|
||||||
@ -221,8 +220,7 @@ macro_rules! pin_and_tim {
|
|||||||
where
|
where
|
||||||
$Px: PinIdProvider,
|
$Px: PinIdProvider,
|
||||||
{
|
{
|
||||||
const PORT: Port = $Px::ID.port();
|
const PIN_ID: PinId = $Px::ID;
|
||||||
const OFFSET: usize = $Px::ID.offset();
|
|
||||||
const FUN_SEL: FunSel = $FunSel;
|
const FUN_SEL: FunSel = $FunSel;
|
||||||
const TIM_ID: TimId = TimId($ID);
|
const TIM_ID: TimId = TimId($ID);
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ use va108xx_hal::{
|
|||||||
const ADT75_I2C_ADDR: u8 = 0b1001000;
|
const ADT75_I2C_ADDR: u8 = 0b1001000;
|
||||||
|
|
||||||
pub struct Adt75TempSensor {
|
pub struct Adt75TempSensor {
|
||||||
sensor_if: I2cMaster<pac::I2ca, SevenBitAddress>,
|
sensor_if: I2cMaster<SevenBitAddress>,
|
||||||
cmd_buf: [u8; 1],
|
cmd_buf: [u8; 1],
|
||||||
current_reg: RegAddresses,
|
current_reg: RegAddresses,
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,6 @@
|
|||||||
//! which must be provided for async support to work. However, it provides the
|
//! 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
|
//! [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.
|
//! 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 core::future::Future;
|
||||||
|
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
@ -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",
|
"type": "cortex-debug",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
|
@ -31,20 +31,6 @@
|
|||||||
"isDefault": true
|
"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",
|
"label": "rust: cargo build systick",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user