From 24cf17d1c63b0f4ccb6e1ac1d86086542a41700f Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Wed, 31 Jan 2024 15:21:50 -0500 Subject: [PATCH 01/30] Rempace embedded-hal with ehal_02 in preparation to add embedded-hal-1 --- hal/Cargo.toml | 5 +- hal/src/delay.rs | 2 +- hal/src/gpio/dynpin.rs | 4 +- hal/src/gpio/pin.rs | 6 +- hal/src/lib.rs | 3 +- hal/src/peripherals/adc/d11.rs | 2 +- hal/src/peripherals/adc/d5x.rs | 2 +- hal/src/peripherals/eic/d11/pin.rs | 2 +- hal/src/peripherals/eic/d5x/pin.rs | 2 +- hal/src/peripherals/pwm/d11.rs | 2 +- hal/src/peripherals/pwm/d5x.rs | 2 +- hal/src/peripherals/timer/d11.rs | 2 +- hal/src/peripherals/timer/d5x.rs | 2 +- hal/src/peripherals/trng.rs | 2 +- hal/src/peripherals/watchdog.rs | 2 +- hal/src/prelude.rs | 8 +-- hal/src/rtc.rs | 2 +- hal/src/sercom/i2c/impl_ehal.rs | 2 +- hal/src/sercom/spi.rs | 12 ++-- hal/src/sercom/spi/impl_ehal_thumbv6m.rs | 2 +- hal/src/sercom/spi/impl_ehal_thumbv7em.rs | 2 +- hal/src/sercom/spi/reg.rs | 2 +- hal/src/sercom/spi_future.rs | 2 +- hal/src/sercom/uart/impl_ehal.rs | 2 +- hal/src/sleeping_delay.rs | 2 +- hal/src/thumbv6m/watchdog.rs | 69 +++++++++++++++++++++++ hal/src/timer_traits.rs | 2 +- 27 files changed, 109 insertions(+), 38 deletions(-) create mode 100644 hal/src/thumbv6m/watchdog.rs diff --git a/hal/Cargo.toml b/hal/Cargo.toml index f7f2efebb566..fcf7f5ac4343 100644 --- a/hal/Cargo.toml +++ b/hal/Cargo.toml @@ -36,7 +36,8 @@ bitfield = "0.13" bitflags = "1.2.1" cipher = "0.3" cortex-m = "0.7" -embedded-hal = "0.2" +embedded-hal-02 = {package = "embedded-hal", version = "0.2"} +embedded-hal-1 = {package = "embedded-hal", version = "1.0.0"} fugit = "0.3" modular-bitfield = "0.11" nb = "1.0" @@ -184,7 +185,7 @@ enable_unsafe_aes_newblock_cipher = [] max-channels = ["dma"] rtic = ["rtic-monotonic"] sdmmc = ["embedded-sdmmc"] -unproven = ["embedded-hal/unproven"] +unproven = ["embedded-hal-02/unproven"] usb = ["usb-device"] use_rtt = ["jlink_rtt"] diff --git a/hal/src/delay.rs b/hal/src/delay.rs index 94acd83c9376..af74664f9262 100644 --- a/hal/src/delay.rs +++ b/hal/src/delay.rs @@ -4,7 +4,7 @@ use cortex_m::peripheral::syst::SystClkSource; use cortex_m::peripheral::SYST; use crate::clock::GenericClockController; -use crate::ehal::blocking::delay::{DelayMs, DelayUs}; +use crate::ehal_02::blocking::delay::{DelayMs, DelayUs}; use crate::time::Hertz; /// System timer (SysTick) as a delay provider diff --git a/hal/src/gpio/dynpin.rs b/hal/src/gpio/dynpin.rs index 88ee48762944..0b5407788129 100644 --- a/hal/src/gpio/dynpin.rs +++ b/hal/src/gpio/dynpin.rs @@ -63,9 +63,9 @@ use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; use paste::paste; -use crate::ehal::digital::v2::OutputPin; +use crate::ehal_02::digital::v2::OutputPin; #[cfg(feature = "unproven")] -use crate::ehal::digital::v2::{InputPin, StatefulOutputPin, ToggleableOutputPin}; +use crate::ehal_02::digital::v2::{InputPin, StatefulOutputPin, ToggleableOutputPin}; use super::pin::*; use super::reg::RegisterInterface; diff --git a/hal/src/gpio/pin.rs b/hal/src/gpio/pin.rs index 024874160b77..ecb9a181d548 100644 --- a/hal/src/gpio/pin.rs +++ b/hal/src/gpio/pin.rs @@ -71,7 +71,7 @@ //! ``` //! use atsamd_hal::pac::Peripherals; //! use atsamd_hal::gpio::Pins; -//! use embedded_hal::digital::v2::OutputPin; +//! use crate::ehal_02::digital::v2::OutputPin; //! //! let mut peripherals = Peripherals::take().unwrap(); //! let mut pins = Pins::new(peripherals.PORT); @@ -102,9 +102,9 @@ use core::convert::Infallible; use core::marker::PhantomData; use core::mem::transmute; -use crate::ehal::digital::v2::OutputPin; +use crate::ehal_02::digital::v2::OutputPin; #[cfg(feature = "unproven")] -use crate::ehal::digital::v2::{InputPin, StatefulOutputPin, ToggleableOutputPin}; +use crate::ehal_02::digital::v2::{InputPin, StatefulOutputPin, ToggleableOutputPin}; use paste::paste; use crate::pac::PORT; diff --git a/hal/src/lib.rs b/hal/src/lib.rs index 9cc0c53c0b2f..855498a87f48 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -1,6 +1,7 @@ #![no_std] -pub use embedded_hal as ehal; +use embedded_hal_02 as ehal_02; +pub use embedded_hal_1 as ehal; pub use fugit; pub use paste; pub mod typelevel; diff --git a/hal/src/peripherals/adc/d11.rs b/hal/src/peripherals/adc/d11.rs index 9b95942da393..556538eede99 100644 --- a/hal/src/peripherals/adc/d11.rs +++ b/hal/src/peripherals/adc/d11.rs @@ -2,7 +2,7 @@ use atsamd_hal_macros::hal_cfg; use crate::clock::GenericClockController; -use crate::ehal::adc::{Channel, OneShot}; +use crate::ehal_02::adc::{Channel, OneShot}; use crate::gpio::*; use crate::pac::{adc, ADC, PM}; diff --git a/hal/src/peripherals/adc/d5x.rs b/hal/src/peripherals/adc/d5x.rs index 349ee5d128ed..1ccff38f7822 100644 --- a/hal/src/peripherals/adc/d5x.rs +++ b/hal/src/peripherals/adc/d5x.rs @@ -4,7 +4,7 @@ use atsamd_hal_macros::hal_cfg; use crate::clock::GenericClockController; #[rustfmt::skip] use crate::gpio::*; -use crate::ehal::adc::{Channel, OneShot}; +use crate::ehal_02::adc::{Channel, OneShot}; use crate::pac::gclk::genctrl::SRCSELECT_A::DFLL; use crate::pac::gclk::pchctrl::GENSELECT_A; use crate::pac::{adc0, ADC0, ADC1, MCLK}; diff --git a/hal/src/peripherals/eic/d11/pin.rs b/hal/src/peripherals/eic/d11/pin.rs index 55686b395b34..a746e31f58a0 100644 --- a/hal/src/peripherals/eic/d11/pin.rs +++ b/hal/src/peripherals/eic/d11/pin.rs @@ -1,5 +1,5 @@ #[cfg(feature = "unproven")] -use crate::ehal::digital::v2::InputPin; +use crate::ehal_02::digital::v2::InputPin; use crate::gpio::{ self, pin::*, AnyPin, FloatingInterrupt, PinMode, PullDownInterrupt, PullUpInterrupt, }; diff --git a/hal/src/peripherals/eic/d5x/pin.rs b/hal/src/peripherals/eic/d5x/pin.rs index 6eadaf441318..4e5c5670fd6a 100644 --- a/hal/src/peripherals/eic/d5x/pin.rs +++ b/hal/src/peripherals/eic/d5x/pin.rs @@ -1,5 +1,5 @@ #[cfg(feature = "unproven")] -use crate::ehal::digital::v2::InputPin; +use crate::ehal_02::digital::v2::InputPin; use crate::gpio::{ self, pin::*, AnyPin, FloatingInterrupt, PinMode, PullDownInterrupt, PullUpInterrupt, }; diff --git a/hal/src/peripherals/pwm/d11.rs b/hal/src/peripherals/pwm/d11.rs index 1d6be00d9235..0363f0d33481 100644 --- a/hal/src/peripherals/pwm/d11.rs +++ b/hal/src/peripherals/pwm/d11.rs @@ -1,7 +1,7 @@ use atsamd_hal_macros::hal_cfg; use crate::clock; -use crate::ehal::{Pwm, PwmPin}; +use crate::ehal_02::{Pwm, PwmPin}; use crate::pac::PM; use crate::time::Hertz; use crate::timer_params::TimerParams; diff --git a/hal/src/peripherals/pwm/d5x.rs b/hal/src/peripherals/pwm/d5x.rs index 98b24edc32b2..a4fdafd73bad 100644 --- a/hal/src/peripherals/pwm/d5x.rs +++ b/hal/src/peripherals/pwm/d5x.rs @@ -3,7 +3,7 @@ use atsamd_hal_macros::hal_cfg; use crate::clock; -use crate::ehal::{Pwm, PwmPin}; +use crate::ehal_02::{Pwm, PwmPin}; use crate::gpio::*; use crate::gpio::{AlternateE, AnyPin, Pin}; use crate::pac::MCLK; diff --git a/hal/src/peripherals/timer/d11.rs b/hal/src/peripherals/timer/d11.rs index e31ab1c3c15e..0616ae45ee05 100644 --- a/hal/src/peripherals/timer/d11.rs +++ b/hal/src/peripherals/timer/d11.rs @@ -1,7 +1,7 @@ //! Working with timer counter hardware use atsamd_hal_macros::hal_cfg; -use crate::ehal::timer::{CountDown, Periodic}; +use crate::ehal_02::timer::{CountDown, Periodic}; use crate::pac::PM; #[hal_cfg("tc1-d11")] use crate::pac::{tc1::COUNT16, TC1}; diff --git a/hal/src/peripherals/timer/d5x.rs b/hal/src/peripherals/timer/d5x.rs index b841f2ee1e19..67281113bd32 100644 --- a/hal/src/peripherals/timer/d5x.rs +++ b/hal/src/peripherals/timer/d5x.rs @@ -1,7 +1,7 @@ //! Working with timer counter hardware use atsamd_hal_macros::hal_cfg; -use crate::ehal::timer::{CountDown, Periodic}; +use crate::ehal_02::timer::{CountDown, Periodic}; use crate::pac::tc0::COUNT16; use crate::pac::{MCLK, TC2, TC3}; #[hal_cfg(all("tc4", "tc5"))] diff --git a/hal/src/peripherals/trng.rs b/hal/src/peripherals/trng.rs index 226aa53c1f4d..ef34107136c9 100644 --- a/hal/src/peripherals/trng.rs +++ b/hal/src/peripherals/trng.rs @@ -3,7 +3,7 @@ use crate::pac::{MCLK, TRNG}; use rand_core::{CryptoRng, RngCore}; #[cfg(feature = "unproven")] -use embedded_hal::blocking::rng::Read; +use crate::ehal_02::blocking::rng::Read; pub struct Trng(TRNG); diff --git a/hal/src/peripherals/watchdog.rs b/hal/src/peripherals/watchdog.rs index 9fbba9ac6489..1aee5d4dd926 100644 --- a/hal/src/peripherals/watchdog.rs +++ b/hal/src/peripherals/watchdog.rs @@ -1,4 +1,4 @@ -use crate::ehal::watchdog; +use crate::ehal_02::watchdog; use crate::pac::WDT; use atsamd_hal_macros::hal_macro_helper; diff --git a/hal/src/prelude.rs b/hal/src/prelude.rs index d4a5cb869188..702ce1cb38da 100644 --- a/hal/src/prelude.rs +++ b/hal/src/prelude.rs @@ -7,11 +7,11 @@ pub use fugit::RateExtU32 as _; // embedded-hal doesn’t yet have v2 in its prelude, so we need to // export it ourselves #[cfg(feature = "unproven")] -pub use crate::ehal::digital::v2::InputPin as _atsamd_hal_embedded_hal_digital_v2_InputPin; -pub use crate::ehal::digital::v2::OutputPin as _atsamd_hal_embedded_hal_digital_v2_OutputPin; +pub use crate::ehal_02::digital::v2::InputPin as _atsamd_hal_embedded_hal_digital_v2_InputPin; +pub use crate::ehal_02::digital::v2::OutputPin as _atsamd_hal_embedded_hal_digital_v2_OutputPin; #[cfg(feature = "unproven")] -pub use crate::ehal::digital::v2::ToggleableOutputPin as _atsamd_hal_embedded_hal_digital_v2_ToggleableOutputPin; +pub use crate::ehal_02::digital::v2::ToggleableOutputPin as _atsamd_hal_embedded_hal_digital_v2_ToggleableOutputPin; -pub use crate::ehal::prelude::*; +pub use crate::ehal_02::prelude::*; pub use nb; diff --git a/hal/src/rtc.rs b/hal/src/rtc.rs index 35937e6d2449..2113ef9fef42 100644 --- a/hal/src/rtc.rs +++ b/hal/src/rtc.rs @@ -1,7 +1,7 @@ //! Real-time clock/counter use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; -use crate::ehal::timer::{CountDown, Periodic}; +use crate::ehal_02::timer::{CountDown, Periodic}; use crate::pac::rtc::{MODE0, MODE2}; use crate::pac::RTC; use crate::time::{Hertz, Nanoseconds}; diff --git a/hal/src/sercom/i2c/impl_ehal.rs b/hal/src/sercom/i2c/impl_ehal.rs index c582c6dbb4fc..64a70c0b06de 100644 --- a/hal/src/sercom/i2c/impl_ehal.rs +++ b/hal/src/sercom/i2c/impl_ehal.rs @@ -1,7 +1,7 @@ //! `embedded-hal` trait implementations for [`I2c`]s use super::{config::AnyConfig, flags::Error, I2c}; -use embedded_hal::blocking::i2c::{Read, Write, WriteRead}; +use crate::ehal_02::blocking::i2c::{Read, Write, WriteRead}; impl<C: AnyConfig> Write for I2c<C> { type Error = Error; diff --git a/hal/src/sercom/spi.rs b/hal/src/sercom/spi.rs index 2a479a044800..7de9274ce615 100644 --- a/hal/src/sercom/spi.rs +++ b/hal/src/sercom/spi.rs @@ -242,16 +242,16 @@ //! //! Only `Spi` structs can actually perform transactions. To do so, use the //! various embedded HAL traits, like -//! [`spi::FullDuplex`](embedded_hal::spi::FullDuplex), -//! [`serial::Read`](embedded_hal::serial::Read) or -//! [`serial::Write`](embedded_hal::serial::Write). +//! [`spi::FullDuplex`](crate::ehal_02::spi::FullDuplex), +//! [`serial::Read`](crate::ehal_02::serial::Read) or +//! [`serial::Write`](crate::ehal_02::serial::Write). //! See the [`impl_ehal`] module documentation for more details about the //! specific trait implementations, which vary based on [`Size`] and //! [`Capability`]. //! //! ``` //! use nb::block; -//! use embedded_hal::spi::FullDuplex; +//! use crate::ehal_02::spi::FullDuplex; //! //! block!(spi.send(0xAA55)); //! let rcvd: u16 = block!(spi.read()); @@ -303,9 +303,9 @@ use atsamd_hal_macros::{hal_cfg, hal_docs, hal_macro_helper, hal_module}; use core::marker::PhantomData; +use crate::ehal_02::spi; +pub use crate::ehal_02::spi::{Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use bitflags::bitflags; -use embedded_hal::spi; -pub use embedded_hal::spi::{Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use crate::sercom::{pad::SomePad, Sercom, APB_CLK_CTRL}; use crate::time::Hertz; diff --git a/hal/src/sercom/spi/impl_ehal_thumbv6m.rs b/hal/src/sercom/spi/impl_ehal_thumbv6m.rs index ebf502ac5fc1..f504be3f410b 100644 --- a/hal/src/sercom/spi/impl_ehal_thumbv6m.rs +++ b/hal/src/sercom/spi/impl_ehal_thumbv6m.rs @@ -68,7 +68,7 @@ //! These traits are implemented following all of the rules outlined above for //! the different [`Size`] and [`Capability`] options. -use embedded_hal::{blocking, serial, spi}; +use crate::ehal_02::{blocking, serial, spi}; use nb::Error::WouldBlock; use num_traits::{AsPrimitive, PrimInt}; diff --git a/hal/src/sercom/spi/impl_ehal_thumbv7em.rs b/hal/src/sercom/spi/impl_ehal_thumbv7em.rs index dfa8f321ca45..f3f451c2c11e 100644 --- a/hal/src/sercom/spi/impl_ehal_thumbv7em.rs +++ b/hal/src/sercom/spi/impl_ehal_thumbv7em.rs @@ -90,7 +90,7 @@ //! These traits are implemented following all of the rules outlined above for //! the different [`Size`] and [`Capability`] options. -use embedded_hal::{blocking, serial, spi}; +use crate::ehal_02::{blocking, serial, spi}; use nb::Error::WouldBlock; use num_traits::{AsPrimitive, PrimInt}; use typenum::{U1, U2, U3, U4}; diff --git a/hal/src/sercom/spi/reg.rs b/hal/src/sercom/spi/reg.rs index d5cd15a6ca6d..7431bdbd49ac 100644 --- a/hal/src/sercom/spi/reg.rs +++ b/hal/src/sercom/spi/reg.rs @@ -1,6 +1,6 @@ use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; -use embedded_hal::spi; +use crate::ehal_02::spi; #[hal_cfg(any("sercom0-d11", "sercom0-d21"))] use crate::pac::sercom0::SPI; diff --git a/hal/src/sercom/spi_future.rs b/hal/src/sercom/spi_future.rs index b7158f6ae94b..582dee590686 100644 --- a/hal/src/sercom/spi_future.rs +++ b/hal/src/sercom/spi_future.rs @@ -177,7 +177,7 @@ use atsamd_hal_macros::hal_cfg; use core::convert::Infallible; use core::task::Poll; -use embedded_hal::digital::v2::OutputPin; +use crate::ehal_02::digital::v2::OutputPin; use crate::gpio::pin::{OptionalPin, SomePin}; use crate::typelevel::NoneT; diff --git a/hal/src/sercom/uart/impl_ehal.rs b/hal/src/sercom/uart/impl_ehal.rs index 67626fff51b8..0ec38d7127b0 100644 --- a/hal/src/sercom/uart/impl_ehal.rs +++ b/hal/src/sercom/uart/impl_ehal.rs @@ -1,7 +1,7 @@ //! `embedded-hal` trait implementations for [`Uart`]s use super::{DataReg, Error, Flags, Receive, Transmit, Uart, ValidConfig}; -use embedded_hal::{ +use crate::ehal_02::{ blocking, serial::{Read, Write}, }; diff --git a/hal/src/sleeping_delay.rs b/hal/src/sleeping_delay.rs index fb27b220fc53..988d73a56398 100644 --- a/hal/src/sleeping_delay.rs +++ b/hal/src/sleeping_delay.rs @@ -3,7 +3,7 @@ use core::sync::atomic; use cortex_m::asm; use fugit::ExtU32; -use crate::ehal::blocking::delay::{DelayMs, DelayUs}; +use crate::ehal_02::blocking::delay::{DelayMs, DelayUs}; use crate::timer_traits::InterruptDrivenTimer; const NUM_US_IN_S: u32 = 1_000_000; diff --git a/hal/src/thumbv6m/watchdog.rs b/hal/src/thumbv6m/watchdog.rs new file mode 100644 index 000000000000..73cb629139d4 --- /dev/null +++ b/hal/src/thumbv6m/watchdog.rs @@ -0,0 +1,69 @@ +use crate::ehal_02::watchdog; +use crate::pac::WDT; + +/// WatchdogTimeout enumerates usable values for configuring +/// the timeout of the watchdog peripheral. +#[repr(u8)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum WatchdogTimeout { + Cycles8 = 0, + Cycles16, + Cycles32, + Cycles64, + Cycles128, + Cycles256, + Cycles512, + Cycles1K, + Cycles2K, + Cycles4K, + Cycles8K, + Cycles16K, +} + +pub struct Watchdog { + wdt: WDT, +} + +impl Watchdog { + pub fn new(wdt: WDT) -> Self { + Self { wdt } + } +} + +impl watchdog::Watchdog for Watchdog { + /// Feeds an existing watchdog to ensure the processor isn't reset. + /// Sometimes commonly referred to as "kicking" or "refreshing". + fn feed(&mut self) { + self.wdt.clear.write(|w| unsafe { w.clear().bits(0xA5) }); + } +} + +/// Disables a running watchdog timer so the processor won't be reset. +impl watchdog::WatchdogDisable for Watchdog { + fn disable(&mut self) { + // Disable the watchdog timer. + self.wdt.ctrl.write(|w| w.enable().clear_bit()); + // Wait for watchdog timer to be disabled. + while self.wdt.status.read().syncbusy().bit_is_set() {} + } +} + +impl watchdog::WatchdogEnable for Watchdog { + type Time = u8; + + /// Enables a watchdog timer to reset the processor if software is frozen + /// or stalled. + fn start<T>(&mut self, period: T) + where + T: Into<Self::Time>, + { + // Write the timeout configuration. + self.wdt + .config + .write(|w| unsafe { w.per().bits(period.into()) }); + // Enable the watchdog timer. + self.wdt.ctrl.write(|w| w.enable().set_bit()); + // Wait for watchdog timer to be enabled. + while self.wdt.status.read().syncbusy().bit_is_set() {} + } +} diff --git a/hal/src/timer_traits.rs b/hal/src/timer_traits.rs index 335e73049600..09abca8ba03d 100644 --- a/hal/src/timer_traits.rs +++ b/hal/src/timer_traits.rs @@ -1,4 +1,4 @@ -use crate::ehal::timer::{CountDown, Periodic}; +use crate::ehal_02::timer::{CountDown, Periodic}; use crate::time; /// Trait for timers that can enable & disable an interrupt that fires From 3be15a0951ba4b18f8fc431dba719e1c8a336e14 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Wed, 31 Jan 2024 15:42:25 -0500 Subject: [PATCH 02/30] Implementations for `gpio` module --- hal/src/gpio/dynpin.rs | 62 +++++++++++++++++++++--- hal/src/gpio/pin.rs | 107 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 152 insertions(+), 17 deletions(-) diff --git a/hal/src/gpio/dynpin.rs b/hal/src/gpio/dynpin.rs index 0b5407788129..44936a4b98d1 100644 --- a/hal/src/gpio/dynpin.rs +++ b/hal/src/gpio/dynpin.rs @@ -61,12 +61,9 @@ use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; +use crate::ehal::digital::{ErrorKind, ErrorType, InputPin, OutputPin, StatefulOutputPin}; use paste::paste; -use crate::ehal_02::digital::v2::OutputPin; -#[cfg(feature = "unproven")] -use crate::ehal_02::digital::v2::{InputPin, StatefulOutputPin, ToggleableOutputPin}; - use super::pin::*; use super::reg::RegisterInterface; @@ -258,12 +255,19 @@ impl DynRegisters { /// /// [`DynPin`]s are not tracked and verified at compile-time, so run-time /// operations are fallible. This `enum` represents the corresponding errors. +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { /// The pin did not have the correct ID or mode for the requested operation InvalidPinType, } +impl crate::ehal::digital::Error for Error { + fn kind(&self) -> crate::ehal::digital::ErrorKind { + ErrorKind::Other + } +} + //============================================================================== // DynPin //============================================================================== @@ -509,11 +513,13 @@ where } //============================================================================== -// Embedded HAL traits +// Embedded HAL v1 traits //============================================================================== +impl ErrorType for DynPin { + type Error = Error; +} impl OutputPin for DynPin { - type Error = Error; #[inline] fn set_high(&mut self) -> Result<(), Self::Error> { self._set_high() @@ -526,6 +532,46 @@ impl OutputPin for DynPin { #[cfg(feature = "unproven")] impl InputPin for DynPin { + #[inline] + fn is_high(&mut self) -> Result<bool, Self::Error> { + self._is_high() + } + #[inline] + fn is_low(&mut self) -> Result<bool, Self::Error> { + self._is_low() + } +} + +#[cfg(feature = "unproven")] +impl StatefulOutputPin for DynPin { + #[inline] + fn is_set_high(&mut self) -> Result<bool, Self::Error> { + self._is_set_high() + } + #[inline] + fn is_set_low(&mut self) -> Result<bool, Self::Error> { + self._is_set_low() + } +} + +//============================================================================== +// Embedded HAL v0.2 traits +//============================================================================== + +impl crate::ehal_02::digital::v2::OutputPin for DynPin { + type Error = Error; + #[inline] + fn set_high(&mut self) -> Result<(), Self::Error> { + self._set_high() + } + #[inline] + fn set_low(&mut self) -> Result<(), Self::Error> { + self._set_low() + } +} + +#[cfg(feature = "unproven")] +impl crate::ehal_02::digital::v2::InputPin for DynPin { type Error = Error; #[inline] fn is_high(&self) -> Result<bool, Self::Error> { @@ -538,7 +584,7 @@ impl InputPin for DynPin { } #[cfg(feature = "unproven")] -impl ToggleableOutputPin for DynPin { +impl crate::ehal_02::digital::v2::ToggleableOutputPin for DynPin { type Error = Error; #[inline] fn toggle(&mut self) -> Result<(), Self::Error> { @@ -547,7 +593,7 @@ impl ToggleableOutputPin for DynPin { } #[cfg(feature = "unproven")] -impl StatefulOutputPin for DynPin { +impl crate::ehal_02::digital::v2::StatefulOutputPin for DynPin { #[inline] fn is_set_high(&self) -> Result<bool, Self::Error> { self._is_set_high() diff --git a/hal/src/gpio/pin.rs b/hal/src/gpio/pin.rs index ecb9a181d548..acc60d8ee370 100644 --- a/hal/src/gpio/pin.rs +++ b/hal/src/gpio/pin.rs @@ -102,9 +102,7 @@ use core::convert::Infallible; use core::marker::PhantomData; use core::mem::transmute; -use crate::ehal_02::digital::v2::OutputPin; -#[cfg(feature = "unproven")] -use crate::ehal_02::digital::v2::{InputPin, StatefulOutputPin, ToggleableOutputPin}; +use crate::ehal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin}; use paste::paste; use crate::pac::PORT; @@ -882,10 +880,101 @@ pub trait SomePin: AnyPin {} impl<P: AnyPin> SomePin for P {} //============================================================================== -// Embedded HAL traits +// Embedded HAL v1 traits //============================================================================== +impl<I, M> ErrorType for Pin<I, M> +where + I: PinId, + M: PinMode, +{ + type Error = Infallible; +} + impl<I, C> OutputPin for Pin<I, Output<C>> +where + I: PinId, + C: OutputConfig, +{ + #[inline] + fn set_low(&mut self) -> Result<(), Self::Error> { + self._set_low(); + Ok(()) + } + + #[inline] + fn set_high(&mut self) -> Result<(), Self::Error> { + self._set_high(); + Ok(()) + } +} + +impl<I> InputPin for Pin<I, ReadableOutput> +where + I: PinId, +{ + #[inline] + fn is_high(&mut self) -> Result<bool, Self::Error> { + Ok(self._is_high()) + } + #[inline] + fn is_low(&mut self) -> Result<bool, Self::Error> { + Ok(self._is_low()) + } +} + +#[cfg(feature = "unproven")] +impl<I, C> 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()) + } + #[inline] + fn is_low(&mut self) -> Result<bool, Self::Error> { + Ok(self._is_low()) + } +} + +#[cfg(feature = "unproven")] +impl<I, C> InputPin for Pin<I, Interrupt<C>> +where + I: PinId, + C: InterruptConfig, +{ + #[inline] + fn is_high(&mut self) -> Result<bool, Self::Error> { + Ok(self._is_high()) + } + #[inline] + fn is_low(&mut self) -> Result<bool, Self::Error> { + Ok(self._is_low()) + } +} + +impl<I, C> StatefulOutputPin for Pin<I, Output<C>> +where + I: PinId, + C: OutputConfig, +{ + #[inline] + fn is_set_high(&mut self) -> Result<bool, Self::Error> { + Ok(self._is_set_high()) + } + #[inline] + fn is_set_low(&mut self) -> Result<bool, Self::Error> { + Ok(self._is_set_low()) + } +} + +//============================================================================== +// Embedded HAL v0.2 traits +//============================================================================== + +impl<I, C> crate::ehal_02::digital::v2::OutputPin for Pin<I, Output<C>> where I: PinId, C: OutputConfig, @@ -904,7 +993,7 @@ where } #[cfg(feature = "unproven")] -impl<I> InputPin for Pin<I, ReadableOutput> +impl<I> crate::ehal_02::digital::v2::InputPin for Pin<I, ReadableOutput> where I: PinId, { @@ -920,7 +1009,7 @@ where } #[cfg(feature = "unproven")] -impl<I, C> InputPin for Pin<I, Input<C>> +impl<I, C> crate::ehal_02::digital::v2::InputPin for Pin<I, Input<C>> where I: PinId, C: InputConfig, @@ -937,7 +1026,7 @@ where } #[cfg(feature = "unproven")] -impl<I, C> InputPin for Pin<I, Interrupt<C>> +impl<I, C> crate::ehal_02::digital::v2::InputPin for Pin<I, Interrupt<C>> where I: PinId, C: InterruptConfig, @@ -954,7 +1043,7 @@ where } #[cfg(feature = "unproven")] -impl<I, C> ToggleableOutputPin for Pin<I, Output<C>> +impl<I, C> crate::ehal_02::digital::v2::ToggleableOutputPin for Pin<I, Output<C>> where I: PinId, C: OutputConfig, @@ -968,7 +1057,7 @@ where } #[cfg(feature = "unproven")] -impl<I, C> StatefulOutputPin for Pin<I, Output<C>> +impl<I, C> crate::ehal_02::digital::v2::StatefulOutputPin for Pin<I, Output<C>> where I: PinId, C: OutputConfig, From a9ad9ac3fd3e9c78de4d6e4aabd6e0e9552aa24d Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Wed, 31 Jan 2024 15:52:26 -0500 Subject: [PATCH 03/30] Implement i2c --- hal/src/sercom/i2c/impl_ehal.rs | 72 ++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/hal/src/sercom/i2c/impl_ehal.rs b/hal/src/sercom/i2c/impl_ehal.rs index 64a70c0b06de..6b4c19297ae7 100644 --- a/hal/src/sercom/i2c/impl_ehal.rs +++ b/hal/src/sercom/i2c/impl_ehal.rs @@ -1,9 +1,71 @@ -//! `embedded-hal` trait implementations for [`I2c`]s +//! [`embedded-hal`] trait implementations for [`I2c`]s use super::{config::AnyConfig, flags::Error, I2c}; -use crate::ehal_02::blocking::i2c::{Read, Write, WriteRead}; +use crate::ehal::i2c::{self, ErrorKind, ErrorType, NoAcknowledgeSource}; -impl<C: AnyConfig> Write for I2c<C> { +impl i2c::Error for Error { + fn kind(&self) -> ErrorKind { + match self { + Error::BusError => ErrorKind::Bus, + Error::ArbitrationLost => ErrorKind::ArbitrationLoss, + Error::LengthError => ErrorKind::Other, + Error::Nack => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Unknown), + Error::Timeout => ErrorKind::Other, + } + } +} + +impl<C: AnyConfig> ErrorType for I2c<C> { + type Error = Error; +} + +impl<C: AnyConfig> i2c::I2c for I2c<C> { + fn transaction( + &mut self, + address: u8, + operations: &mut [i2c::Operation<'_>], + ) -> Result<(), Self::Error> { + for op in operations { + match op { + i2c::Operation::Read(buf) => { + self.do_read(address, buf)?; + self.cmd_stop(); + } + i2c::Operation::Write(bytes) => { + self.do_write(address, bytes)?; + self.cmd_stop(); + } + } + } + + Ok(()) + } + + fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { + self.do_write(address, bytes)?; + self.cmd_stop(); + Ok(()) + } + + fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { + self.do_read(address, buffer)?; + self.cmd_stop(); + Ok(()) + } + + fn write_read( + &mut self, + address: u8, + bytes: &[u8], + buffer: &mut [u8], + ) -> Result<(), Self::Error> { + self.do_write_read(address, bytes, buffer)?; + self.cmd_stop(); + Ok(()) + } +} + +impl<C: AnyConfig> crate::ehal_02::blocking::i2c::Write for I2c<C> { type Error = Error; fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { @@ -13,7 +75,7 @@ impl<C: AnyConfig> Write for I2c<C> { } } -impl<C: AnyConfig> Read for I2c<C> { +impl<C: AnyConfig> crate::ehal_02::blocking::i2c::Read for I2c<C> { type Error = Error; fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { @@ -23,7 +85,7 @@ impl<C: AnyConfig> Read for I2c<C> { } } -impl<C: AnyConfig> WriteRead for I2c<C> { +impl<C: AnyConfig> crate::ehal_02::blocking::i2c::WriteRead for I2c<C> { type Error = Error; fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { From bf7ed50b5506eb998043d7212e3476def87eddbe Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Wed, 31 Jan 2024 17:16:47 -0500 Subject: [PATCH 04/30] Implement SPI --- hal/src/sercom/spi.rs | 29 +++++++ hal/src/sercom/spi/impl_ehal.rs | 132 ++++++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 hal/src/sercom/spi/impl_ehal.rs diff --git a/hal/src/sercom/spi.rs b/hal/src/sercom/spi.rs index 7de9274ce615..6307e56b9919 100644 --- a/hal/src/sercom/spi.rs +++ b/hal/src/sercom/spi.rs @@ -306,6 +306,7 @@ use core::marker::PhantomData; use crate::ehal_02::spi; pub use crate::ehal_02::spi::{Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use bitflags::bitflags; +use num_traits::AsPrimitive; use crate::sercom::{pad::SomePad, Sercom, APB_CLK_CTRL}; use crate::time::Hertz; @@ -628,6 +629,7 @@ where mode: PhantomData<M>, size: PhantomData<Z>, freq: Hertz, + nop_word: DataWidth, } impl<P: ValidPads> Config<P> { @@ -649,6 +651,7 @@ impl<P: ValidPads> Config<P> { mode: PhantomData, size: PhantomData, freq: freq.into(), + nop_word: 0x00.as_(), } } @@ -715,6 +718,7 @@ where mode: PhantomData, size: PhantomData, freq: self.freq, + nop_word: self.nop_word, } } @@ -866,6 +870,31 @@ where self } + /// Get the NOP word + /// + /// This word is used when reading in Duplex mode, since an equal number of + /// words must be sent in order to avoid overflow errors. + pub fn get_nop_word(&self) -> DataWidth { + self.nop_word + } + + /// Set the NOP word + /// + /// This word is used when reading in Duplex mode, since an equal number of + /// words must be sent in order to avoid overflow errors. + pub fn set_nop_word(&mut self, nop_word: DataWidth) { + self.nop_word = nop_word; + } + + /// Set the NOP word using the builder pattern + /// + /// This word is used when reading in Duplex mode, since an equal number of + /// words must be sent in order to avoid overflow errors. + pub fn nop_word(mut self, nop_word: DataWidth) -> Self { + self.nop_word = nop_word; + self + } + /// Get the baud rate /// /// The returned baud rate may not exactly match what was set. diff --git a/hal/src/sercom/spi/impl_ehal.rs b/hal/src/sercom/spi/impl_ehal.rs new file mode 100644 index 000000000000..490a933652e2 --- /dev/null +++ b/hal/src/sercom/spi/impl_ehal.rs @@ -0,0 +1,132 @@ +use super::*; +use crate::ehal::spi::{self, ErrorKind, ErrorType, SpiBus}; +use num_traits::{AsPrimitive, PrimInt}; + +#[cfg(feature = "thumbv6")] +#[path = "impl_ehal_thumbv6m.rs"] +pub mod impl_ehal_02; + +#[cfg(feature = "thumbv7")] +#[path = "impl_ehal_thumbv7em.rs"] +pub mod impl_ehal_02; + +impl spi::Error for Error { + fn kind(&self) -> ErrorKind { + match self { + Error::Overflow => ErrorKind::Overrun, + Error::LengthError => ErrorKind::Other, + } + } +} + +impl<P, M, C> ErrorType for Spi<Config<P, M, C>, Duplex> +where + Config<P, M, C>: ValidConfig, + P: ValidPads, + M: MasterMode, + C: Size, +{ + type Error = Error; +} + +impl<P, M, C> Spi<Config<P, M, C>, Duplex> +where + Config<P, M, C>: ValidConfig, + P: ValidPads, + M: MasterMode, + C: Size + Copy + 'static, + C::Word: PrimInt + AsPrimitive<DataWidth>, + DataWidth: AsPrimitive<C::Word>, +{ + /// Read and write a single word to the bus simultaneously. + fn transfer_word_in_place(&mut self, word: C::Word) -> Result<C::Word, Error> { + while self.read_flags().contains(Flags::DRE) { + core::hint::spin_loop(); + } + self.read_flags_errors()?; + unsafe { + self.write_data(word.as_()); + } + + while self.read_flags().contains(Flags::TXC | Flags::RXC) { + core::hint::spin_loop(); + } + let word = unsafe { self.read_data().as_() }; + Ok(word) + } + + /// Perform a transfer, word by word. + /// + /// No-op words will be written if `read` is longer than `write`. Extra + /// words are ignored if `write` is longer than `read`. + fn transfer_word_by_word( + &mut self, + read: &mut [C::Word], + write: &[C::Word], + ) -> Result<(), Error> { + let nop_word = self.config.nop_word; + for (r, w) in read + .iter_mut() + .zip(write.iter().chain(core::iter::repeat(&nop_word.as_()))) + { + *r = self.transfer_word_in_place(*w)?; + } + + Ok(()) + } +} + +impl<P, M, C> SpiBus<Word<C>> for Spi<Config<P, M, C>, Duplex> +where + Config<P, M, C>: ValidConfig, + P: ValidPads, + M: MasterMode, + C: Size + Copy + 'static, + C::Word: PrimInt + AsPrimitive<DataWidth>, + DataWidth: AsPrimitive<C::Word>, +{ + fn read(&mut self, words: &mut [Word<C>]) -> Result<(), Self::Error> { + for word in words.iter_mut() { + // Should replace todo with nop_word + *word = self.transfer_word_in_place(self.config.nop_word.as_())?; + } + + Ok(()) + } + + #[inline] + fn write(&mut self, words: &[Word<C>]) -> Result<(), Self::Error> { + // We are `Duplex`, so we must receive as many words as we send, + // otherwise we could trigger an overflow + for word in words { + let _ = self.transfer_word_in_place(*word)?; + } + Ok(()) + } + + #[inline] + fn transfer(&mut self, read: &mut [Word<C>], write: &[Word<C>]) -> Result<(), Self::Error> { + self.transfer_word_by_word(read, write) + } + + #[inline] + fn transfer_in_place<'w>(&mut self, words: &mut [Word<C>]) -> Result<(), Self::Error> { + // Can only ever do word-by-word to avoid DMA race conditions + for word in words { + let read = self.transfer_word_in_place(*word)?; + *word = read; + } + + Ok(()) + } + + #[inline] + fn flush(&mut self) -> Result<(), Error> { + // Ignore buffer overflow errors + while !self.read_flags().contains(Flags::TXC) { + core::hint::spin_loop(); + } + + Ok(()) + } +} From 00a84e867c2096025aa94731d7e3655f6607b600 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Wed, 3 Apr 2024 16:54:47 -0400 Subject: [PATCH 05/30] Adapt to new peripheral macros --- Cargo.toml | 4 + hal/Cargo.toml | 2 + hal/src/sercom/spi.rs | 18 +- hal/src/sercom/spi/impl_ehal.rs | 37 ++-- hal/src/sercom/spi/impl_ehal_thumbv6m.rs | 249 ++++++++++++++++++++-- hal/src/sercom/spi/impl_ehal_thumbv7em.rs | 20 +- hal/src/thumbv6m/watchdog.rs | 69 ------ 7 files changed, 271 insertions(+), 128 deletions(-) create mode 100644 Cargo.toml delete mode 100644 hal/src/thumbv6m/watchdog.rs diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 000000000000..54874e2ffc42 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,4 @@ +[workspace] +resolver = "2" +members = ["hal", "atsamd-hal-macros"] +exclude = ["pac", "boards"] \ No newline at end of file diff --git a/hal/Cargo.toml b/hal/Cargo.toml index fcf7f5ac4343..62bcc5293b17 100644 --- a/hal/Cargo.toml +++ b/hal/Cargo.toml @@ -38,6 +38,8 @@ cipher = "0.3" cortex-m = "0.7" embedded-hal-02 = {package = "embedded-hal", version = "0.2"} embedded-hal-1 = {package = "embedded-hal", version = "1.0.0"} +embedded-hal-nb = "1.0.0" +embedded-io = "0.6" fugit = "0.3" modular-bitfield = "0.11" nb = "1.0" diff --git a/hal/src/sercom/spi.rs b/hal/src/sercom/spi.rs index 6307e56b9919..008e2bd9485c 100644 --- a/hal/src/sercom/spi.rs +++ b/hal/src/sercom/spi.rs @@ -348,11 +348,7 @@ pub mod lengths { }); } -#[hal_module( - any("sercom0-d11", "sercom0-d21") => "spi/impl_ehal_thumbv6m.rs", - "sercom0-d5x" => "spi/impl_ehal_thumbv7em.rs", -)] -pub mod impl_ehal {} +pub mod impl_ehal; //============================================================================= // BitOrder @@ -1300,6 +1296,18 @@ where self.config.as_mut().regs.disable(); self.config } + + /// Block until at least one of the flags specified in `flags`, plus `ERROR`, is set. + /// + /// # Returns `Err(Error)` if an error is detected. + fn block_on_flags(&mut self, flags: Flags) -> Result<(), Error> { + while !self.read_flags().intersects(flags | Flags::ERROR) { + core::hint::spin_loop(); + } + + self.read_flags_errors()?; + Ok(()) + } } #[hal_cfg("sercom0-d5x")] diff --git a/hal/src/sercom/spi/impl_ehal.rs b/hal/src/sercom/spi/impl_ehal.rs index 490a933652e2..a819a59099a7 100644 --- a/hal/src/sercom/spi/impl_ehal.rs +++ b/hal/src/sercom/spi/impl_ehal.rs @@ -1,20 +1,20 @@ use super::*; -use crate::ehal::spi::{self, ErrorKind, ErrorType, SpiBus}; +use crate::ehal::spi::{self, ErrorType, SpiBus}; +#[allow(unused_imports)] +use crate::ehal_02::{blocking, serial}; use num_traits::{AsPrimitive, PrimInt}; -#[cfg(feature = "thumbv6")] -#[path = "impl_ehal_thumbv6m.rs"] -pub mod impl_ehal_02; - -#[cfg(feature = "thumbv7")] -#[path = "impl_ehal_thumbv7em.rs"] -pub mod impl_ehal_02; +#[hal_module( + any("sercom0-d11", "sercom0-d21") => "impl_ehal_thumbv6m.rs", + "sercom0-d5x" => "impl_ehal_thumbv7em.rs" +)] +pub mod impl_ehal_02 {} impl spi::Error for Error { - fn kind(&self) -> ErrorKind { + fn kind(&self) -> crate::ehal::spi::ErrorKind { match self { - Error::Overflow => ErrorKind::Overrun, - Error::LengthError => ErrorKind::Other, + Error::Overflow => crate::ehal::spi::ErrorKind::Overrun, + Error::LengthError => crate::ehal::spi::ErrorKind::Other, } } } @@ -40,17 +40,13 @@ where { /// Read and write a single word to the bus simultaneously. fn transfer_word_in_place(&mut self, word: C::Word) -> Result<C::Word, Error> { - while self.read_flags().contains(Flags::DRE) { - core::hint::spin_loop(); - } - self.read_flags_errors()?; + self.block_on_flags(Flags::DRE)?; + unsafe { self.write_data(word.as_()); } - while self.read_flags().contains(Flags::TXC | Flags::RXC) { - core::hint::spin_loop(); - } + self.block_on_flags(Flags::TXC | Flags::RXC)?; let word = unsafe { self.read_data().as_() }; Ok(word) } @@ -123,10 +119,7 @@ where #[inline] fn flush(&mut self) -> Result<(), Error> { // Ignore buffer overflow errors - while !self.read_flags().contains(Flags::TXC) { - core::hint::spin_loop(); - } - + let _ = self.block_on_flags(Flags::TXC); Ok(()) } } diff --git a/hal/src/sercom/spi/impl_ehal_thumbv6m.rs b/hal/src/sercom/spi/impl_ehal_thumbv6m.rs index f504be3f410b..8c3d5c8355d0 100644 --- a/hal/src/sercom/spi/impl_ehal_thumbv6m.rs +++ b/hal/src/sercom/spi/impl_ehal_thumbv6m.rs @@ -68,33 +68,68 @@ //! These traits are implemented following all of the rules outlined above for //! the different [`Size`] and [`Capability`] options. -use crate::ehal_02::{blocking, serial, spi}; +use super::*; use nb::Error::WouldBlock; use num_traits::{AsPrimitive, PrimInt}; -use super::*; +impl embedded_hal_nb::serial::Error for Error { + fn kind(&self) -> embedded_hal_nb::serial::ErrorKind { + match self { + Error::Overflow => embedded_hal_nb::serial::ErrorKind::Overrun, + Error::LengthError => embedded_hal_nb::serial::ErrorKind::Other, + } + } +} + +impl<P, M, C, D> embedded_hal_nb::serial::ErrorType for Spi<Config<P, M, C>, D> +where + Config<P, M, C>: ValidConfig, + P: ValidPads, + M: OpMode, + C: CharSize, + D: Capability, +{ + type Error = Error; +} + +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + embedded_io::ErrorKind::Other + } +} + +impl<P, M, C, D> embedded_io::ErrorType for Spi<Config<P, M, C>, D> +where + Config<P, M, C>: ValidConfig, + P: ValidPads, + M: OpMode, + C: Size, + D: Capability, +{ + type Error = Error; +} //============================================================================= // serial::Read //============================================================================= -/// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in a [`MasterMode`] +/// Implement [`Read`] for [`Rx`] [`Spi`] structs in a [`MasterMode`] /// -/// `serial::Read` is only implemented for `Spi` structs with `Rx` +/// [`Read`] is only implemented for `Spi` structs with `Rx` /// [`Capability`]. In a `MasterMode`, `Read` has to initiate transactions, so /// it keeps track of the transaction state. If a transaction is in progress, /// it will wait on `RXC`. If not, it will wait on `DRE`, and then send `0`. -impl<P, M, C> serial::Read<C::Word> for Spi<Config<P, M, C>, Rx> +/// +/// [`Read`]: embedded_hal_nb::serial::Read +impl<P, M, C> embedded_hal_nb::serial::Read<C::Word> for Spi<Config<P, M, C>, Rx> where Config<P, M, C>: ValidConfig, P: ValidPads, M: MasterMode, C: CharSize, C::Word: PrimInt, - u16: AsPrimitive<C::Word>, + DataWidth: AsPrimitive<C::Word>, { - type Error = Error; - #[inline] fn read(&mut self) -> nb::Result<C::Word, Error> { let in_progress = self.capability.in_progress; @@ -112,23 +147,48 @@ where } } -/// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in [`Slave`] +/// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in a [`MasterMode`] +/// +/// [`Read`] is only implemented for `Spi` structs with `Rx` +/// [`Capability`]. In a `MasterMode`, `Read` has to initiate transactions, so +/// it keeps track of the transaction state. If a transaction is in progress, +/// it will wait on `RXC`. If not, it will wait on `DRE`, and then send `0`. +/// +/// [`Read`]: crate::ehal_02::serial::Read +impl<P, M, C> serial::Read<C::Word> for Spi<Config<P, M, C>, Rx> +where + Config<P, M, C>: ValidConfig, + P: ValidPads, + M: MasterMode, + C: CharSize, + C::Word: PrimInt, + DataWidth: AsPrimitive<C::Word>, +{ + type Error = Error; + + #[inline] + fn read(&mut self) -> nb::Result<C::Word, Error> { + <Self as embedded_hal_nb::serial::Read<C::Word>>::read(self) + } +} + +/// Implement [`Read`] for [`Rx`] [`Spi`] structs in [`Slave`] /// [`OpMode`] /// -/// `serial::Read` is only implemented for `Spi` structs with `Rx` +/// [`Read`] is only implemented for `Spi` structs with `Rx` /// [`Capability`]. In `Slave` `OpMode`, `Read` does not have to initiate /// transactions, so it does not have to store any internal state. It only has /// to wait on `RXC`. -impl<P, C> serial::Read<C::Word> for Spi<Config<P, Slave, C>, Rx> +/// +/// [`Read`]: embedded_hal_nb::serial::Read +impl<P, C> embedded_hal_nb::serial::Read<C::Word> for Spi<Config<P, Slave, C>, Rx> where Config<P, Slave, C>: ValidConfig, P: ValidPads, C: CharSize, C::Word: PrimInt, - u16: AsPrimitive<C::Word>, + DataWidth: AsPrimitive<C::Word>, { - type Error = Error; - /// Wait for an `RXC` flag, then read the word #[inline] fn read(&mut self) -> nb::Result<C::Word, Error> { @@ -141,22 +201,83 @@ where } } +/// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in [`Slave`] +/// [`OpMode`] +/// +/// [`serial::Read`] is only implemented for `Spi` structs with `Rx` +/// [`Capability`]. In `Slave` `OpMode`, `Read` does not have to initiate +/// transactions, so it does not have to store any internal state. It only has +/// to wait on `RXC`. +impl<P, C> serial::Read<C::Word> for Spi<Config<P, Slave, C>, Rx> +where + Config<P, Slave, C>: ValidConfig, + P: ValidPads, + C: CharSize, + C::Word: PrimInt, + DataWidth: AsPrimitive<C::Word>, +{ + type Error = Error; + + /// Wait for an `RXC` flag, then read the word + #[inline] + fn read(&mut self) -> nb::Result<C::Word, Error> { + <Self as embedded_hal_nb::serial::Read<C::Word>>::read(self) + } +} + +//============================================================================= +// embedded_io::Read +//============================================================================= +impl<P, M> embedded_io::Read for Spi<Config<P, M, EightBit>, Rx> +where + Config<P, M, EightBit>: ValidConfig, + P: ValidPads, + M: MasterMode, +{ + fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { + for byte in buf.iter_mut() { + let w = nb::block!(<Self as embedded_hal_nb::serial::Read>::read(self))?; + *byte = w; + } + + Ok(buf.len()) + } +} + +impl<P> embedded_io::Read for Spi<Config<P, Slave, EightBit>, Rx> +where + Config<P, Slave, EightBit>: ValidConfig, + P: ValidPads, +{ + fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { + for byte in buf.iter_mut() { + let w = nb::block!(<Self as embedded_hal_nb::serial::Read>::read(self))?; + *byte = w; + } + + Ok(buf.len()) + } +} + //============================================================================= // serial::Write //============================================================================= -/// Implement [`serial::Write`] for [`Tx`] [`Spi`] structs +/// Implement [`Write`] for [`Tx`] [`Spi`] structs /// -/// `serial::Write` is only implemented for `Spi` structs with `Tx` +/// [`Write`] is only implemented for `Spi` structs with `Tx` /// [`Capability`]. Because the `Capability` is `Tx`, this implementation never /// reads the DATA register and ignores all buffer overflow errors. -impl<C> serial::Write<C::Word> for Spi<C, Tx> +/// +/// [`Write`]: embedded_hal_nb::serial::Write +impl<P, M, C> embedded_hal_nb::serial::Write<C::Word> for Spi<Config<P, M, C>, Tx> where - C: ValidConfig, - C::Word: PrimInt + AsPrimitive<u16>, + Config<P, M, C>: ValidConfig, + P: ValidPads, + M: OpMode, + C: CharSize, + C::Word: PrimInt + AsPrimitive<DataWidth>, { - type Error = Error; - #[inline] fn write(&mut self, word: C::Word) -> nb::Result<(), Error> { // Ignore buffer overflow errors @@ -179,6 +300,32 @@ where } } +/// Implement [`serial::Write`] for [`Tx`] [`Spi`] structs +/// +/// `serial::Write` is only implemented for `Spi` structs with `Tx` +/// [`Capability`]. Because the `Capability` is `Tx`, this implementation never +/// reads the DATA register and ignores all buffer overflow errors. +impl<P, M, C> serial::Write<C::Word> for Spi<Config<P, M, C>, Tx> +where + Config<P, M, C>: ValidConfig, + P: ValidPads, + M: OpMode, + C: CharSize, + C::Word: PrimInt + AsPrimitive<DataWidth>, +{ + type Error = Error; + + #[inline] + fn write(&mut self, word: C::Word) -> nb::Result<(), Error> { + <Self as embedded_hal_nb::serial::Write<C::Word>>::write(self, word) + } + + #[inline] + fn flush(&mut self) -> nb::Result<(), Error> { + <Self as embedded_hal_nb::serial::Write<C::Word>>::flush(self) + } +} + //============================================================================= // blocking::serial::Write //============================================================================= @@ -190,6 +337,28 @@ where { } +//============================================================================= +// embedded_io::Write +//============================================================================= +impl<P, M> embedded_io::Write for Spi<Config<P, M, EightBit>, Tx> +where + Config<P, M, EightBit>: ValidConfig, + P: ValidPads, + M: OpMode, +{ + fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { + for byte in buf { + nb::block!(<Self as embedded_hal_nb::serial::Write>::write(self, *byte))?; + } + + Ok(buf.len()) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + nb::block!(<Self as embedded_hal_nb::serial::Write>::flush(self)) + } +} + //============================================================================= // spi::FullDuplex //============================================================================= @@ -199,7 +368,43 @@ where /// `spi::FullDuplex` is only implemented when the `Spi` struct has [`Duplex`] /// [`Capability`]. The [`Word`] size used in the implementation depends on the /// corresponding [`CharSize`]. -impl<C> spi::FullDuplex<C::Word> for Spi<C, Duplex> +impl<P, M, C> embedded_hal_nb::spi::FullDuplex<C::Word> for Spi<Config<P, M, C>, Duplex> +where + Config<P, M, C>: ValidConfig, + P: ValidPads, + M: MasterMode, + C: CharSize, + C::Word: PrimInt + AsPrimitive<u16>, + u16: AsPrimitive<C::Word>, +{ + #[inline] + fn read(&mut self) -> nb::Result<C::Word, Error> { + let flags = self.read_flags_errors()?; + if flags.contains(Flags::RXC) { + unsafe { Ok(self.read_data().as_()) } + } else { + Err(WouldBlock) + } + } + + #[inline] + fn write(&mut self, word: C::Word) -> nb::Result<(), Error> { + let flags = self.read_flags_errors()?; + if flags.contains(Flags::DRE) { + unsafe { self.write_data(word.as_()) }; + Ok(()) + } else { + Err(WouldBlock) + } + } +} + +/// Implement [`spi::FullDuplex`] for [`Spi`] structs with [`AtomicSize`] +/// +/// `spi::FullDuplex` is only implemented when the `Spi` struct has [`Duplex`] +/// [`Capability`]. The [`Word`] size used in the implementation depends on the +/// corresponding [`CharSize`]. +impl<C> crate::ehal_02::spi::FullDuplex<C::Word> for Spi<C, Duplex> where C: ValidConfig, C::Word: PrimInt + AsPrimitive<u16>, diff --git a/hal/src/sercom/spi/impl_ehal_thumbv7em.rs b/hal/src/sercom/spi/impl_ehal_thumbv7em.rs index f3f451c2c11e..67dcfbbd6fae 100644 --- a/hal/src/sercom/spi/impl_ehal_thumbv7em.rs +++ b/hal/src/sercom/spi/impl_ehal_thumbv7em.rs @@ -116,7 +116,7 @@ where M: MasterMode, L: Length, L::Word: PrimInt, - u32: AsPrimitive<L::Word>, + DataWidth: AsPrimitive<L::Word>, { type Error = Error; @@ -150,7 +150,7 @@ where P: ValidPads, L: Length, L::Word: PrimInt, - u32: AsPrimitive<L::Word>, + DataWidth: AsPrimitive<L::Word>, { type Error = Error; @@ -178,7 +178,7 @@ impl<C> serial::Write<C::Word> for Spi<C, Tx> where C: ValidConfig, C::Size: AtomicSize, - C::Word: PrimInt + AsPrimitive<u32>, + C::Word: PrimInt + AsPrimitive<DataWidth>, { type Error = Error; @@ -233,8 +233,8 @@ impl<C> spi::FullDuplex<C::Word> for Spi<C, Duplex> where C: ValidConfig, C::Size: AtomicSize, - C::Word: PrimInt + AsPrimitive<u32>, - u32: AsPrimitive<C::Word>, + C::Word: PrimInt + AsPrimitive<DataWidth>, + DataWidth: AsPrimitive<C::Word>, { type Error = Error; @@ -297,7 +297,7 @@ macro_rules! impl_blocking_spi_transfer { Some(cell) => cell.get(), None => unreachable!(), }; - self.config.as_mut().regs.write_data(word as u32); + self.config.as_mut().regs.write_data(word as DataWidth); } if to_recv.len() > to_send.len() && flags.contains(Flags::RXC) { let word = self.config.as_mut().regs.read_data() as Word<$Length>; @@ -404,7 +404,7 @@ macro_rules! impl_blocking_spi_write { Some(word) => *word, None => unreachable!(), }; - self.config.as_mut().regs.write_data(word as u32); + self.config.as_mut().regs.write_data(word as DataWidth); } if to_recv > to_send.len() && flags.contains(Flags::RXC) { self.config.as_mut().regs.read_data() as Word<$Length>; @@ -443,7 +443,7 @@ macro_rules! impl_blocking_spi_write { if self.read_status().contains(Status::LENERR) { return Err(Error::LengthError) } else if self.read_flags().contains(Flags::DRE) { - self.config.as_mut().regs.write_data(*word as u32); + self.config.as_mut().regs.write_data(*word as DataWidth); break } } @@ -607,7 +607,7 @@ macro_rules! impl_blocking_spi_write_iter { loop { let flags = self.read_flags_errors()?; if flags.contains(Flags::DRE) { - unsafe { self.write_data(word as u32) }; + unsafe { self.write_data(word as DataWidth) }; break } } @@ -654,7 +654,7 @@ macro_rules! impl_blocking_spi_write_iter { if self.read_status().contains(Status::LENERR) { return Err(Error::LengthError) } else if self.read_flags().contains(Flags::DRE) { - unsafe { self.write_data(word as u32) }; + unsafe { self.write_data(word as DataWidth) }; break } } diff --git a/hal/src/thumbv6m/watchdog.rs b/hal/src/thumbv6m/watchdog.rs deleted file mode 100644 index 73cb629139d4..000000000000 --- a/hal/src/thumbv6m/watchdog.rs +++ /dev/null @@ -1,69 +0,0 @@ -use crate::ehal_02::watchdog; -use crate::pac::WDT; - -/// WatchdogTimeout enumerates usable values for configuring -/// the timeout of the watchdog peripheral. -#[repr(u8)] -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub enum WatchdogTimeout { - Cycles8 = 0, - Cycles16, - Cycles32, - Cycles64, - Cycles128, - Cycles256, - Cycles512, - Cycles1K, - Cycles2K, - Cycles4K, - Cycles8K, - Cycles16K, -} - -pub struct Watchdog { - wdt: WDT, -} - -impl Watchdog { - pub fn new(wdt: WDT) -> Self { - Self { wdt } - } -} - -impl watchdog::Watchdog for Watchdog { - /// Feeds an existing watchdog to ensure the processor isn't reset. - /// Sometimes commonly referred to as "kicking" or "refreshing". - fn feed(&mut self) { - self.wdt.clear.write(|w| unsafe { w.clear().bits(0xA5) }); - } -} - -/// Disables a running watchdog timer so the processor won't be reset. -impl watchdog::WatchdogDisable for Watchdog { - fn disable(&mut self) { - // Disable the watchdog timer. - self.wdt.ctrl.write(|w| w.enable().clear_bit()); - // Wait for watchdog timer to be disabled. - while self.wdt.status.read().syncbusy().bit_is_set() {} - } -} - -impl watchdog::WatchdogEnable for Watchdog { - type Time = u8; - - /// Enables a watchdog timer to reset the processor if software is frozen - /// or stalled. - fn start<T>(&mut self, period: T) - where - T: Into<Self::Time>, - { - // Write the timeout configuration. - self.wdt - .config - .write(|w| unsafe { w.per().bits(period.into()) }); - // Enable the watchdog timer. - self.wdt.ctrl.write(|w| w.enable().set_bit()); - // Wait for watchdog timer to be enabled. - while self.wdt.status.read().syncbusy().bit_is_set() {} - } -} From 479dcb6477cec53f6fe54ca0e9d12baee6b7d844 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Thu, 4 Apr 2024 17:12:23 -0400 Subject: [PATCH 06/30] Fix compile error --- hal/src/sercom/spi/impl_ehal.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/src/sercom/spi/impl_ehal.rs b/hal/src/sercom/spi/impl_ehal.rs index a819a59099a7..ef0ded89d752 100644 --- a/hal/src/sercom/spi/impl_ehal.rs +++ b/hal/src/sercom/spi/impl_ehal.rs @@ -2,7 +2,7 @@ use super::*; use crate::ehal::spi::{self, ErrorType, SpiBus}; #[allow(unused_imports)] use crate::ehal_02::{blocking, serial}; -use num_traits::{AsPrimitive, PrimInt}; +use num_traits::PrimInt; #[hal_module( any("sercom0-d11", "sercom0-d21") => "impl_ehal_thumbv6m.rs", From 47a2461bb57d304c3b121916fe55c9b3c6fa2f4d Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Thu, 4 Apr 2024 17:56:40 -0400 Subject: [PATCH 07/30] Add copy bounds to sercom wordsize to satisfy ehal-01 --- hal/src/sercom/spi/char_size.rs | 2 +- hal/src/sercom/uart/charsize.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/src/sercom/spi/char_size.rs b/hal/src/sercom/spi/char_size.rs index 19945a6d4465..49e4c729ca89 100644 --- a/hal/src/sercom/spi/char_size.rs +++ b/hal/src/sercom/spi/char_size.rs @@ -24,7 +24,7 @@ use crate::typelevel::Sealed; /// [type-level function]: crate::typelevel#type-level-functions pub trait CharSize: Sealed { /// Word size for the character size - type Word: 'static; + type Word: 'static + Copy; /// Register bit pattern for the corresponding `CharSize` const BITS: u8; diff --git a/hal/src/sercom/uart/charsize.rs b/hal/src/sercom/uart/charsize.rs index b334373ade5e..187c3ea95c60 100644 --- a/hal/src/sercom/uart/charsize.rs +++ b/hal/src/sercom/uart/charsize.rs @@ -11,7 +11,7 @@ use num_traits::{AsPrimitive, PrimInt}; /// use a `u16` word. pub trait CharSize: Sealed { /// Word size for the character size - type Word: 'static + PrimInt + AsPrimitive<DataReg>; + type Word: 'static + PrimInt + AsPrimitive<DataReg> + Copy; } /// Type-level `enum` indicating a [`CharSize`] that is not dynamic From ca8d173b30f156b02537398c0f7df86c09c1b63c Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Thu, 4 Apr 2024 18:17:56 -0400 Subject: [PATCH 08/30] Fix wrong copy bounds --- hal/src/sercom/spi/impl_ehal.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hal/src/sercom/spi/impl_ehal.rs b/hal/src/sercom/spi/impl_ehal.rs index ef0ded89d752..7c8f600b58e2 100644 --- a/hal/src/sercom/spi/impl_ehal.rs +++ b/hal/src/sercom/spi/impl_ehal.rs @@ -34,7 +34,7 @@ where Config<P, M, C>: ValidConfig, P: ValidPads, M: MasterMode, - C: Size + Copy + 'static, + C: Size + 'static, C::Word: PrimInt + AsPrimitive<DataWidth>, DataWidth: AsPrimitive<C::Word>, { @@ -77,8 +77,8 @@ where Config<P, M, C>: ValidConfig, P: ValidPads, M: MasterMode, - C: Size + Copy + 'static, - C::Word: PrimInt + AsPrimitive<DataWidth>, + C: Size + 'static, + C::Word: PrimInt + AsPrimitive<DataWidth> + Copy, DataWidth: AsPrimitive<C::Word>, { fn read(&mut self, words: &mut [Word<C>]) -> Result<(), Self::Error> { From 90ebaf5256c9a028394cbda60c898a883c90e1f3 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Wed, 17 Apr 2024 16:39:42 -0400 Subject: [PATCH 09/30] Impl embedded-io::{Read, Write} for uart --- hal/src/lib.rs | 3 ++ hal/src/sercom/uart/impl_ehal.rs | 73 +++++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/hal/src/lib.rs b/hal/src/lib.rs index 855498a87f48..37a91716e5fd 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -2,6 +2,9 @@ use embedded_hal_02 as ehal_02; pub use embedded_hal_1 as ehal; +#[cfg(feature = "async")] +pub use embedded_hal_async; +pub use embedded_io; pub use fugit; pub use paste; pub mod typelevel; diff --git a/hal/src/sercom/uart/impl_ehal.rs b/hal/src/sercom/uart/impl_ehal.rs index 0ec38d7127b0..9f4283311f9d 100644 --- a/hal/src/sercom/uart/impl_ehal.rs +++ b/hal/src/sercom/uart/impl_ehal.rs @@ -1,6 +1,9 @@ //! `embedded-hal` trait implementations for [`Uart`]s -use super::{DataReg, Error, Flags, Receive, Transmit, Uart, ValidConfig}; +use super::{ + Capability, Config, DataReg, EightBit, Error, Error as UartError, Flags, Receive, Transmit, + Uart, ValidConfig, ValidPads, +}; use crate::ehal_02::{ blocking, serial::{Read, Write}, @@ -65,3 +68,71 @@ where Uart<C, D>: Write<C::Word>, { } + +impl embedded_io::Error for UartError { + fn kind(&self) -> embedded_io::ErrorKind { + embedded_io::ErrorKind::Other + } +} + +impl<C, D> embedded_io::ErrorType for Uart<C, D> +where + C: ValidConfig, + D: Capability, +{ + type Error = UartError; +} + +impl<P, D> embedded_io::Write for Uart<Config<P, EightBit>, D> +where + P: ValidPads, + D: Transmit, +{ + #[inline] + fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { + for byte in buf { + while !self.read_flags().contains(Flags::DRE) { + core::hint::spin_loop(); + } + + unsafe { self.write_data(byte.as_()) }; + } + + Ok(buf.len()) + } + + /// Wait for a `TXC` flag + #[inline] + fn flush(&mut self) -> Result<(), Self::Error> { + while !self.read_flags().contains(Flags::TXC) { + core::hint::spin_loop(); + } + + self.clear_flags(Flags::TXC); + Ok(()) + } +} + +impl<P, D> embedded_io::Read for Uart<Config<P, EightBit>, D> +where + P: ValidPads, + D: Receive, +{ + /// Wait for an `RXC` flag, then read the word + #[inline] + fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { + if buf.is_empty() { + return Ok(0); + } + + for byte in buf.iter_mut() { + let flags = self.read_flags_errors()?; + while !flags.contains(Flags::RXC) { + core::hint::spin_loop(); + } + *byte = unsafe { self.read_data().as_() }; + } + + Ok(buf.len()) + } +} From 26fcf191a5c3ec8501c6f8b4eb507e4780450d32 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Wed, 17 Apr 2024 16:39:52 -0400 Subject: [PATCH 10/30] Fix Tier 1 examples --- boards/atsame54_xpro/examples/blinky_rtic.rs | 7 +++---- boards/feather_m0/examples/i2c.rs | 6 +++--- boards/feather_m0/examples/pwm.rs | 4 ++-- boards/feather_m0/examples/uart.rs | 4 ++-- boards/feather_m4/examples/clocking_v2.rs | 14 ++++++-------- boards/feather_m4/examples/i2c.rs | 4 ++-- boards/feather_m4/examples/nvm_dsu.rs | 2 +- boards/feather_m4/examples/pukcc_test.rs | 2 +- boards/feather_m4/examples/smart_eeprom.rs | 2 +- boards/metro_m0/examples/blinky_rtic.rs | 1 - boards/metro_m4/examples/blinky_basic.rs | 2 -- boards/metro_m4/examples/usb_logging.rs | 2 +- 12 files changed, 22 insertions(+), 28 deletions(-) diff --git a/boards/atsame54_xpro/examples/blinky_rtic.rs b/boards/atsame54_xpro/examples/blinky_rtic.rs index 60e6e0d2eccf..2a8d6563f081 100644 --- a/boards/atsame54_xpro/examples/blinky_rtic.rs +++ b/boards/atsame54_xpro/examples/blinky_rtic.rs @@ -5,10 +5,9 @@ use atsame54_xpro as bsp; use bsp::hal; use bsp::hal::clock::v2 as clock; use dwt_systick_monotonic::DwtSystick; -use dwt_systick_monotonic::ExtU32 as _; +use dwt_systick_monotonic::{fugit::RateExtU32, ExtU32}; // TODO: Any reason this cannot be in a HAL's prelude? -use hal::ehal::digital::v2::StatefulOutputPin as _; -use hal::prelude::*; +use hal::ehal::digital::StatefulOutputPin; use panic_rtt_target as _; use rtt_target::{rprintln, rtt_init_print}; @@ -45,7 +44,7 @@ mod app { bsp::pin_alias!(pins.xosc1_x_in), bsp::pin_alias!(pins.xosc1_x_out), // Xosc1 on Same54Xpro is 12 MHz - 12.MHz(), + 12_u32.MHz(), ) .enable(); diff --git a/boards/feather_m0/examples/i2c.rs b/boards/feather_m0/examples/i2c.rs index 33abce390bdd..8c3f421f4356 100644 --- a/boards/feather_m0/examples/i2c.rs +++ b/boards/feather_m0/examples/i2c.rs @@ -19,8 +19,8 @@ use pac::Peripherals; use hal::clock::GenericClockController; use hal::dmac::{DmaController, PriorityLevel}; -use hal::ehal::blocking::i2c::WriteRead; -use hal::prelude::*; +use hal::ehal::i2c::I2c; +use hal::fugit::RateExtU32; use hal::sercom::i2c; const LENGTH: usize = 1; @@ -57,7 +57,7 @@ fn main() -> ! { let sercom3_clock = &clocks.sercom3_core(&gclk0).unwrap(); let pads = i2c::Pads::new(sda, scl); let mut i2c = i2c::Config::new(&pm, peripherals.SERCOM3, pads, sercom3_clock.freq()) - .baud(100.khz()) + .baud(100.kHz()) .enable(); let mut buffer = [0x00; 1]; diff --git a/boards/feather_m0/examples/pwm.rs b/boards/feather_m0/examples/pwm.rs index 11d9ce2a9aec..8deb883a76bd 100644 --- a/boards/feather_m0/examples/pwm.rs +++ b/boards/feather_m0/examples/pwm.rs @@ -15,7 +15,7 @@ use feather_m0 as bsp; use bsp::pin_alias; use hal::clock::GenericClockController; use hal::delay::Delay; -use hal::prelude::*; +use hal::fugit::RateExtU32; use hal::pwm::Pwm3; use pac::{CorePeripherals, Peripherals}; @@ -38,7 +38,7 @@ fn main() -> ! { let gclk0 = clocks.gclk0(); let mut pwm3 = Pwm3::new( &clocks.tcc2_tc3(&gclk0).unwrap(), - 1.khz(), + 1.kHz(), peripherals.TC3, &mut peripherals.PM, ); diff --git a/boards/feather_m0/examples/uart.rs b/boards/feather_m0/examples/uart.rs index a51495e0fcf3..68c25c3a66b8 100644 --- a/boards/feather_m0/examples/uart.rs +++ b/boards/feather_m0/examples/uart.rs @@ -16,7 +16,7 @@ use feather_m0 as bsp; use bsp::{entry, periph_alias, pin_alias}; use hal::clock::GenericClockController; use hal::dmac::{DmaController, PriorityLevel}; -use hal::prelude::*; +use hal::fugit::RateExtU32; use pac::Peripherals; @@ -49,7 +49,7 @@ fn main() -> ! { // Setup UART peripheral let uart = bsp::uart( &mut clocks, - 9600.hz(), + 9600.Hz(), uart_sercom, &mut pm, uart_rx, diff --git a/boards/feather_m4/examples/clocking_v2.rs b/boards/feather_m4/examples/clocking_v2.rs index a7bbbff2d57a..92714758d04e 100644 --- a/boards/feather_m4/examples/clocking_v2.rs +++ b/boards/feather_m4/examples/clocking_v2.rs @@ -3,8 +3,6 @@ use panic_halt as _; -use core::fmt::Write as _; - use atsamd_hal::{ clock::v2::{ self as clock, @@ -15,10 +13,9 @@ use atsamd_hal::{ rtcosc::RtcOsc, xosc32k::{ControlGainMode, Xosc1k, Xosc32k, Xosc32kBase}, }, - ehal::serial::Read as _, - ehal::serial::Write, + embedded_io::{Read, Write}, + fugit::RateExtU32, gpio::{Pins, PA04, PA05}, - prelude::*, rtc::{ClockMode, Rtc}, sercom::{ uart::{self, BaudMode, Flags, Oversampling}, @@ -142,7 +139,7 @@ mod app { // In the future, the `Rtc` will take ownership of the `RtcOsc` let rtc = Rtc::clock_mode(device.RTC, rtc_osc.freq(), &mut mclk); - writeln!(&mut uart as &mut dyn Write<_, Error = _>, "RTIC booted!").unwrap(); + writeln!(&mut uart as &mut dyn Write<Error = _>, "RTIC booted!").unwrap(); ( SharedResources { uart, rtc }, @@ -156,12 +153,13 @@ mod app { let mut uart = cx.shared.uart; let mut rtc = cx.shared.rtc; // Read from `Uart` to clean interrupt flag - let _ = uart.lock(|u| u.read().unwrap()); + let mut buf = [0]; + let _ = uart.lock(|u| u.read(&mut buf).unwrap()); // Print out `DateTime` coming from `Rtc` uart.lock(|u| { writeln!( - u as &mut dyn Write<_, Error = _>, + u as &mut dyn Write<Error = _>, "{:#?}", rtc.lock(|r| r.current_time()) ) diff --git a/boards/feather_m4/examples/i2c.rs b/boards/feather_m4/examples/i2c.rs index 2925ee62f822..6305b62460b1 100644 --- a/boards/feather_m4/examples/i2c.rs +++ b/boards/feather_m4/examples/i2c.rs @@ -19,8 +19,8 @@ use pac::Peripherals; use hal::clock::GenericClockController; use hal::dmac::{DmaController, PriorityLevel}; -use hal::ehal::blocking::i2c::WriteRead; -use hal::prelude::*; +use hal::ehal::i2c::I2c; +use hal::fugit::RateExtU32; use hal::sercom::i2c; const LENGTH: usize = 1; diff --git a/boards/feather_m4/examples/nvm_dsu.rs b/boards/feather_m4/examples/nvm_dsu.rs index 4f69d0342b02..761914b5288c 100644 --- a/boards/feather_m4/examples/nvm_dsu.rs +++ b/boards/feather_m4/examples/nvm_dsu.rs @@ -12,7 +12,7 @@ use panic_halt as _; use panic_semihosting as _; use bsp::entry; -use ehal::digital::v2::ToggleableOutputPin; +use ehal::digital::StatefulOutputPin; use hal::clock::GenericClockController; use hal::dsu::Dsu; use hal::nvm::{retrieve_bank_size, Bank, Nvm, WriteGranularity, BLOCKSIZE}; diff --git a/boards/feather_m4/examples/pukcc_test.rs b/boards/feather_m4/examples/pukcc_test.rs index ae2389b1e8bf..e1adb33c2d2e 100644 --- a/boards/feather_m4/examples/pukcc_test.rs +++ b/boards/feather_m4/examples/pukcc_test.rs @@ -12,7 +12,7 @@ use panic_halt as _; use panic_semihosting as _; use bsp::entry; -use ehal::digital::v2::ToggleableOutputPin; +use ehal::digital::StatefulOutputPin; use hal::clock::GenericClockController; use hal::pac::{interrupt, CorePeripherals, Peripherals}; use hal::{pukcc::*, usb::UsbBus}; diff --git a/boards/feather_m4/examples/smart_eeprom.rs b/boards/feather_m4/examples/smart_eeprom.rs index 9474b72d9ae3..59a80b284b60 100644 --- a/boards/feather_m4/examples/smart_eeprom.rs +++ b/boards/feather_m4/examples/smart_eeprom.rs @@ -12,7 +12,7 @@ use panic_halt as _; use panic_semihosting as _; use bsp::entry; -use ehal::digital::v2::ToggleableOutputPin; +use ehal::digital::StatefulOutputPin; use hal::clock::GenericClockController; use hal::nvm::{smart_eeprom, Nvm}; use hal::pac::{interrupt, CorePeripherals, Peripherals}; diff --git a/boards/metro_m0/examples/blinky_rtic.rs b/boards/metro_m0/examples/blinky_rtic.rs index 460e6a63757c..8a2757dce7b3 100644 --- a/boards/metro_m0/examples/blinky_rtic.rs +++ b/boards/metro_m0/examples/blinky_rtic.rs @@ -10,7 +10,6 @@ use metro_m0 as bsp; use panic_halt as _; #[cfg(feature = "use_semihosting")] use panic_semihosting as _; -use rtic; #[rtic::app(device = bsp::pac, peripherals = true, dispatchers = [EVSYS])] mod app { diff --git a/boards/metro_m4/examples/blinky_basic.rs b/boards/metro_m4/examples/blinky_basic.rs index 1a3b7b226f9f..0fc83d25e9f1 100644 --- a/boards/metro_m4/examples/blinky_basic.rs +++ b/boards/metro_m4/examples/blinky_basic.rs @@ -3,7 +3,6 @@ use metro_m4 as bsp; -use bsp::ehal; use bsp::hal; use bsp::pac; @@ -17,7 +16,6 @@ use hal::clock::GenericClockController; use hal::prelude::*; use pac::{CorePeripherals, Peripherals}; -use ehal::blocking::delay::DelayMs; use hal::delay::Delay; #[entry] diff --git a/boards/metro_m4/examples/usb_logging.rs b/boards/metro_m4/examples/usb_logging.rs index 92b64d7cb552..8185f24335eb 100644 --- a/boards/metro_m4/examples/usb_logging.rs +++ b/boards/metro_m4/examples/usb_logging.rs @@ -9,7 +9,7 @@ use bsp::pac; use cortex_m::asm::delay as cycle_delay; use cortex_m::peripheral::NVIC; -use ehal::digital::v2::ToggleableOutputPin; +use ehal::digital::StatefulOutputPin; use usb_device::bus::UsbBusAllocator; use usb_device::prelude::*; use usbd_serial::{SerialPort, USB_CLASS_CDC}; From 547b46821246972bc2733dc5eed72ac65ee17407 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Wed, 17 Apr 2024 16:53:49 -0400 Subject: [PATCH 11/30] impl embedded_hal_nb for uart --- hal/src/sercom/uart/impl_ehal.rs | 93 +++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 19 deletions(-) diff --git a/hal/src/sercom/uart/impl_ehal.rs b/hal/src/sercom/uart/impl_ehal.rs index 9f4283311f9d..b86d2489c039 100644 --- a/hal/src/sercom/uart/impl_ehal.rs +++ b/hal/src/sercom/uart/impl_ehal.rs @@ -22,12 +22,7 @@ where /// Wait for an `RXC` flag, then read the word #[inline] fn read(&mut self) -> nb::Result<C::Word, Error> { - let flags = self.read_flags_errors()?; - if flags.contains(Flags::RXC) { - unsafe { Ok(self.read_data().as_()) } - } else { - Err(WouldBlock) - } + <Self as embedded_hal_nb::serial::Read<C::Word>>::read(self) } } @@ -36,28 +31,18 @@ where C: ValidConfig, D: Transmit, { - type Error = core::convert::Infallible; + type Error = UartError; /// Wait for a `DRE` flag, then write a word #[inline] fn write(&mut self, word: C::Word) -> nb::Result<(), Self::Error> { - if self.read_flags().contains(Flags::DRE) { - unsafe { self.write_data(word.as_()) }; - Ok(()) - } else { - Err(WouldBlock) - } + <Self as embedded_hal_nb::serial::Write<C::Word>>::write(self, word) } /// Wait for a `TXC` flag #[inline] fn flush(&mut self) -> nb::Result<(), Self::Error> { - if self.read_flags().contains(Flags::TXC) { - self.clear_flags(Flags::TXC); - Ok(()) - } else { - Err(WouldBlock) - } + <Self as embedded_hal_nb::serial::Write<C::Word>>::flush(self) } } @@ -70,6 +55,7 @@ where } impl embedded_io::Error for UartError { + #[inline] fn kind(&self) -> embedded_io::ErrorKind { embedded_io::ErrorKind::Other } @@ -136,3 +122,72 @@ where Ok(buf.len()) } } + +impl embedded_hal_nb::serial::Error for UartError { + #[inline] + fn kind(&self) -> embedded_hal_nb::serial::ErrorKind { + use embedded_hal_nb::serial::ErrorKind; + + match self { + Self::ParityError => ErrorKind::Parity, + Self::FrameError => ErrorKind::FrameFormat, + Self::Overflow => ErrorKind::Overrun, + _ => ErrorKind::Other, + } + } +} + +impl<C, D, W> embedded_hal_nb::serial::ErrorType for Uart<C, D> +where + C: ValidConfig<Word = W>, + W: Copy, + D: Capability, +{ + type Error = UartError; +} + +impl<C, D> embedded_hal_nb::serial::Read<C::Word> for Uart<C, D> +where + C: ValidConfig, + D: Receive, + DataReg: AsPrimitive<C::Word>, +{ + #[inline] + fn read(&mut self) -> nb::Result<C::Word, Self::Error> { + // Wait for an `RXC` flag, then read the word + let flags = self.read_flags_errors()?; + if flags.contains(Flags::RXC) { + unsafe { Ok(self.read_data().as_()) } + } else { + Err(WouldBlock) + } + } +} + +impl<C, D> embedded_hal_nb::serial::Write<C::Word> for Uart<C, D> +where + C: ValidConfig, + D: Transmit, +{ + /// Wait for a `DRE` flag, then write a word + #[inline] + fn write(&mut self, word: C::Word) -> nb::Result<(), Self::Error> { + if self.read_flags().contains(Flags::DRE) { + unsafe { self.write_data(word.as_()) }; + Ok(()) + } else { + Err(WouldBlock) + } + } + + /// Wait for a `TXC` flag + #[inline] + fn flush(&mut self) -> nb::Result<(), Self::Error> { + if self.read_flags().contains(Flags::TXC) { + self.clear_flags(Flags::TXC); + Ok(()) + } else { + Err(WouldBlock) + } + } +} From c709a0fc0f14d14783c0438be8204ac6e6434ad0 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Wed, 17 Apr 2024 16:55:38 -0400 Subject: [PATCH 12/30] Fix u16::max_value() clippy lint --- hal/src/timer_params.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/src/timer_params.rs b/hal/src/timer_params.rs index 359c0e27bfa8..82b428fd8734 100644 --- a/hal/src/timer_params.rs +++ b/hal/src/timer_params.rs @@ -38,7 +38,7 @@ impl TimerParams { let cycles: u32 = ticks / divider; - if cycles > u16::max_value() as u32 { + if cycles > u16::MAX as u32 { panic!("cycles {} is out of range for a 16 bit counter", cycles); } From 12483268d81af0172517f7533d8d87e4e79196ee Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Wed, 17 Apr 2024 17:06:07 -0400 Subject: [PATCH 13/30] Fix clippy transmute lint --- hal/src/peripherals/pukcc/c_abi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/src/peripherals/pukcc/c_abi.rs b/hal/src/peripherals/pukcc/c_abi.rs index a4c149bcc660..350b85c2ea41 100644 --- a/hal/src/peripherals/pukcc/c_abi.rs +++ b/hal/src/peripherals/pukcc/c_abi.rs @@ -675,7 +675,7 @@ pub trait Service: crate::typelevel::Sealed { pukcl_params.header.u2Status = super::PukclReturnCode::Severe(super::PukclReturnCodeSevere::ComputationNotStarted) .into(); - core::mem::transmute::<_, extern "C" fn(*mut PukclParams)>(Self::FUNCTION_ADDRESS)( + core::mem::transmute::<usize, extern "C" fn(*mut PukclParams)>(Self::FUNCTION_ADDRESS)( pukcl_params, ) } From a79bf5c09dde80cf4f755c150fca401690124c36 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Wed, 17 Apr 2024 17:06:22 -0400 Subject: [PATCH 14/30] Add block_on_flags method to uart --- hal/src/sercom/uart.rs | 7 +++++++ hal/src/sercom/uart/impl_ehal.rs | 16 ++++------------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/hal/src/sercom/uart.rs b/hal/src/sercom/uart.rs index bbcb9dcabe01..cd8d065ce3dc 100644 --- a/hal/src/sercom/uart.rs +++ b/hal/src/sercom/uart.rs @@ -736,6 +736,13 @@ where update(self.config.as_mut()); self.config.as_mut().registers.enable_peripheral(true); } + + /// Block until all the specified flags are set + fn block_on_flags(&mut self, flags: Flags) { + while !self.read_flags().contains(flags) { + core::hint::spin_loop(); + } + } } impl<C, D> Uart<C, D> diff --git a/hal/src/sercom/uart/impl_ehal.rs b/hal/src/sercom/uart/impl_ehal.rs index b86d2489c039..8f4c5678d70d 100644 --- a/hal/src/sercom/uart/impl_ehal.rs +++ b/hal/src/sercom/uart/impl_ehal.rs @@ -77,10 +77,7 @@ where #[inline] fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { for byte in buf { - while !self.read_flags().contains(Flags::DRE) { - core::hint::spin_loop(); - } - + self.block_on_flags(Flags::DRE); unsafe { self.write_data(byte.as_()) }; } @@ -90,10 +87,7 @@ where /// Wait for a `TXC` flag #[inline] fn flush(&mut self) -> Result<(), Self::Error> { - while !self.read_flags().contains(Flags::TXC) { - core::hint::spin_loop(); - } - + self.block_on_flags(Flags::TXC); self.clear_flags(Flags::TXC); Ok(()) } @@ -112,10 +106,8 @@ where } for byte in buf.iter_mut() { - let flags = self.read_flags_errors()?; - while !flags.contains(Flags::RXC) { - core::hint::spin_loop(); - } + self.read_flags_errors()?; + self.block_on_flags(Flags::RXC); *byte = unsafe { self.read_data().as_() }; } From b4fc8d0b9e5f4646ff280bdf8e37beccb6a7cd31 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Wed, 17 Apr 2024 17:47:37 -0400 Subject: [PATCH 15/30] Minor cleanup --- hal/src/sercom/spi/impl_ehal.rs | 2 -- hal/src/sercom/uart.rs | 7 ------- hal/src/sercom/uart/impl_ehal.rs | 16 +++++++--------- 3 files changed, 7 insertions(+), 18 deletions(-) diff --git a/hal/src/sercom/spi/impl_ehal.rs b/hal/src/sercom/spi/impl_ehal.rs index 7c8f600b58e2..e22bfcf11954 100644 --- a/hal/src/sercom/spi/impl_ehal.rs +++ b/hal/src/sercom/spi/impl_ehal.rs @@ -83,7 +83,6 @@ where { fn read(&mut self, words: &mut [Word<C>]) -> Result<(), Self::Error> { for word in words.iter_mut() { - // Should replace todo with nop_word *word = self.transfer_word_in_place(self.config.nop_word.as_())?; } @@ -107,7 +106,6 @@ where #[inline] fn transfer_in_place<'w>(&mut self, words: &mut [Word<C>]) -> Result<(), Self::Error> { - // Can only ever do word-by-word to avoid DMA race conditions for word in words { let read = self.transfer_word_in_place(*word)?; *word = read; diff --git a/hal/src/sercom/uart.rs b/hal/src/sercom/uart.rs index cd8d065ce3dc..bbcb9dcabe01 100644 --- a/hal/src/sercom/uart.rs +++ b/hal/src/sercom/uart.rs @@ -736,13 +736,6 @@ where update(self.config.as_mut()); self.config.as_mut().registers.enable_peripheral(true); } - - /// Block until all the specified flags are set - fn block_on_flags(&mut self, flags: Flags) { - while !self.read_flags().contains(flags) { - core::hint::spin_loop(); - } - } } impl<C, D> Uart<C, D> diff --git a/hal/src/sercom/uart/impl_ehal.rs b/hal/src/sercom/uart/impl_ehal.rs index 8f4c5678d70d..f2bbf41a87c3 100644 --- a/hal/src/sercom/uart/impl_ehal.rs +++ b/hal/src/sercom/uart/impl_ehal.rs @@ -76,9 +76,10 @@ where { #[inline] fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { - for byte in buf { - self.block_on_flags(Flags::DRE); - unsafe { self.write_data(byte.as_()) }; + for word in buf { + nb::block!(<Self as embedded_hal_nb::serial::Write<u8>>::write( + self, *word + ))?; } Ok(buf.len()) @@ -87,8 +88,7 @@ where /// Wait for a `TXC` flag #[inline] fn flush(&mut self) -> Result<(), Self::Error> { - self.block_on_flags(Flags::TXC); - self.clear_flags(Flags::TXC); + nb::block!(<Self as embedded_hal_nb::serial::Write<u8>>::flush(self))?; Ok(()) } } @@ -98,7 +98,6 @@ where P: ValidPads, D: Receive, { - /// Wait for an `RXC` flag, then read the word #[inline] fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { if buf.is_empty() { @@ -106,9 +105,8 @@ where } for byte in buf.iter_mut() { - self.read_flags_errors()?; - self.block_on_flags(Flags::RXC); - *byte = unsafe { self.read_data().as_() }; + let w = nb::block!(<Self as embedded_hal_nb::serial::Read<u8>>::read(self))?; + *byte = w; } Ok(buf.len()) From 74d13319374833e829198bb83b95fab565497958 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Wed, 17 Apr 2024 17:47:58 -0400 Subject: [PATCH 16/30] Impl embedded_hal_nb::serial for spi --- hal/src/sercom/spi.rs | 12 +- hal/src/sercom/spi/impl_ehal_thumbv6m.rs | 4 + hal/src/sercom/spi/impl_ehal_thumbv7em.rs | 144 +++++++++++++++++----- hal/src/sercom/spi/reg.rs | 8 +- 4 files changed, 129 insertions(+), 39 deletions(-) diff --git a/hal/src/sercom/spi.rs b/hal/src/sercom/spi.rs index 008e2bd9485c..81ad21cd4ca2 100644 --- a/hal/src/sercom/spi.rs +++ b/hal/src/sercom/spi.rs @@ -303,11 +303,11 @@ use atsamd_hal_macros::{hal_cfg, hal_docs, hal_macro_helper, hal_module}; use core::marker::PhantomData; -use crate::ehal_02::spi; -pub use crate::ehal_02::spi::{Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use bitflags::bitflags; use num_traits::AsPrimitive; +use crate::ehal; +pub use crate::ehal::spi::{Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use crate::sercom::{pad::SomePad, Sercom, APB_CLK_CTRL}; use crate::time::Hertz; use crate::typelevel::{Is, NoneT, Sealed}; @@ -819,19 +819,19 @@ where /// Get the SPI mode (clock polarity & phase) #[inline] - pub fn get_spi_mode(&self) -> spi::Mode { + pub fn get_spi_mode(&self) -> ehal::spi::Mode { self.regs.get_spi_mode() } /// Set the SPI mode (clock polarity & phase) #[inline] - pub fn set_spi_mode(&mut self, mode: spi::Mode) { + pub fn set_spi_mode(&mut self, mode: ehal::spi::Mode) { self.regs.set_spi_mode(mode); } /// Set the SPI mode (clock polarity & phase) using the builder pattern #[inline] - pub fn spi_mode(mut self, mode: spi::Mode) -> Self { + pub fn spi_mode(mut self, mode: ehal::spi::Mode) -> Self { self.set_spi_mode(mode); self } @@ -1297,7 +1297,7 @@ where self.config } - /// Block until at least one of the flags specified in `flags`, plus `ERROR`, is set. + /// Block until at least one of the flags specified in `flags`, or `ERROR`, is set. /// /// # Returns `Err(Error)` if an error is detected. fn block_on_flags(&mut self, flags: Flags) -> Result<(), Error> { diff --git a/hal/src/sercom/spi/impl_ehal_thumbv6m.rs b/hal/src/sercom/spi/impl_ehal_thumbv6m.rs index 8c3d5c8355d0..2f7789b85485 100644 --- a/hal/src/sercom/spi/impl_ehal_thumbv6m.rs +++ b/hal/src/sercom/spi/impl_ehal_thumbv6m.rs @@ -250,6 +250,10 @@ where P: ValidPads, { fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { + if buf.is_empty() { + return Ok(0); + }; + for byte in buf.iter_mut() { let w = nb::block!(<Self as embedded_hal_nb::serial::Read>::read(self))?; *byte = w; diff --git a/hal/src/sercom/spi/impl_ehal_thumbv7em.rs b/hal/src/sercom/spi/impl_ehal_thumbv7em.rs index 67dcfbbd6fae..d8f66347245a 100644 --- a/hal/src/sercom/spi/impl_ehal_thumbv7em.rs +++ b/hal/src/sercom/spi/impl_ehal_thumbv7em.rs @@ -90,26 +90,59 @@ //! These traits are implemented following all of the rules outlined above for //! the different [`Size`] and [`Capability`] options. -use crate::ehal_02::{blocking, serial, spi}; +use crate::ehal_02; +use crate::sercom::spi::{ + AtomicSize, Capability, Config, DataWidth, Duplex, DynLength, Error, Flags, GreaterThan4, + Length, MasterMode, OpMode, Receive, Rx, Slave, Spi, Status, Tx, ValidConfig, ValidPads, Word, +}; use nb::Error::WouldBlock; use num_traits::{AsPrimitive, PrimInt}; use typenum::{U1, U2, U3, U4}; use crate::pac::sercom0::RegisterBlock; -use super::*; +impl embedded_hal_nb::serial::Error for Error { + fn kind(&self) -> embedded_hal_nb::serial::ErrorKind { + match self { + Error::Overflow => embedded_hal_nb::serial::ErrorKind::Overrun, + Error::LengthError => embedded_hal_nb::serial::ErrorKind::Other, + } + } +} + +impl<C, D> embedded_hal_nb::serial::ErrorType for Spi<C, D> +where + C: ValidConfig, + D: Capability, +{ + type Error = Error; +} + +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + embedded_io::ErrorKind::Other + } +} + +impl<C, D> embedded_io::ErrorType for Spi<C, D> +where + C: ValidConfig, + D: Capability, +{ + type Error = Error; +} //============================================================================= // serial::Read //============================================================================= -/// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in a [`MasterMode`] +/// Implement [`embedded_hal_nb::serial::Read`] for [`Rx`] [`Spi`] structs in a [`MasterMode`] /// /// `serial::Read` is only implemented for `Spi` structs with `Rx` /// [`Capability`]. In a `MasterMode`, `Read` has to initiate transactions, so /// it keeps track of the transaction state. If a transaction is in progress, /// it will wait on `RXC`. If not, it will wait on `DRE`, and then send `0`. -impl<P, M, L> serial::Read<L::Word> for Spi<Config<P, M, L>, Rx> +impl<P, M, L> embedded_hal_nb::serial::Read<L::Word> for Spi<Config<P, M, L>, Rx> where Config<P, M, L>: ValidConfig, P: ValidPads, @@ -118,10 +151,7 @@ where L::Word: PrimInt, DataWidth: AsPrimitive<L::Word>, { - type Error = Error; - - #[inline] - fn read(&mut self) -> nb::Result<L::Word, Error> { + fn read(&mut self) -> nb::Result<L::Word, Self::Error> { let in_progress = self.capability.in_progress; let flags = self.read_flags_errors()?; if !in_progress && flags.contains(Flags::DRE) { @@ -137,6 +167,26 @@ where } } +/// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in a [`MasterMode`] +/// +/// Refer to the [`embedded_hal_nb::serial::Read`] implementation of [`Spi`] for more details. +impl<P, M, L> ehal_02::serial::Read<L::Word> for Spi<Config<P, M, L>, Rx> +where + Config<P, M, L>: ValidConfig, + P: ValidPads, + M: MasterMode, + L: Length, + L::Word: PrimInt, + DataWidth: AsPrimitive<L::Word>, +{ + type Error = Error; + + #[inline] + fn read(&mut self) -> nb::Result<L::Word, Error> { + <Self as embedded_hal_nb::serial::Read<L::Word>>::read(self) + } +} + /// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in [`Slave`] /// [`OpMode`] /// @@ -144,7 +194,7 @@ where /// [`Capability`]. In `Slave` `OpMode`, `Read` does not have to initiate /// transactions, so it does not have to store any internal state. It only has /// to wait on `RXC`. -impl<P, L> serial::Read<L::Word> for Spi<Config<P, Slave, L>, Rx> +impl<P, L> embedded_hal_nb::serial::Read<L::Word> for Spi<Config<P, Slave, L>, Rx> where Config<P, Slave, L>: ValidConfig, P: ValidPads, @@ -152,8 +202,6 @@ where L::Word: PrimInt, DataWidth: AsPrimitive<L::Word>, { - type Error = Error; - #[inline] fn read(&mut self) -> nb::Result<L::Word, Error> { let flags = self.read_flags_errors()?; @@ -165,23 +213,41 @@ where } } +/// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in [`Slave`] +/// [`OpMode`] +/// +/// Refer to the [`embedded_hal_nb::serial::Read`] implementation of [`Spi`] for more details. +impl<P, L> ehal_02::serial::Read<L::Word> for Spi<Config<P, Slave, L>, Rx> +where + Config<P, Slave, L>: ValidConfig, + P: ValidPads, + L: Length, + L::Word: PrimInt, + DataWidth: AsPrimitive<L::Word>, +{ + type Error = Error; + + #[inline] + fn read(&mut self) -> nb::Result<L::Word, Error> { + <Self as embedded_hal_nb::serial::Read<L::Word>>::read(self) + } +} + //============================================================================= // serial::Write //============================================================================= -/// Implement [`serial::Write`] for [`Tx`] [`Spi`] structs +/// Implement [`embedded_hal_nb::serial::Write`] for [`Tx`] [`Spi`] structs /// /// `serial::Write` is only implemented for `Spi` structs with `Tx` /// [`Capability`]. Because the `Capability` is `Tx`, this implementation never /// reads the DATA register and ignores all buffer overflow errors. -impl<C> serial::Write<C::Word> for Spi<C, Tx> +impl<C> embedded_hal_nb::serial::Write<C::Word> for Spi<C, Tx> where C: ValidConfig, C::Size: AtomicSize, C::Word: PrimInt + AsPrimitive<DataWidth>, { - type Error = Error; - #[inline] fn write(&mut self, word: C::Word) -> nb::Result<(), Error> { // Ignore buffer overflow errors @@ -208,14 +274,34 @@ where } } +/// Implement [`serial::Write`] for [`Tx`] [`Spi`] structs +impl<C> ehal_02::serial::Write<C::Word> for Spi<C, Tx> +where + C: ValidConfig, + C::Size: AtomicSize, + C::Word: PrimInt + AsPrimitive<DataWidth>, +{ + type Error = Error; + + #[inline] + fn write(&mut self, word: C::Word) -> nb::Result<(), Error> { + <Self as embedded_hal_nb::serial::Write<C::Word>>::write(self, word) + } + + #[inline] + fn flush(&mut self) -> nb::Result<(), Error> { + <Self as embedded_hal_nb::serial::Write<C::Word>>::flush(self) + } +} + //============================================================================= // blocking::serial::Write //============================================================================= -impl<C> blocking::serial::write::Default<C::Word> for Spi<C, Tx> +impl<C> ehal_02::blocking::serial::write::Default<C::Word> for Spi<C, Tx> where C: ValidConfig, - Spi<C, Tx>: serial::Write<C::Word>, + Spi<C, Tx>: ehal_02::serial::Write<C::Word>, { } @@ -229,7 +315,7 @@ where /// [`Capability`] and the transaction [`Length`] is `<= 4` bytes. When the /// [`Length`] is `<= 4`, the [`Word`] is a primitive integer, with a size that /// depends on the [`Length`] (`u8`, `u16` or `u32`). -impl<C> spi::FullDuplex<C::Word> for Spi<C, Duplex> +impl<C> ehal_02::spi::FullDuplex<C::Word> for Spi<C, Duplex> where C: ValidConfig, C::Size: AtomicSize, @@ -276,7 +362,7 @@ macro_rules! impl_blocking_spi_transfer { /// (`u8`, `u16` or `u32`). /// /// [`Transfer`]: blocking::spi::Transfer - impl<P, M, A> blocking::spi::Transfer<Word<$Length>> for Spi<Config<P, M, $Length>, A> + impl<P, M, A> $crate::ehal_02::blocking::spi::Transfer<Word<$Length>> for Spi<Config<P, M, $Length>, A> where Config<P, M, $Length>: ValidConfig, P: ValidPads, @@ -324,7 +410,7 @@ impl_blocking_spi_transfer!(U1, U2, U3, U4); /// is incorrect, it will panic. /// /// [`Transfer`]: blocking::spi::Transfer -impl<P, M, L, A> blocking::spi::Transfer<u8> for Spi<Config<P, M, L>, A> +impl<P, M, L, A> ehal_02::blocking::spi::Transfer<u8> for Spi<Config<P, M, L>, A> where Config<P, M, L>: ValidConfig, P: ValidPads, @@ -350,7 +436,7 @@ where /// of [`Spi::get_dyn_length`], it will panic. /// /// [`Transfer`]: blocking::spi::Transfer -impl<P, M, A> blocking::spi::Transfer<u8> for Spi<Config<P, M, DynLength>, A> +impl<P, M, A> ehal_02::blocking::spi::Transfer<u8> for Spi<Config<P, M, DynLength>, A> where Config<P, M, DynLength>: ValidConfig, P: ValidPads, @@ -383,7 +469,7 @@ macro_rules! impl_blocking_spi_write { /// (`u8`, `u16` or `u32`). /// /// [`Write`]: blocking::spi::Write - impl<P, M> blocking::spi::Write<Word<$Length>> for Spi<Config<P, M, $Length>, Duplex> + impl<P, M> $crate::ehal_02::blocking::spi::Write<Word<$Length>> for Spi<Config<P, M, $Length>, Duplex> where Config<P, M, $Length>: ValidConfig, P: ValidPads, @@ -426,7 +512,7 @@ macro_rules! impl_blocking_spi_write { /// reads the DATA register and ignores all buffer overflow errors. /// /// [`Write`]: blocking::spi::Write - impl<P, M> blocking::spi::Write<Word<$Length>> for Spi<Config<P, M, $Length>, Tx> + impl<P, M> $crate::ehal_02::blocking::spi::Write<Word<$Length>> for Spi<Config<P, M, $Length>, Tx> where Config<P, M, $Length>: ValidConfig, P: ValidPads, @@ -465,7 +551,7 @@ impl_blocking_spi_write!(U1, U2, U3, U4); /// it will panic. /// /// [`Write`]: blocking::spi::Write -impl<P, M, L> blocking::spi::Write<u8> for Spi<Config<P, M, L>, Duplex> +impl<P, M, L> ehal_02::blocking::spi::Write<u8> for Spi<Config<P, M, L>, Duplex> where Config<P, M, L>: ValidConfig, P: ValidPads, @@ -495,7 +581,7 @@ where /// register and ignores all buffer overflow errors. /// /// [`Write`]: blocking::spi::Write -impl<P, M, L> blocking::spi::Write<u8> for Spi<Config<P, M, L>, Tx> +impl<P, M, L> ehal_02::blocking::spi::Write<u8> for Spi<Config<P, M, L>, Tx> where Config<P, M, L>: ValidConfig, P: ValidPads, @@ -522,7 +608,7 @@ where /// [`Spi::get_dyn_length`], it will panic. /// /// [`Write`]: blocking::spi::Write -impl<P, M> blocking::spi::Write<u8> for Spi<Config<P, M, DynLength>, Duplex> +impl<P, M> ehal_02::blocking::spi::Write<u8> for Spi<Config<P, M, DynLength>, Duplex> where Config<P, M, DynLength>: ValidConfig, P: ValidPads, @@ -551,7 +637,7 @@ where /// register and ignores all buffer overflow errors. /// /// [`Write`]: blocking::spi::Write -impl<P, M> blocking::spi::Write<u8> for Spi<Config<P, M, DynLength>, Tx> +impl<P, M> ehal_02::blocking::spi::Write<u8> for Spi<Config<P, M, DynLength>, Tx> where Config<P, M, DynLength>: ValidConfig, P: ValidPads, @@ -586,7 +672,7 @@ macro_rules! impl_blocking_spi_write_iter { /// /// [`WriteIter`]: blocking::spi::WriteIter #[cfg(feature = "unproven")] - impl<P, M> blocking::spi::WriteIter<Word<$Length>> for Spi<Config<P, M, $Length>, Duplex> + impl<P, M> $crate::ehal_02::blocking::spi::WriteIter<Word<$Length>> for Spi<Config<P, M, $Length>, Duplex> where Config<P, M, $Length>: ValidConfig, P: ValidPads, @@ -634,7 +720,7 @@ macro_rules! impl_blocking_spi_write_iter { /// /// [`WriteIter`]: blocking::spi::WriteIter #[cfg(feature = "unproven")] - impl<P, M> blocking::spi::WriteIter<Word<$Length>> for Spi<Config<P, M, $Length>, Tx> + impl<P, M> $crate::ehal_02::blocking::spi::WriteIter<Word<$Length>> for Spi<Config<P, M, $Length>, Tx> where Config<P, M, $Length>: ValidConfig, P: ValidPads, diff --git a/hal/src/sercom/spi/reg.rs b/hal/src/sercom/spi/reg.rs index 7431bdbd49ac..f8dcf0f0f487 100644 --- a/hal/src/sercom/spi/reg.rs +++ b/hal/src/sercom/spi/reg.rs @@ -1,6 +1,6 @@ use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; -use crate::ehal_02::spi; +use crate::ehal; #[hal_cfg(any("sercom0-d11", "sercom0-d21"))] use crate::pac::sercom0::SPI; @@ -160,7 +160,7 @@ impl<S: Sercom> Registers<S> { /// Get the SPI mode (clock polarity & phase) #[inline] - pub fn get_spi_mode(&self) -> spi::Mode { + pub fn get_spi_mode(&self) -> ehal::spi::Mode { let reg = self.spi().ctrla.read(); let cpol = reg.cpol().bit(); let cpha = reg.cpha().bit(); @@ -172,12 +172,12 @@ impl<S: Sercom> Registers<S> { false => Phase::CaptureOnFirstTransition, true => Phase::CaptureOnSecondTransition, }; - spi::Mode { polarity, phase } + ehal::spi::Mode { polarity, phase } } /// Set the SPI mode (clock polarity & phase) #[inline] - pub fn set_spi_mode(&mut self, mode: spi::Mode) { + pub fn set_spi_mode(&mut self, mode: ehal::spi::Mode) { let cpol = match mode.polarity { Polarity::IdleLow => false, Polarity::IdleHigh => true, From a19e6e04db38ae31aba93364723159a44f3374bc Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Thu, 18 Apr 2024 13:55:00 -0400 Subject: [PATCH 17/30] Update changelogs --- boards/atsame54_xpro/CHANGELOG.md | 1 + boards/feather_m0/CHANGELOG.md | 1 + boards/feather_m4/CHANGELOG.md | 1 + boards/metro_m0/CHANGELOG.md | 1 + boards/metro_m4/CHANGELOG.md | 1 + boards/samd11_bare/CHANGELOG.md | 1 + hal/CHANGELOG.md | 1 + 7 files changed, 7 insertions(+) diff --git a/boards/atsame54_xpro/CHANGELOG.md b/boards/atsame54_xpro/CHANGELOG.md index 8eda981f90cd..c9fb5dc7e074 100644 --- a/boards/atsame54_xpro/CHANGELOG.md +++ b/boards/atsame54_xpro/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased +- Implement `embedded-hal` `1.0` for GPIO, SPI, I2C, UART and fix examples - Update the PACs to svd2rust 0.30.2. # v0.6.0 diff --git a/boards/feather_m0/CHANGELOG.md b/boards/feather_m0/CHANGELOG.md index c0551c59500b..1b8a61f6aae2 100644 --- a/boards/feather_m0/CHANGELOG.md +++ b/boards/feather_m0/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased +- Implement `embedded-hal` `1.0` for GPIO, SPI, I2C, UART and fix examples - Update the PACs to svd2rust 0.30.2. # v0.13.0 diff --git a/boards/feather_m4/CHANGELOG.md b/boards/feather_m4/CHANGELOG.md index 5e2d7184e94a..e9282103a41c 100644 --- a/boards/feather_m4/CHANGELOG.md +++ b/boards/feather_m4/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased +- Implement `embedded-hal` `1.0` for GPIO, SPI, I2C, UART and fix examples - Update the PACs to svd2rust 0.30.2. # v0.11.0 diff --git a/boards/metro_m0/CHANGELOG.md b/boards/metro_m0/CHANGELOG.md index 79cabefc76d1..42791da46be0 100644 --- a/boards/metro_m0/CHANGELOG.md +++ b/boards/metro_m0/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased +- Implement `embedded-hal` `1.0` for GPIO, SPI, I2C, UART and fix examples - Update the PACs to svd2rust 0.30.2. # v0.13.0 diff --git a/boards/metro_m4/CHANGELOG.md b/boards/metro_m4/CHANGELOG.md index c1a934dca59c..06e86ef25f9f 100644 --- a/boards/metro_m4/CHANGELOG.md +++ b/boards/metro_m4/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased +- Implement `embedded-hal` `1.0` for GPIO, SPI, I2C, UART and fix examples - Update the PACs to svd2rust 0.30.2. # v0.12.0 diff --git a/boards/samd11_bare/CHANGELOG.md b/boards/samd11_bare/CHANGELOG.md index 78f114a1fde4..350c0846ed9b 100644 --- a/boards/samd11_bare/CHANGELOG.md +++ b/boards/samd11_bare/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased +- Implement `embedded-hal` `1.0` for GPIO, SPI, I2C, UART and fix examples - Update the PACs to svd2rust 0.30.2. # v0.9.0 diff --git a/hal/CHANGELOG.md b/hal/CHANGELOG.md index 0e051eca2564..51817a4bbbcb 100644 --- a/hal/CHANGELOG.md +++ b/hal/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased Changes +- Implement `embedded-hal` `1.0` for GPIO, SPI, I2C, UART - CI/CD pipeline now uses `cargo clippy` instead of `cargo build` and denies clippy warnings by default - Fix HAL clippy lints - Add compile error for combined `library` and `dma` features From af91c6a7981f658a0038ea5fa33cdd646d08523c Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Mon, 29 Apr 2024 10:21:12 -0400 Subject: [PATCH 18/30] Implement ehal-1 timer traits --- hal/src/lib.rs | 3 +- hal/src/peripherals/timer/d11.rs | 44 ++++++++++++++++++++---------- hal/src/peripherals/timer/d5x.rs | 47 +++++++++++++++++++++----------- hal/src/rtc.rs | 46 ++++++++++++++++++++----------- hal/src/sleeping_delay.rs | 41 ++++++++++++++++------------ hal/src/timer_params.rs | 8 +++--- hal/src/timer_traits.rs | 15 +++++++--- 7 files changed, 129 insertions(+), 75 deletions(-) diff --git a/hal/src/lib.rs b/hal/src/lib.rs index 37a91716e5fd..3c8b3ac3ca9f 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -2,8 +2,6 @@ use embedded_hal_02 as ehal_02; pub use embedded_hal_1 as ehal; -#[cfg(feature = "async")] -pub use embedded_hal_async; pub use embedded_io; pub use fugit; pub use paste; @@ -81,6 +79,7 @@ pub mod dmac; #[doc(hidden)] mod peripherals; #[doc(inline)] +#[allow(unused_imports)] pub use crate::peripherals::*; #[macro_use] diff --git a/hal/src/peripherals/timer/d11.rs b/hal/src/peripherals/timer/d11.rs index 0616ae45ee05..486f28b4b215 100644 --- a/hal/src/peripherals/timer/d11.rs +++ b/hal/src/peripherals/timer/d11.rs @@ -1,5 +1,8 @@ //! Working with timer counter hardware +use core::convert::Infallible; + use atsamd_hal_macros::hal_cfg; +use fugit::NanosDurationU32; use crate::ehal_02::timer::{CountDown, Periodic}; use crate::pac::PM; @@ -12,7 +15,6 @@ use crate::timer_params::TimerParams; use crate::clock; use crate::time::{Hertz, Nanoseconds}; use crate::timer_traits::InterruptDrivenTimer; -use void::Void; // Note: // TC3 + TC4 can be paired to make a 32-bit counter @@ -33,6 +35,8 @@ pub struct TimerCounter<TC> { tc: TC, } +impl<TC: Count16> TimerCounter<TC> {} + /// This is a helper trait to make it easier to make most of the /// TimerCounter impl generic. It doesn't make too much sense to /// to try to implement this trait outside of this module. @@ -51,6 +55,29 @@ where where T: Into<Self::Time>, { + <Self as InterruptDrivenTimer>::start(self, timeout); + } + + fn wait(&mut self) -> nb::Result<(), void::Void> { + // Unwrapping an unreacheable error is totally OK + <Self as InterruptDrivenTimer>::wait(self).unwrap(); + Ok(()) + } +} + +impl<TC> InterruptDrivenTimer for TimerCounter<TC> +where + TC: Count16, +{ + /// Enable the interrupt generation for this hardware timer. + /// This method only sets the clock configuration to trigger + /// the interrupt; it does not configure the interrupt controller + /// or define an interrupt handler. + fn enable_interrupt(&mut self) { + self.tc.count_16().intenset.write(|w| w.ovf().set_bit()); + } + + fn start<T: Into<NanosDurationU32>>(&mut self, timeout: T) { let params = TimerParams::new_us(timeout.into(), self.freq); let divider = params.divider; let cycles = params.cycles; @@ -98,7 +125,7 @@ where }); } - fn wait(&mut self) -> nb::Result<(), Void> { + fn wait(&mut self) -> nb::Result<(), Infallible> { let count = self.tc.count_16(); if count.intflag.read().ovf().bit_is_set() { // Writing a 1 clears the flag @@ -108,19 +135,6 @@ where Err(nb::Error::WouldBlock) } } -} - -impl<TC> InterruptDrivenTimer for TimerCounter<TC> -where - TC: Count16, -{ - /// Enable the interrupt generation for this hardware timer. - /// This method only sets the clock configuration to trigger - /// the interrupt; it does not configure the interrupt controller - /// or define an interrupt handler. - fn enable_interrupt(&mut self) { - self.tc.count_16().intenset.write(|w| w.ovf().set_bit()); - } /// Disables interrupt generation for this hardware timer. /// This method only sets the clock configuration to prevent diff --git a/hal/src/peripherals/timer/d5x.rs b/hal/src/peripherals/timer/d5x.rs index 67281113bd32..3d5877e01638 100644 --- a/hal/src/peripherals/timer/d5x.rs +++ b/hal/src/peripherals/timer/d5x.rs @@ -1,5 +1,8 @@ //! Working with timer counter hardware +use core::convert::Infallible; + use atsamd_hal_macros::hal_cfg; +use fugit::NanosDurationU32; use crate::ehal_02::timer::{CountDown, Periodic}; use crate::pac::tc0::COUNT16; @@ -11,7 +14,6 @@ use crate::timer_traits::InterruptDrivenTimer; use crate::clock; use crate::time::{Hertz, Nanoseconds}; -use void::Void; // Note: // TC3 + TC4 can be paired to make a 32-bit counter @@ -50,7 +52,33 @@ where where T: Into<Self::Time>, { - let params = TimerParams::new_us(timeout.into(), self.freq); + <Self as InterruptDrivenTimer>::start(self, timeout); + } + + fn wait(&mut self) -> nb::Result<(), void::Void> { + // Unwrapping an unreacheable error is totally OK + <Self as InterruptDrivenTimer>::wait(self).unwrap(); + Ok(()) + } +} + +impl<TC> InterruptDrivenTimer for TimerCounter<TC> +where + TC: Count16, +{ + /// Enable the interrupt generation for this hardware timer. + /// This method only sets the clock configuration to trigger + /// the interrupt; it does not configure the interrupt controller + /// or define an interrupt handler. + fn enable_interrupt(&mut self) { + self.tc.count_16().intenset.write(|w| w.ovf().set_bit()); + } + + fn start<T>(&mut self, timeout: T) + where + T: Into<NanosDurationU32>, + { + let params = TimerParams::new_ns(timeout.into(), self.freq); let divider = params.divider; let cycles = params.cycles; let count = self.tc.count_16(); @@ -98,7 +126,7 @@ where }); } - fn wait(&mut self) -> nb::Result<(), Void> { + fn wait(&mut self) -> nb::Result<(), Infallible> { let count = self.tc.count_16(); if count.intflag.read().ovf().bit_is_set() { // Writing a 1 clears the flag @@ -108,19 +136,6 @@ where Err(nb::Error::WouldBlock) } } -} - -impl<TC> InterruptDrivenTimer for TimerCounter<TC> -where - TC: Count16, -{ - /// Enable the interrupt generation for this hardware timer. - /// This method only sets the clock configuration to trigger - /// the interrupt; it does not configure the interrupt controller - /// or define an interrupt handler. - fn enable_interrupt(&mut self) { - self.tc.count_16().intenset.write(|w| w.ovf().set_bit()); - } /// Disables interrupt generation for this hardware timer. /// This method only sets the clock configuration to prevent diff --git a/hal/src/rtc.rs b/hal/src/rtc.rs index 2113ef9fef42..5259178abde8 100644 --- a/hal/src/rtc.rs +++ b/hal/src/rtc.rs @@ -1,14 +1,15 @@ //! Real-time clock/counter use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; +use fugit::NanosDurationU32; -use crate::ehal_02::timer::{CountDown, Periodic}; +use crate::ehal_02; use crate::pac::rtc::{MODE0, MODE2}; use crate::pac::RTC; use crate::time::{Hertz, Nanoseconds}; use crate::timer_traits::InterruptDrivenTimer; use crate::typelevel::Sealed; +use core::convert::Infallible; use core::marker::PhantomData; -use void::Void; #[cfg(feature = "sdmmc")] use embedded_sdmmc::{TimeSource, Timestamp}; @@ -277,7 +278,7 @@ impl Rtc<Count32Mode> { /// This resets the internal counter and sets the prescaler to match the /// provided timeout. You should configure the prescaler using the longest /// timeout you plan to measure. - pub fn reset_and_compute_prescaler<T: Into<<Self as CountDown>::Time>>( + pub fn reset_and_compute_prescaler<T: Into<<Self as ehal_02::timer::CountDown>::Time>>( &mut self, timeout: T, ) -> &Self { @@ -344,13 +345,36 @@ impl Rtc<ClockMode> { // --- Timer / Counter Functionality -impl Periodic for Rtc<Count32Mode> {} -impl CountDown for Rtc<Count32Mode> { +impl ehal_02::timer::Periodic for Rtc<Count32Mode> {} +impl ehal_02::timer::CountDown for Rtc<Count32Mode> { type Time = Nanoseconds; fn start<T>(&mut self, timeout: T) where T: Into<Self::Time>, + { + <Self as InterruptDrivenTimer>::start(self, timeout); + } + + fn wait(&mut self) -> nb::Result<(), void::Void> { + // Unwrapping an unreacheable error is totally OK + <Self as InterruptDrivenTimer>::wait(self).unwrap(); + Ok(()) + } +} + +impl InterruptDrivenTimer for Rtc<Count32Mode> { + /// Enable the interrupt generation for this hardware timer. + /// This method only sets the clock configuration to trigger + /// the interrupt; it does not configure the interrupt controller + /// or define an interrupt handler. + fn enable_interrupt(&mut self) { + self.mode0().intenset.write(|w| w.cmp0().set_bit()); + } + + fn start<T>(&mut self, timeout: T) + where + T: Into<NanosDurationU32>, { let params = TimerParams::new_us(timeout, self.rtc_clock_freq); let divider = params.divider; @@ -376,7 +400,7 @@ impl CountDown for Rtc<Count32Mode> { }); } - fn wait(&mut self) -> nb::Result<(), Void> { + fn wait(&mut self) -> nb::Result<(), Infallible> { if self.mode0().intflag.read().cmp0().bit_is_set() { // Writing a 1 clears the flag self.mode0().intflag.modify(|_, w| w.cmp0().set_bit()); @@ -385,16 +409,6 @@ impl CountDown for Rtc<Count32Mode> { Err(nb::Error::WouldBlock) } } -} - -impl InterruptDrivenTimer for Rtc<Count32Mode> { - /// Enable the interrupt generation for this hardware timer. - /// This method only sets the clock configuration to trigger - /// the interrupt; it does not configure the interrupt controller - /// or define an interrupt handler. - fn enable_interrupt(&mut self) { - self.mode0().intenset.write(|w| w.cmp0().set_bit()); - } /// Disables interrupt generation for this hardware timer. /// This method only sets the clock configuration to prevent diff --git a/hal/src/sleeping_delay.rs b/hal/src/sleeping_delay.rs index 988d73a56398..515c6749dfb1 100644 --- a/hal/src/sleeping_delay.rs +++ b/hal/src/sleeping_delay.rs @@ -3,10 +3,11 @@ use core::sync::atomic; use cortex_m::asm; use fugit::ExtU32; -use crate::ehal_02::blocking::delay::{DelayMs, DelayUs}; +use crate::ehal::delay::DelayNs; +use crate::ehal_02; use crate::timer_traits::InterruptDrivenTimer; -const NUM_US_IN_S: u32 = 1_000_000; +const NUM_NS_IN_S: u32 = 1_000_000_000; /// Delay and sleep while we do (WFI) using a timer pub struct SleepingDelay<TIM> { @@ -35,28 +36,42 @@ where } } -impl<TIM, TYPE> DelayUs<TYPE> for SleepingDelay<TIM> +impl<TIM, TYPE> ehal_02::blocking::delay::DelayUs<TYPE> for SleepingDelay<TIM> where TIM: InterruptDrivenTimer, TYPE: Into<u32>, { fn delay_us(&mut self, us: TYPE) { - let us: u32 = us.into(); + <Self as DelayNs>::delay_us(self, us.into()); + } +} + +impl<TIM, TYPE> ehal_02::blocking::delay::DelayMs<TYPE> for SleepingDelay<TIM> +where + TIM: InterruptDrivenTimer, + TYPE: Into<u32>, +{ + fn delay_ms(&mut self, ms: TYPE) { + <Self as DelayNs>::delay_ms(self, ms.into()); + } +} +impl<TIM: InterruptDrivenTimer> DelayNs for SleepingDelay<TIM> { + fn delay_ns(&mut self, ns: u32) { // Determine how many cycles we need to run for this delay, if any // Avoid timers that run longer than a second because for 48 MHz-based timers, // there is no valid divisor + cycle count greater than ~1.3s, so we'd panic. - let mut count: u32 = 1 + (us / NUM_US_IN_S); + let mut loop_counter: u32 = 1 + (ns / NUM_NS_IN_S); // Start the timer and sleep! - self.timer.start((us / count).nanos()); + self.timer.start((ns / loop_counter).nanos()); self.timer.enable_interrupt(); loop { asm::wfi(); if self.timer.wait().is_ok() || self.interrupt_fired.load(atomic::Ordering::Relaxed) { self.interrupt_fired.store(false, atomic::Ordering::Relaxed); - count -= 1; - if count == 0 { + loop_counter -= 1; + if loop_counter == 0 { break; } } @@ -64,13 +79,3 @@ where self.timer.disable_interrupt(); } } - -impl<TIM, TYPE> DelayMs<TYPE> for SleepingDelay<TIM> -where - TIM: InterruptDrivenTimer, - TYPE: Into<u32>, -{ - fn delay_ms(&mut self, ms: TYPE) { - self.delay_us(ms.into() * 1_000_u32); - } -} diff --git a/hal/src/timer_params.rs b/hal/src/timer_params.rs index 82b428fd8734..33d7d225f293 100644 --- a/hal/src/timer_params.rs +++ b/hal/src/timer_params.rs @@ -16,7 +16,7 @@ impl TimerParams { } /// calculates TimerParams from a given period based timeout. - pub fn new_us(timeout: Nanoseconds, src_freq: Hertz) -> Self { + pub fn new_ns(timeout: Nanoseconds, src_freq: Hertz) -> Self { let ticks: u32 = (timeout.to_nanos() as u64 * src_freq.to_Hz() as u64 / 1_000_000_000_u64) as u32; Self::new_from_ticks(ticks) @@ -51,13 +51,13 @@ impl TimerParams { #[cfg(test)] mod tests { - use crate::prelude::*; + use crate::fugit::{ExtU32, RateExtU32}; use crate::timer_params::TimerParams; #[test] fn timer_params_hz_and_us_same_1hz() { let tp_from_hz = TimerParams::new(1.Hz(), 48.MHz()); - let tp_from_us = TimerParams::new_us(1_000_000.micros(), 48.MHz()); + let tp_from_us = TimerParams::new_ns(1_000_000.micros(), 48.MHz()); assert_eq!(tp_from_hz.divider, tp_from_us.divider); assert_eq!(tp_from_hz.cycles, tp_from_us.cycles); @@ -66,7 +66,7 @@ mod tests { #[test] fn timer_params_hz_and_us_same_3hz() { let tp_from_hz = TimerParams::new(3.Hz(), 48.MHz()); - let tp_from_us = TimerParams::new_us(333_333.micros(), 48.MHz()); + let tp_from_us = TimerParams::new_ns(333_333.micros(), 48.MHz()); // There's some rounding error here, but it is extremely small (1 cycle // difference) diff --git a/hal/src/timer_traits.rs b/hal/src/timer_traits.rs index 09abca8ba03d..a2bc858ce750 100644 --- a/hal/src/timer_traits.rs +++ b/hal/src/timer_traits.rs @@ -1,12 +1,19 @@ -use crate::ehal_02::timer::{CountDown, Periodic}; -use crate::time; +use core::convert::Infallible; -/// Trait for timers that can enable & disable an interrupt that fires +use fugit::NanosDurationU32; + +/// Specifies a timer that can enable & disable an interrupt that fires /// when the timer expires -pub trait InterruptDrivenTimer: CountDown<Time = time::Nanoseconds> + Periodic { +pub trait InterruptDrivenTimer { /// Enable the timer interrupt fn enable_interrupt(&mut self); + /// Start the timer with a given timeout in nanoseconds + fn start<T: Into<NanosDurationU32>>(&mut self, timeout: T); + + /// Wait for the timer to finish counting down **without blocking**. + fn wait(&mut self) -> nb::Result<(), Infallible>; + /// Disable the timer interrupt fn disable_interrupt(&mut self); } From 3592c65f11fb800a8bfbd32d89c2ac45a7a8d969 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Mon, 29 Apr 2024 10:36:02 -0400 Subject: [PATCH 19/30] Implement embedded-hal 1.0 pwm --- hal/src/peripherals/pwm/d11.rs | 32 ++++++++++++++++++++++++-------- hal/src/peripherals/pwm/d5x.rs | 34 ++++++++++++++++++++++++++-------- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/hal/src/peripherals/pwm/d11.rs b/hal/src/peripherals/pwm/d11.rs index 0363f0d33481..a841d266a8a5 100644 --- a/hal/src/peripherals/pwm/d11.rs +++ b/hal/src/peripherals/pwm/d11.rs @@ -1,7 +1,6 @@ use atsamd_hal_macros::hal_cfg; use crate::clock; -use crate::ehal_02::{Pwm, PwmPin}; use crate::pac::PM; use crate::time::Hertz; use crate::timer_params::TimerParams; @@ -86,7 +85,25 @@ impl $TYPE { } } -impl PwmPin for $TYPE { +impl $crate::ehal::pwm::ErrorType for$TYPE { + type Error = ::core::convert::Infallible; +} + +impl $crate::ehal::pwm::SetDutyCycle for $TYPE { + fn max_duty_cycle(&self) -> u16 { + let count = self.tc.count16(); + let top = count.cc[0].read().cc().bits(); + top + } + + fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { + let count = self.tc.count16(); + unsafe { count.cc[1].write(|w| w.cc().bits(duty)); } + Ok(()) + } +} + +impl $crate::ehal_02::PwmPin for $TYPE { type Duty = u16; fn disable(&mut self) { @@ -106,14 +123,13 @@ impl PwmPin for $TYPE { } fn get_max_duty(&self) -> Self::Duty { - let count = self.tc.count16(); - let top = count.cc[0].read().cc().bits(); - top + use $crate::ehal::pwm::SetDutyCycle; + self.max_duty_cycle() } fn set_duty(&mut self, duty: Self::Duty) { - let count = self.tc.count16(); - count.cc[1].write(|w| unsafe { w.cc().bits(duty) }); + use $crate::ehal::pwm::SetDutyCycle; + let _ignore_infaillible = self.set_duty_cycle(duty); } } @@ -199,7 +215,7 @@ impl $TYPE { } } -impl Pwm for $TYPE { +impl $crate::ehal_02::Pwm for $TYPE { type Channel = Channel; type Time = Hertz; type Duty = u32; diff --git a/hal/src/peripherals/pwm/d5x.rs b/hal/src/peripherals/pwm/d5x.rs index a4fdafd73bad..423aaa9bdaaf 100644 --- a/hal/src/peripherals/pwm/d5x.rs +++ b/hal/src/peripherals/pwm/d5x.rs @@ -3,7 +3,6 @@ use atsamd_hal_macros::hal_cfg; use crate::clock; -use crate::ehal_02::{Pwm, PwmPin}; use crate::gpio::*; use crate::gpio::{AlternateE, AnyPin, Pin}; use crate::pac::MCLK; @@ -216,7 +215,25 @@ impl<I: PinId> $TYPE<I> { } } -impl<I: PinId> PwmPin for $TYPE<I> { +impl<I: PinId> $crate::ehal::pwm::ErrorType for$TYPE<I> { + type Error = ::core::convert::Infallible; +} + +impl<I: PinId> $crate::ehal::pwm::SetDutyCycle for $TYPE<I> { + fn max_duty_cycle(&self) -> u16 { + let count = self.tc.count16(); + let top = count.cc[0].read().cc().bits(); + top + } + + fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { + let count = self.tc.count16(); + unsafe { count.ccbuf[1].write(|w| w.ccbuf().bits(duty)); } + Ok(()) + } +} + +impl<I: PinId> $crate::ehal_02::PwmPin for $TYPE<I> { type Duty = u16; fn disable(&mut self) { @@ -237,17 +254,18 @@ impl<I: PinId> PwmPin for $TYPE<I> { } fn get_max_duty(&self) -> Self::Duty { - let count = self.tc.count16(); - let top = count.cc[0].read().cc().bits(); - top + use $crate::ehal::pwm::SetDutyCycle; + self.max_duty_cycle() } fn set_duty(&mut self, duty: Self::Duty) { - let count = self.tc.count16(); - count.ccbuf[1].write(|w| unsafe {w.ccbuf().bits(duty)}); + use $crate::ehal::pwm::SetDutyCycle; + let _ignore_infaillible = self.set_duty_cycle(duty); } } + + )+}} #[hal_cfg("tc0")] @@ -582,7 +600,7 @@ impl<I: PinId, M: PinMode> $TYPE<I, M> { } } -impl<I: PinId, M: PinMode> Pwm for $TYPE<I, M> { +impl<I: PinId, M: PinMode> $crate::ehal_02::Pwm for $TYPE<I, M> { type Channel = Channel; type Time = Hertz; type Duty = u32; From 7621b5f53c4b3f4319c15496b92af88f4d243dfc Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Mon, 29 Apr 2024 10:36:10 -0400 Subject: [PATCH 20/30] Update changelog --- hal/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/CHANGELOG.md b/hal/CHANGELOG.md index 51817a4bbbcb..8e5b5d2d0174 100644 --- a/hal/CHANGELOG.md +++ b/hal/CHANGELOG.md @@ -1,6 +1,6 @@ # Unreleased Changes -- Implement `embedded-hal` `1.0` for GPIO, SPI, I2C, UART +- Implement `embedded-hal` `1.0` for GPIO, SPI, I2C, UART, delay and PWM - CI/CD pipeline now uses `cargo clippy` instead of `cargo build` and denies clippy warnings by default - Fix HAL clippy lints - Add compile error for combined `library` and `dma` features From ca4cf3dedb21044718fca0ba3dd20fb7ce0cc65b Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Mon, 29 Apr 2024 10:36:53 -0400 Subject: [PATCH 21/30] Fix compile error --- hal/src/peripherals/timer/d11.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/src/peripherals/timer/d11.rs b/hal/src/peripherals/timer/d11.rs index 486f28b4b215..aadc0e67e316 100644 --- a/hal/src/peripherals/timer/d11.rs +++ b/hal/src/peripherals/timer/d11.rs @@ -78,7 +78,7 @@ where } fn start<T: Into<NanosDurationU32>>(&mut self, timeout: T) { - let params = TimerParams::new_us(timeout.into(), self.freq); + let params = TimerParams::new_ns(timeout.into(), self.freq); let divider = params.divider; let cycles = params.cycles; From e2140cc430b8a4890f40425d3cc7686513e2a9ad Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Mon, 29 Apr 2024 11:05:39 -0400 Subject: [PATCH 22/30] Remove unproven feature from HAL --- README.md | 16 ++-- boards/atsame54_xpro/Cargo.toml | 3 +- boards/feather_m0/Cargo.toml | 11 +-- boards/feather_m4/Cargo.toml | 10 +-- boards/feather_m4/examples/pwm.rs | 2 - boards/metro_m0/Cargo.toml | 5 +- boards/metro_m4/Cargo.toml | 5 +- boards/samd11_bare/Cargo.toml | 4 +- boards/samd11_bare/README.md | 4 +- boards/samd11_bare/examples/adc.rs | 2 +- crates.json | 104 ++++++++++------------ hal/Cargo.toml | 13 +-- hal/src/gpio/dynpin.rs | 5 -- hal/src/gpio/pin.rs | 7 -- hal/src/peripherals/eic/d11/pin.rs | 2 - hal/src/peripherals/eic/d5x/pin.rs | 2 - hal/src/peripherals/mod.rs | 4 - hal/src/peripherals/trng.rs | 2 - hal/src/prelude.rs | 2 - hal/src/sercom/spi/impl_ehal_thumbv6m.rs | 2 - hal/src/sercom/spi/impl_ehal_thumbv7em.rs | 2 - 21 files changed, 75 insertions(+), 132 deletions(-) diff --git a/README.md b/README.md index db0ed7c57f9e..ab7e1ea289af 100644 --- a/README.md +++ b/README.md @@ -12,14 +12,14 @@ The Hardware Abstraction Layer (HAL - [ in 0.99s Running `probe-run --chip ATSAMD11C14A target\thumbv6m-none-eabi\release\examples\adc` (HOST) INFO flashing program (7.18 KiB) diff --git a/boards/samd11_bare/examples/adc.rs b/boards/samd11_bare/examples/adc.rs index f887525e313c..e580c59b0ee5 100644 --- a/boards/samd11_bare/examples/adc.rs +++ b/boards/samd11_bare/examples/adc.rs @@ -9,7 +9,7 @@ //! on your command line. You can also force an exit with a //! cortex_m::asm::bkpt() //! -//! `cargo run --release --example adc --features=unproven` +//! `cargo run --release --example adc` #![no_std] #![no_main] diff --git a/crates.json b/crates.json index cae374805a1d..41192c503206 100644 --- a/crates.json +++ b/crates.json @@ -1,5 +1,35 @@ { "boards": { + "atsame54_xpro": { + "tier": 1, + "build": "cargo build --examples --all-features", + "target": "thumbv7em-none-eabihf" + }, + "feather_m0": { + "tier": 1, + "build": "cargo build --examples", + "target": "thumbv6m-none-eabi" + }, + "feather_m4": { + "tier": 1, + "build": "cargo build --examples --all-features", + "target": "thumbv7em-none-eabihf" + }, + "metro_m0": { + "tier": 1, + "build": "cargo build --examples --all-features", + "target": "thumbv6m-none-eabi" + }, + "metro_m4": { + "tier": 1, + "build": "cargo build --examples --all-features", + "target": "thumbv7em-none-eabihf" + }, + "samd11_bare": { + "tier": 1, + "build": "cargo build --examples --all-features", + "target": "thumbv6m-none-eabi" + }, "arduino_mkr1000": { "tier": 2, "build": "cargo build --examples --all-features", @@ -20,11 +50,6 @@ "build": "cargo build --examples --all-features", "target": "thumbv6m-none-eabi" }, - "atsame54_xpro": { - "tier": 1, - "build": "cargo build --examples --all-features", - "target": "thumbv7em-none-eabihf" - }, "circuit_playground_express": { "tier": 2, "build": "cargo build --examples --all-features", @@ -35,16 +60,6 @@ "build": "cargo build --examples --all-features", "target": "thumbv7em-none-eabihf" }, - "feather_m0": { - "tier": 1, - "build": "cargo build --examples", - "target": "thumbv6m-none-eabi" - }, - "feather_m4": { - "tier": 1, - "build": "cargo build --examples --all-features", - "target": "thumbv7em-none-eabihf" - }, "gemma_m0": { "tier": 2, "build": "cargo build --examples --all-features", @@ -70,16 +85,6 @@ "build": "cargo build --examples --all-features", "target": "thumbv7em-none-eabihf" }, - "metro_m0": { - "tier": 1, - "build": "cargo build --examples --all-features", - "target": "thumbv6m-none-eabi" - }, - "metro_m4": { - "tier": 1, - "build": "cargo build --examples --all-features", - "target": "thumbv7em-none-eabihf" - }, "neo_trinkey": { "tier": 2, "build": "cargo build --examples --all-features", @@ -110,11 +115,6 @@ "build": "cargo build --examples --all-features", "target": "thumbv7em-none-eabihf" }, - "samd11_bare": { - "tier": 1, - "build": "cargo build --examples --all-features", - "target": "thumbv6m-none-eabi" - }, "samd21_mini": { "tier": 2, "build": "cargo build --examples --all-features", @@ -175,7 +175,6 @@ "samd11c": { "features": [ "samd11c", - "unproven", "dma", "defmt" ], @@ -184,7 +183,6 @@ "samd11d": { "features": [ "samd11d", - "unproven", "dma", "defmt" ], @@ -193,7 +191,6 @@ "samd21g": { "features": [ "samd21g", - "unproven", "usb", "dma", "defmt" @@ -203,7 +200,6 @@ "samd21j": { "features": [ "samd21j", - "unproven", "usb", "dma", "defmt" @@ -213,7 +209,6 @@ "samd51g": { "features": [ "samd51g", - "unproven", "usb", "sdmmc", "dma", @@ -224,7 +219,6 @@ "samd51j": { "features": [ "samd51j", - "unproven", "usb", "sdmmc", "dma", @@ -235,7 +229,6 @@ "samd51n": { "features": [ "samd51n", - "unproven", "usb", "sdmmc", "dma", @@ -246,7 +239,6 @@ "samd51p": { "features": [ "samd51p", - "unproven", "usb", "sdmmc", "dma", @@ -257,75 +249,75 @@ }, "hal_build_variants": { "samd11c": { - "features": [ "samd11c", "unproven", "dma", "rtic", "defmt" ], + "features": [ "samd11c", "dma", "rtic", "defmt" ], "target": "thumbv6m-none-eabi" }, "samd11d": { - "features": [ "samd11d", "unproven", "dma", "rtic", "defmt" ], + "features": [ "samd11d", "dma", "rtic", "defmt" ], "target": "thumbv6m-none-eabi" }, "samd21e": { - "features": [ "samd21e", "unproven", "usb", "dma", "rtic", "defmt" ], + "features": [ "samd21e", "usb", "dma", "rtic", "defmt" ], "target": "thumbv6m-none-eabi" }, "samd21el": { - "features": [ "samd21el", "unproven", "dma", "rtic", "defmt" ], + "features": [ "samd21el", "dma", "rtic", "defmt" ], "target": "thumbv6m-none-eabi" }, "samd21g": { - "features": [ "samd21g", "unproven", "usb", "dma", "rtic", "defmt" ], + "features": [ "samd21g", "usb", "dma", "rtic", "defmt" ], "target": "thumbv6m-none-eabi" }, "samd21gl": { - "features": [ "samd21gl", "unproven", "dma", "rtic", "defmt" ], + "features": [ "samd21gl", "dma", "rtic", "defmt" ], "target": "thumbv6m-none-eabi" }, "samd21j": { - "features": [ "samd21j", "unproven", "usb", "dma", "rtic", "defmt" ], + "features": [ "samd21j", "usb", "dma", "rtic", "defmt" ], "target": "thumbv6m-none-eabi" }, "samd51g": { - "features": [ "samd51g", "unproven", "usb", "dma", "sdmmc", "rtic", "defmt" ], + "features": [ "samd51g", "usb", "dma", "sdmmc", "rtic", "defmt" ], "target": "thumbv7em-none-eabihf" }, "samd51j": { - "features": [ "samd51j", "unproven", "usb", "dma", "sdmmc", "rtic", "defmt" ], + "features": [ "samd51j", "usb", "dma", "sdmmc", "rtic", "defmt" ], "target": "thumbv7em-none-eabihf" }, "samd51n": { - "features": [ "samd51n", "unproven", "usb", "dma", "sdmmc", "rtic", "defmt" ], + "features": [ "samd51n", "usb", "dma", "sdmmc", "rtic", "defmt" ], "target": "thumbv7em-none-eabihf" }, "samd51p": { - "features": [ "samd51p", "unproven", "usb", "dma", "sdmmc", "rtic", "defmt" ], + "features": [ "samd51p", "usb", "dma", "sdmmc", "rtic", "defmt" ], "target": "thumbv7em-none-eabihf" }, "same51g": { - "features": [ "same51g", "unproven", "usb", "dma", "sdmmc", "rtic", "can", "defmt" ], + "features": [ "same51g", "usb", "dma", "sdmmc", "rtic", "can", "defmt" ], "target": "thumbv7em-none-eabihf" }, "same51j": { - "features": [ "same51j", "unproven", "usb", "dma", "sdmmc", "rtic", "can", "defmt" ], + "features": [ "same51j", "usb", "dma", "sdmmc", "rtic", "can", "defmt" ], "target": "thumbv7em-none-eabihf" }, "same51n": { - "features": [ "same51n", "unproven", "usb", "dma", "sdmmc", "rtic", "can", "defmt" ], + "features": [ "same51n", "usb", "dma", "sdmmc", "rtic", "can", "defmt" ], "target": "thumbv7em-none-eabihf" }, "same53j": { - "features": [ "same53j", "unproven", "usb", "dma", "sdmmc", "rtic", "defmt" ], + "features": [ "same53j", "usb", "dma", "sdmmc", "rtic", "defmt" ], "target": "thumbv7em-none-eabihf" }, "same53n": { - "features": [ "same53n", "unproven", "usb", "dma", "sdmmc", "rtic", "defmt" ], + "features": [ "same53n", "usb", "dma", "sdmmc", "rtic", "defmt" ], "target": "thumbv7em-none-eabihf" }, "same54n": { - "features": [ "same54n", "unproven", "usb", "dma", "sdmmc", "rtic", "can", "defmt" ], + "features": [ "same54n", "usb", "dma", "sdmmc", "rtic", "can", "defmt" ], "target": "thumbv7em-none-eabihf" }, "same54p": { - "features": [ "same54p", "unproven", "usb", "dma", "sdmmc", "rtic", "can", "defmt" ], + "features": [ "same54p", "usb", "dma", "sdmmc", "rtic", "can", "defmt" ], "target": "thumbv7em-none-eabihf" } } diff --git a/hal/Cargo.toml b/hal/Cargo.toml index 62bcc5293b17..dced5199a59d 100644 --- a/hal/Cargo.toml +++ b/hal/Cargo.toml @@ -23,7 +23,7 @@ rust-version = "1.65" version = "0.16.0" [package.metadata.docs.rs] -features = ["samd21g", "samd21g-rt", "unproven", "usb", "dma"] +features = ["samd21g", "samd21g-rt", "usb", "dma"] #=============================================================================== # Required depdendencies @@ -36,7 +36,7 @@ bitfield = "0.13" bitflags = "1.2.1" cipher = "0.3" cortex-m = "0.7" -embedded-hal-02 = {package = "embedded-hal", version = "0.2"} +embedded-hal-02 = {package = "embedded-hal", version = "0.2", features = ["unproven"]} embedded-hal-1 = {package = "embedded-hal", version = "1.0.0"} embedded-hal-nb = "1.0.0" embedded-io = "0.6" @@ -174,20 +174,13 @@ same54p-rt = ["same54p", "atsame54p/rt"] # These features are user-selectable and enable additional features within the # HAL, like USB or DMA support. - -# Many essential traits within embedded-hal are locked behind the `unproven` -# feature. This is unfortunate, but it should be resolved with embedded-hal 1.0. -# Until then, we make `unproven` a default feature. -default = ["unproven"] - can = ["mcan-core"] -dma = ["unproven"] +dma = [] defmt = ["dep:defmt"] enable_unsafe_aes_newblock_cipher = [] max-channels = ["dma"] rtic = ["rtic-monotonic"] sdmmc = ["embedded-sdmmc"] -unproven = ["embedded-hal-02/unproven"] usb = ["usb-device"] use_rtt = ["jlink_rtt"] diff --git a/hal/src/gpio/dynpin.rs b/hal/src/gpio/dynpin.rs index 44936a4b98d1..6be2d8cf9486 100644 --- a/hal/src/gpio/dynpin.rs +++ b/hal/src/gpio/dynpin.rs @@ -530,7 +530,6 @@ impl OutputPin for DynPin { } } -#[cfg(feature = "unproven")] impl InputPin for DynPin { #[inline] fn is_high(&mut self) -> Result<bool, Self::Error> { @@ -542,7 +541,6 @@ impl InputPin for DynPin { } } -#[cfg(feature = "unproven")] impl StatefulOutputPin for DynPin { #[inline] fn is_set_high(&mut self) -> Result<bool, Self::Error> { @@ -570,7 +568,6 @@ impl crate::ehal_02::digital::v2::OutputPin for DynPin { } } -#[cfg(feature = "unproven")] impl crate::ehal_02::digital::v2::InputPin for DynPin { type Error = Error; #[inline] @@ -583,7 +580,6 @@ impl crate::ehal_02::digital::v2::InputPin for DynPin { } } -#[cfg(feature = "unproven")] impl crate::ehal_02::digital::v2::ToggleableOutputPin for DynPin { type Error = Error; #[inline] @@ -592,7 +588,6 @@ impl crate::ehal_02::digital::v2::ToggleableOutputPin for DynPin { } } -#[cfg(feature = "unproven")] impl crate::ehal_02::digital::v2::StatefulOutputPin for DynPin { #[inline] fn is_set_high(&self) -> Result<bool, Self::Error> { diff --git a/hal/src/gpio/pin.rs b/hal/src/gpio/pin.rs index acc60d8ee370..af5ca781f6ba 100644 --- a/hal/src/gpio/pin.rs +++ b/hal/src/gpio/pin.rs @@ -923,7 +923,6 @@ where } } -#[cfg(feature = "unproven")] impl<I, C> InputPin for Pin<I, Input<C>> where I: PinId, @@ -939,7 +938,6 @@ where } } -#[cfg(feature = "unproven")] impl<I, C> InputPin for Pin<I, Interrupt<C>> where I: PinId, @@ -992,7 +990,6 @@ where } } -#[cfg(feature = "unproven")] impl<I> crate::ehal_02::digital::v2::InputPin for Pin<I, ReadableOutput> where I: PinId, @@ -1008,7 +1005,6 @@ where } } -#[cfg(feature = "unproven")] impl<I, C> crate::ehal_02::digital::v2::InputPin for Pin<I, Input<C>> where I: PinId, @@ -1025,7 +1021,6 @@ where } } -#[cfg(feature = "unproven")] impl<I, C> crate::ehal_02::digital::v2::InputPin for Pin<I, Interrupt<C>> where I: PinId, @@ -1042,7 +1037,6 @@ where } } -#[cfg(feature = "unproven")] impl<I, C> crate::ehal_02::digital::v2::ToggleableOutputPin for Pin<I, Output<C>> where I: PinId, @@ -1056,7 +1050,6 @@ where } } -#[cfg(feature = "unproven")] impl<I, C> crate::ehal_02::digital::v2::StatefulOutputPin for Pin<I, Output<C>> where I: PinId, diff --git a/hal/src/peripherals/eic/d11/pin.rs b/hal/src/peripherals/eic/d11/pin.rs index a746e31f58a0..c537dfb57a2c 100644 --- a/hal/src/peripherals/eic/d11/pin.rs +++ b/hal/src/peripherals/eic/d11/pin.rs @@ -1,4 +1,3 @@ -#[cfg(feature = "unproven")] use crate::ehal_02::digital::v2::InputPin; use crate::gpio::{ self, pin::*, AnyPin, FloatingInterrupt, PinMode, PullDownInterrupt, PullUpInterrupt, @@ -157,7 +156,6 @@ crate::paste::item! { } } - #[cfg(feature = "unproven")] impl<GPIO, C> InputPin for [<$PadType $num>]<GPIO> where GPIO: AnyPin<Mode = Interrupt<C>>, diff --git a/hal/src/peripherals/eic/d5x/pin.rs b/hal/src/peripherals/eic/d5x/pin.rs index 4e5c5670fd6a..8c1d57bb6749 100644 --- a/hal/src/peripherals/eic/d5x/pin.rs +++ b/hal/src/peripherals/eic/d5x/pin.rs @@ -1,4 +1,3 @@ -#[cfg(feature = "unproven")] use crate::ehal_02::digital::v2::InputPin; use crate::gpio::{ self, pin::*, AnyPin, FloatingInterrupt, PinMode, PullDownInterrupt, PullUpInterrupt, @@ -155,7 +154,6 @@ crate::paste::item! { } } - #[cfg(feature = "unproven")] impl<GPIO, C> InputPin for [<$PadType $num>]<GPIO> where GPIO: AnyPin<Mode = Interrupt<C>>, diff --git a/hal/src/peripherals/mod.rs b/hal/src/peripherals/mod.rs index f7e060756175..34e271e6dd5d 100644 --- a/hal/src/peripherals/mod.rs +++ b/hal/src/peripherals/mod.rs @@ -1,6 +1,5 @@ use atsamd_hal_macros::{hal_cfg, hal_module}; -#[cfg(feature = "unproven")] #[hal_module( any("adc-d11", "adc-d21") => "adc/d11.rs", "adc-d5x" => "adc/d5x.rs", @@ -32,7 +31,6 @@ pub mod eic {} )] pub mod usb {} -#[cfg(feature = "unproven")] #[hal_module( any("clock-d11", "clock-d21") => "pwm/d11.rs", "clock-d5x" => "pwm/d5x.rs", @@ -60,7 +58,6 @@ pub mod qspi {} #[hal_module("trng")] pub mod trng {} -#[cfg(feature = "unproven")] #[hal_module("icm")] pub mod icm {} @@ -71,7 +68,6 @@ pub mod nvm {} #[hal_module(any("can0", "can1"))] pub mod can {} -#[cfg(feature = "unproven")] #[hal_module("wdt")] pub mod watchdog {} diff --git a/hal/src/peripherals/trng.rs b/hal/src/peripherals/trng.rs index ef34107136c9..35379b583c0a 100644 --- a/hal/src/peripherals/trng.rs +++ b/hal/src/peripherals/trng.rs @@ -2,7 +2,6 @@ use crate::pac::{MCLK, TRNG}; use rand_core::{CryptoRng, RngCore}; -#[cfg(feature = "unproven")] use crate::ehal_02::blocking::rng::Read; pub struct Trng(TRNG); @@ -63,7 +62,6 @@ impl RngCore for Trng { impl CryptoRng for Trng {} -#[cfg(feature = "unproven")] impl Read for Trng { type Error = (); fn read(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> { diff --git a/hal/src/prelude.rs b/hal/src/prelude.rs index 702ce1cb38da..10271f207feb 100644 --- a/hal/src/prelude.rs +++ b/hal/src/prelude.rs @@ -6,10 +6,8 @@ pub use fugit::RateExtU32 as _; // embedded-hal doesn’t yet have v2 in its prelude, so we need to // export it ourselves -#[cfg(feature = "unproven")] pub use crate::ehal_02::digital::v2::InputPin as _atsamd_hal_embedded_hal_digital_v2_InputPin; pub use crate::ehal_02::digital::v2::OutputPin as _atsamd_hal_embedded_hal_digital_v2_OutputPin; -#[cfg(feature = "unproven")] pub use crate::ehal_02::digital::v2::ToggleableOutputPin as _atsamd_hal_embedded_hal_digital_v2_ToggleableOutputPin; pub use crate::ehal_02::prelude::*; diff --git a/hal/src/sercom/spi/impl_ehal_thumbv6m.rs b/hal/src/sercom/spi/impl_ehal_thumbv6m.rs index 2f7789b85485..3b25e97c2d1f 100644 --- a/hal/src/sercom/spi/impl_ehal_thumbv6m.rs +++ b/hal/src/sercom/spi/impl_ehal_thumbv6m.rs @@ -592,7 +592,6 @@ impl_blocking_spi_write!(EightBit, NineBit); // blocking::spi::WriteIter //============================================================================= -#[cfg(feature = "unproven")] macro_rules! impl_blocking_spi_write_iter { ( $($CharSize:ident),+ ) => { $( @@ -682,5 +681,4 @@ macro_rules! impl_blocking_spi_write_iter { }; } -#[cfg(feature = "unproven")] impl_blocking_spi_write_iter!(EightBit, NineBit); diff --git a/hal/src/sercom/spi/impl_ehal_thumbv7em.rs b/hal/src/sercom/spi/impl_ehal_thumbv7em.rs index d8f66347245a..3612a472fba5 100644 --- a/hal/src/sercom/spi/impl_ehal_thumbv7em.rs +++ b/hal/src/sercom/spi/impl_ehal_thumbv7em.rs @@ -671,7 +671,6 @@ macro_rules! impl_blocking_spi_write_iter { /// (`u8`, `u16` or `u32`). /// /// [`WriteIter`]: blocking::spi::WriteIter - #[cfg(feature = "unproven")] impl<P, M> $crate::ehal_02::blocking::spi::WriteIter<Word<$Length>> for Spi<Config<P, M, $Length>, Duplex> where Config<P, M, $Length>: ValidConfig, @@ -719,7 +718,6 @@ macro_rules! impl_blocking_spi_write_iter { /// reads the DATA register and ignores all buffer overflow errors. /// /// [`WriteIter`]: blocking::spi::WriteIter - #[cfg(feature = "unproven")] impl<P, M> $crate::ehal_02::blocking::spi::WriteIter<Word<$Length>> for Spi<Config<P, M, $Length>, Tx> where Config<P, M, $Length>: ValidConfig, From 19b81fffe79a5056853cc41d7c4799d93fc60414 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Mon, 29 Apr 2024 11:12:09 -0400 Subject: [PATCH 23/30] Update changelog --- hal/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/hal/CHANGELOG.md b/hal/CHANGELOG.md index 8e5b5d2d0174..beebaa75ba67 100644 --- a/hal/CHANGELOG.md +++ b/hal/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased Changes +- Remove `unproven` Cargo feature - Implement `embedded-hal` `1.0` for GPIO, SPI, I2C, UART, delay and PWM - CI/CD pipeline now uses `cargo clippy` instead of `cargo build` and denies clippy warnings by default - Fix HAL clippy lints From 4b5889a309beb7e0e0266b5f22104fb5a49a7f0c Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Mon, 29 Apr 2024 16:14:01 -0400 Subject: [PATCH 24/30] Fix SPI implementation --- hal/src/sercom/spi/impl_ehal.rs | 8 +-- hal/src/sercom/spi/impl_ehal_thumbv6m.rs | 60 +++++++++----------- hal/src/sercom/spi/impl_ehal_thumbv7em.rs | 68 +++++++++++++++++------ 3 files changed, 81 insertions(+), 55 deletions(-) diff --git a/hal/src/sercom/spi/impl_ehal.rs b/hal/src/sercom/spi/impl_ehal.rs index e22bfcf11954..5f396f9cd24f 100644 --- a/hal/src/sercom/spi/impl_ehal.rs +++ b/hal/src/sercom/spi/impl_ehal.rs @@ -19,12 +19,10 @@ impl spi::Error for Error { } } -impl<P, M, C> ErrorType for Spi<Config<P, M, C>, Duplex> +impl<C, D> ErrorType for Spi<C, D> where - Config<P, M, C>: ValidConfig, - P: ValidPads, - M: MasterMode, - C: Size, + C: ValidConfig, + D: Capability, { type Error = Error; } diff --git a/hal/src/sercom/spi/impl_ehal_thumbv6m.rs b/hal/src/sercom/spi/impl_ehal_thumbv6m.rs index 3b25e97c2d1f..b212651d92cb 100644 --- a/hal/src/sercom/spi/impl_ehal_thumbv6m.rs +++ b/hal/src/sercom/spi/impl_ehal_thumbv6m.rs @@ -69,24 +69,22 @@ //! the different [`Size`] and [`Capability`] options. use super::*; +use crate::ehal_nb; use nb::Error::WouldBlock; use num_traits::{AsPrimitive, PrimInt}; -impl embedded_hal_nb::serial::Error for Error { - fn kind(&self) -> embedded_hal_nb::serial::ErrorKind { +impl ehal_nb::serial::Error for Error { + fn kind(&self) -> ehal_nb::serial::ErrorKind { match self { - Error::Overflow => embedded_hal_nb::serial::ErrorKind::Overrun, - Error::LengthError => embedded_hal_nb::serial::ErrorKind::Other, + Error::Overflow => ehal_nb::serial::ErrorKind::Overrun, + Error::LengthError => ehal_nb::serial::ErrorKind::Other, } } } -impl<P, M, C, D> embedded_hal_nb::serial::ErrorType for Spi<Config<P, M, C>, D> +impl<C, D> ehal_nb::serial::ErrorType for Spi<C, D> where - Config<P, M, C>: ValidConfig, - P: ValidPads, - M: OpMode, - C: CharSize, + C: ValidConfig, D: Capability, { type Error = Error; @@ -98,12 +96,9 @@ impl embedded_io::Error for Error { } } -impl<P, M, C, D> embedded_io::ErrorType for Spi<Config<P, M, C>, D> +impl<C, D> embedded_io::ErrorType for Spi<C, D> where - Config<P, M, C>: ValidConfig, - P: ValidPads, - M: OpMode, - C: Size, + C: ValidConfig, D: Capability, { type Error = Error; @@ -120,8 +115,8 @@ where /// it keeps track of the transaction state. If a transaction is in progress, /// it will wait on `RXC`. If not, it will wait on `DRE`, and then send `0`. /// -/// [`Read`]: embedded_hal_nb::serial::Read -impl<P, M, C> embedded_hal_nb::serial::Read<C::Word> for Spi<Config<P, M, C>, Rx> +/// [`Read`]: ehal_nb::serial::Read +impl<P, M, C> ehal_nb::serial::Read<C::Word> for Spi<Config<P, M, C>, Rx> where Config<P, M, C>: ValidConfig, P: ValidPads, @@ -168,7 +163,7 @@ where #[inline] fn read(&mut self) -> nb::Result<C::Word, Error> { - <Self as embedded_hal_nb::serial::Read<C::Word>>::read(self) + <Self as ehal_nb::serial::Read<C::Word>>::read(self) } } @@ -180,8 +175,8 @@ where /// transactions, so it does not have to store any internal state. It only has /// to wait on `RXC`. /// -/// [`Read`]: embedded_hal_nb::serial::Read -impl<P, C> embedded_hal_nb::serial::Read<C::Word> for Spi<Config<P, Slave, C>, Rx> +/// [`Read`]: ehal_nb::serial::Read +impl<P, C> ehal_nb::serial::Read<C::Word> for Spi<Config<P, Slave, C>, Rx> where Config<P, Slave, C>: ValidConfig, P: ValidPads, @@ -221,7 +216,7 @@ where /// Wait for an `RXC` flag, then read the word #[inline] fn read(&mut self) -> nb::Result<C::Word, Error> { - <Self as embedded_hal_nb::serial::Read<C::Word>>::read(self) + <Self as ehal_nb::serial::Read<C::Word>>::read(self) } } @@ -236,7 +231,7 @@ where { fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { for byte in buf.iter_mut() { - let w = nb::block!(<Self as embedded_hal_nb::serial::Read>::read(self))?; + let w = nb::block!(<Self as ehal_nb::serial::Read>::read(self))?; *byte = w; } @@ -255,7 +250,7 @@ where }; for byte in buf.iter_mut() { - let w = nb::block!(<Self as embedded_hal_nb::serial::Read>::read(self))?; + let w = nb::block!(<Self as ehal_nb::serial::Read>::read(self))?; *byte = w; } @@ -273,8 +268,8 @@ where /// [`Capability`]. Because the `Capability` is `Tx`, this implementation never /// reads the DATA register and ignores all buffer overflow errors. /// -/// [`Write`]: embedded_hal_nb::serial::Write -impl<P, M, C> embedded_hal_nb::serial::Write<C::Word> for Spi<Config<P, M, C>, Tx> +/// [`Write`]: ehal_nb::serial::Write +impl<P, M, C> ehal_nb::serial::Write<C::Word> for Spi<Config<P, M, C>, Tx> where Config<P, M, C>: ValidConfig, P: ValidPads, @@ -321,12 +316,12 @@ where #[inline] fn write(&mut self, word: C::Word) -> nb::Result<(), Error> { - <Self as embedded_hal_nb::serial::Write<C::Word>>::write(self, word) + <Self as ehal_nb::serial::Write<C::Word>>::write(self, word) } #[inline] fn flush(&mut self) -> nb::Result<(), Error> { - <Self as embedded_hal_nb::serial::Write<C::Word>>::flush(self) + <Self as ehal_nb::serial::Write<C::Word>>::flush(self) } } @@ -352,14 +347,14 @@ where { fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { for byte in buf { - nb::block!(<Self as embedded_hal_nb::serial::Write>::write(self, *byte))?; + nb::block!(<Self as ehal_nb::serial::Write>::write(self, *byte))?; } Ok(buf.len()) } fn flush(&mut self) -> Result<(), Self::Error> { - nb::block!(<Self as embedded_hal_nb::serial::Write>::flush(self)) + nb::block!(<Self as ehal_nb::serial::Write>::flush(self)) } } @@ -372,12 +367,9 @@ where /// `spi::FullDuplex` is only implemented when the `Spi` struct has [`Duplex`] /// [`Capability`]. The [`Word`] size used in the implementation depends on the /// corresponding [`CharSize`]. -impl<P, M, C> embedded_hal_nb::spi::FullDuplex<C::Word> for Spi<Config<P, M, C>, Duplex> +impl<C> ehal_nb::spi::FullDuplex<C::Word> for Spi<C, Duplex> where - Config<P, M, C>: ValidConfig, - P: ValidPads, - M: MasterMode, - C: CharSize, + C: ValidConfig, C::Word: PrimInt + AsPrimitive<u16>, u16: AsPrimitive<C::Word>, { @@ -392,7 +384,7 @@ where } #[inline] - fn write(&mut self, word: C::Word) -> nb::Result<(), Error> { + fn write(&mut self, word: C::Word) -> nb::Result<(), Self::Error> { let flags = self.read_flags_errors()?; if flags.contains(Flags::DRE) { unsafe { self.write_data(word.as_()) }; diff --git a/hal/src/sercom/spi/impl_ehal_thumbv7em.rs b/hal/src/sercom/spi/impl_ehal_thumbv7em.rs index 3612a472fba5..8b106e637086 100644 --- a/hal/src/sercom/spi/impl_ehal_thumbv7em.rs +++ b/hal/src/sercom/spi/impl_ehal_thumbv7em.rs @@ -91,6 +91,7 @@ //! the different [`Size`] and [`Capability`] options. use crate::ehal_02; +use crate::ehal_nb; use crate::sercom::spi::{ AtomicSize, Capability, Config, DataWidth, Duplex, DynLength, Error, Flags, GreaterThan4, Length, MasterMode, OpMode, Receive, Rx, Slave, Spi, Status, Tx, ValidConfig, ValidPads, Word, @@ -101,16 +102,16 @@ use typenum::{U1, U2, U3, U4}; use crate::pac::sercom0::RegisterBlock; -impl embedded_hal_nb::serial::Error for Error { - fn kind(&self) -> embedded_hal_nb::serial::ErrorKind { +impl ehal_nb::serial::Error for Error { + fn kind(&self) -> ehal_nb::serial::ErrorKind { match self { - Error::Overflow => embedded_hal_nb::serial::ErrorKind::Overrun, - Error::LengthError => embedded_hal_nb::serial::ErrorKind::Other, + Error::Overflow => ehal_nb::serial::ErrorKind::Overrun, + Error::LengthError => ehal_nb::serial::ErrorKind::Other, } } } -impl<C, D> embedded_hal_nb::serial::ErrorType for Spi<C, D> +impl<C, D> ehal_nb::serial::ErrorType for Spi<C, D> where C: ValidConfig, D: Capability, @@ -136,13 +137,13 @@ where // serial::Read //============================================================================= -/// Implement [`embedded_hal_nb::serial::Read`] for [`Rx`] [`Spi`] structs in a [`MasterMode`] +/// Implement [`ehal_nb::serial::Read`] for [`Rx`] [`Spi`] structs in a [`MasterMode`] /// /// `serial::Read` is only implemented for `Spi` structs with `Rx` /// [`Capability`]. In a `MasterMode`, `Read` has to initiate transactions, so /// it keeps track of the transaction state. If a transaction is in progress, /// it will wait on `RXC`. If not, it will wait on `DRE`, and then send `0`. -impl<P, M, L> embedded_hal_nb::serial::Read<L::Word> for Spi<Config<P, M, L>, Rx> +impl<P, M, L> ehal_nb::serial::Read<L::Word> for Spi<Config<P, M, L>, Rx> where Config<P, M, L>: ValidConfig, P: ValidPads, @@ -169,7 +170,7 @@ where /// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in a [`MasterMode`] /// -/// Refer to the [`embedded_hal_nb::serial::Read`] implementation of [`Spi`] for more details. +/// Refer to the [`ehal_nb::serial::Read`] implementation of [`Spi`] for more details. impl<P, M, L> ehal_02::serial::Read<L::Word> for Spi<Config<P, M, L>, Rx> where Config<P, M, L>: ValidConfig, @@ -183,7 +184,7 @@ where #[inline] fn read(&mut self) -> nb::Result<L::Word, Error> { - <Self as embedded_hal_nb::serial::Read<L::Word>>::read(self) + <Self as ehal_nb::serial::Read<L::Word>>::read(self) } } @@ -194,7 +195,7 @@ where /// [`Capability`]. In `Slave` `OpMode`, `Read` does not have to initiate /// transactions, so it does not have to store any internal state. It only has /// to wait on `RXC`. -impl<P, L> embedded_hal_nb::serial::Read<L::Word> for Spi<Config<P, Slave, L>, Rx> +impl<P, L> ehal_nb::serial::Read<L::Word> for Spi<Config<P, Slave, L>, Rx> where Config<P, Slave, L>: ValidConfig, P: ValidPads, @@ -216,7 +217,7 @@ where /// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in [`Slave`] /// [`OpMode`] /// -/// Refer to the [`embedded_hal_nb::serial::Read`] implementation of [`Spi`] for more details. +/// Refer to the [`ehal_nb::serial::Read`] implementation of [`Spi`] for more details. impl<P, L> ehal_02::serial::Read<L::Word> for Spi<Config<P, Slave, L>, Rx> where Config<P, Slave, L>: ValidConfig, @@ -229,7 +230,7 @@ where #[inline] fn read(&mut self) -> nb::Result<L::Word, Error> { - <Self as embedded_hal_nb::serial::Read<L::Word>>::read(self) + <Self as ehal_nb::serial::Read<L::Word>>::read(self) } } @@ -237,12 +238,12 @@ where // serial::Write //============================================================================= -/// Implement [`embedded_hal_nb::serial::Write`] for [`Tx`] [`Spi`] structs +/// Implement [`ehal_nb::serial::Write`] for [`Tx`] [`Spi`] structs /// /// `serial::Write` is only implemented for `Spi` structs with `Tx` /// [`Capability`]. Because the `Capability` is `Tx`, this implementation never /// reads the DATA register and ignores all buffer overflow errors. -impl<C> embedded_hal_nb::serial::Write<C::Word> for Spi<C, Tx> +impl<C> ehal_nb::serial::Write<C::Word> for Spi<C, Tx> where C: ValidConfig, C::Size: AtomicSize, @@ -285,12 +286,12 @@ where #[inline] fn write(&mut self, word: C::Word) -> nb::Result<(), Error> { - <Self as embedded_hal_nb::serial::Write<C::Word>>::write(self, word) + <Self as ehal_nb::serial::Write<C::Word>>::write(self, word) } #[inline] fn flush(&mut self) -> nb::Result<(), Error> { - <Self as embedded_hal_nb::serial::Write<C::Word>>::flush(self) + <Self as ehal_nb::serial::Write<C::Word>>::flush(self) } } @@ -309,6 +310,41 @@ where // spi::FullDuplex //============================================================================= +// Implement [`spi::FullDuplex`] for [`Spi`] structs with [`AtomicSize`] +/// +/// `spi::FullDuplex` is only implemented when the `Spi` struct has [`Duplex`] +/// [`Capability`] and the transaction [`Length`] is `<= 4` bytes. When the +/// [`Length`] is `<= 4`, the [`Word`] is a primitive integer, with a size that +/// depends on the [`Length`] (`u8`, `u16` or `u32`). +impl<C> ehal_nb::spi::FullDuplex<C::Word> for Spi<C, Duplex> +where + C: ValidConfig, + C::Size: AtomicSize, + C::Word: PrimInt + AsPrimitive<DataWidth>, + DataWidth: AsPrimitive<C::Word>, +{ + #[inline] + fn read(&mut self) -> nb::Result<C::Word, Error> { + let flags = self.read_flags_errors()?; + if flags.contains(Flags::RXC) { + Ok(self.config.as_mut().regs.read_data().as_()) + } else { + Err(WouldBlock) + } + } + + #[inline] + fn write(&mut self, word: C::Word) -> nb::Result<(), Error> { + let flags = self.read_flags_errors()?; + if flags.contains(Flags::DRE) { + self.config.as_mut().regs.write_data(word.as_()); + Ok(()) + } else { + Err(WouldBlock) + } + } +} + /// Implement [`spi::FullDuplex`] for [`Spi`] structs with [`AtomicSize`] /// /// `spi::FullDuplex` is only implemented when the `Spi` struct has [`Duplex`] From 375c640b93d07a315425a8b40348fd898fe869ea Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Mon, 29 Apr 2024 16:14:10 -0400 Subject: [PATCH 25/30] Fix T1 examples (again) --- boards/feather_m0/examples/pwm.rs | 13 ++-- boards/feather_m0/examples/timers.rs | 4 +- .../feather_m4/examples/neopixel_rainbow.rs | 5 +- boards/feather_m4/examples/serial.rs | 7 ++- boards/feather_m4/examples/timers.rs | 4 +- boards/feather_m4/examples/uart.rs | 4 +- boards/feather_m4/examples/uart_poll_echo.rs | 10 ++- boards/metro_m4/Cargo.toml | 2 + boards/metro_m4/examples/neopixel_blink.rs | 7 ++- boards/metro_m4/examples/neopixel_rainbow.rs | 5 +- boards/metro_m4/examples/serial.rs | 7 ++- boards/metro_m4/examples/spi.rs | 9 ++- boards/metro_m4/examples/timer.rs | 4 +- boards/samd11_bare/examples/serial.rs | 7 ++- boards/samd11_bare/examples/timer.rs | 4 +- hal/src/delay.rs | 62 ++++++++++++------- hal/src/lib.rs | 2 + hal/src/prelude.rs | 4 +- 18 files changed, 106 insertions(+), 54 deletions(-) diff --git a/boards/feather_m0/examples/pwm.rs b/boards/feather_m0/examples/pwm.rs index 8deb883a76bd..3dc284a79f9f 100644 --- a/boards/feather_m0/examples/pwm.rs +++ b/boards/feather_m0/examples/pwm.rs @@ -15,6 +15,7 @@ use feather_m0 as bsp; use bsp::pin_alias; use hal::clock::GenericClockController; use hal::delay::Delay; +use hal::ehal::{delay::DelayNs, pwm::SetDutyCycle}; use hal::fugit::RateExtU32; use hal::pwm::Pwm3; use pac::{CorePeripherals, Peripherals}; @@ -42,12 +43,14 @@ fn main() -> ! { peripherals.TC3, &mut peripherals.PM, ); - let max_duty = pwm3.get_max_duty(); + let max_duty = pwm3.max_duty_cycle(); loop { - pwm3.set_duty(max_duty / 2); - delay.delay_ms(1000u16); - pwm3.set_duty(max_duty / 8); - delay.delay_ms(1000u16); + // The embedded-hal spec requires that set_duty_cycle returns a Result. + // In our case, the function is infaillible so we can safely ignore the result. + let _ = pwm3.set_duty_cycle(max_duty / 2); + delay.delay_ms(1000); + let _ = pwm3.set_duty_cycle(max_duty / 8); + delay.delay_ms(1000); } } diff --git a/boards/feather_m0/examples/timers.rs b/boards/feather_m0/examples/timers.rs index 9e7907e6aa5e..5618649e3fbf 100644 --- a/boards/feather_m0/examples/timers.rs +++ b/boards/feather_m0/examples/timers.rs @@ -12,9 +12,11 @@ use feather_m0 as bsp; use bsp::{entry, pin_alias}; use hal::clock::GenericClockController; -use hal::prelude::*; +use hal::ehal::digital::OutputPin; +use hal::nb; use hal::time::Hertz; use hal::timer::TimerCounter; +use hal::timer_traits::InterruptDrivenTimer; use pac::Peripherals; #[entry] diff --git a/boards/feather_m4/examples/neopixel_rainbow.rs b/boards/feather_m4/examples/neopixel_rainbow.rs index 5bd27f58d621..2dbfe83187ac 100644 --- a/boards/feather_m4/examples/neopixel_rainbow.rs +++ b/boards/feather_m4/examples/neopixel_rainbow.rs @@ -19,10 +19,11 @@ use panic_semihosting as _; use bsp::entry; use hal::clock::GenericClockController; use hal::delay::Delay; +use hal::ehal::delay::DelayNs; use hal::pac::{CorePeripherals, Peripherals}; -use hal::prelude::*; use hal::time::Hertz; use hal::timer::*; +use hal::timer_traits::InterruptDrivenTimer; use smart_leds::{ hsv::{hsv2rgb, Hsv}, @@ -62,7 +63,7 @@ fn main() -> ! { val: 2, })]; neopixel.write(colors.iter().cloned()).unwrap(); - delay.delay_ms(5u8); + delay.delay_ms(5); } } } diff --git a/boards/feather_m4/examples/serial.rs b/boards/feather_m4/examples/serial.rs index 6f84c465c8e5..5d54cbdfeebe 100644 --- a/boards/feather_m4/examples/serial.rs +++ b/boards/feather_m4/examples/serial.rs @@ -12,10 +12,13 @@ use panic_semihosting as _; use bsp::{entry, periph_alias, pin_alias}; use hal::clock::GenericClockController; use hal::delay::Delay; +use hal::ehal::delay::DelayNs; +use hal::embedded_hal_nb::serial::Write; +use hal::fugit::RateExtU32; +use hal::nb; use hal::pac::gclk::genctrl::SRCSELECT_A; use hal::pac::gclk::pchctrl::GENSELECT_A; use hal::pac::{CorePeripherals, Peripherals}; -use hal::prelude::*; #[entry] fn main() -> ! { @@ -49,6 +52,6 @@ fn main() -> ! { for byte in b"Hello, world!" { nb::block!(uart.write(*byte)).unwrap(); } - delay.delay_ms(1000u16); + delay.delay_ms(1000); } } diff --git a/boards/feather_m4/examples/timers.rs b/boards/feather_m4/examples/timers.rs index 84e0851af524..abdceed60dbf 100644 --- a/boards/feather_m4/examples/timers.rs +++ b/boards/feather_m4/examples/timers.rs @@ -13,9 +13,11 @@ use panic_semihosting as _; use bsp::entry; use hal::clock::GenericClockController; +use hal::ehal::digital::OutputPin; +use hal::nb; use hal::pac::Peripherals; -use hal::prelude::*; use hal::time::Hertz; +use hal::timer_traits::InterruptDrivenTimer; use hal::timer::TimerCounter; diff --git a/boards/feather_m4/examples/uart.rs b/boards/feather_m4/examples/uart.rs index eed5be270ea8..a2fe007febe2 100644 --- a/boards/feather_m4/examples/uart.rs +++ b/boards/feather_m4/examples/uart.rs @@ -13,7 +13,9 @@ use feather_m4 as bsp; use bsp::{entry, periph_alias, pin_alias}; use hal::clock::GenericClockController; use hal::dmac::{DmaController, PriorityLevel}; -use hal::prelude::*; +use hal::embedded_hal_nb::serial::{Read, Write}; +use hal::fugit::RateExtU32; +use hal::nb; use pac::Peripherals; diff --git a/boards/feather_m4/examples/uart_poll_echo.rs b/boards/feather_m4/examples/uart_poll_echo.rs index 5d923087573c..bb467e1ee365 100644 --- a/boards/feather_m4/examples/uart_poll_echo.rs +++ b/boards/feather_m4/examples/uart_poll_echo.rs @@ -19,10 +19,14 @@ use panic_semihosting as _; use bsp::{entry, periph_alias, pin_alias}; use hal::clock::GenericClockController; use hal::delay::Delay; +use hal::ehal::delay::DelayNs; +use hal::ehal::digital::OutputPin; +use hal::embedded_hal_nb::serial::{Read, Write}; +use hal::fugit::RateExtU32; +use hal::nb; use hal::pac::gclk::genctrl::SRCSELECT_A; use hal::pac::gclk::pchctrl::GENSELECT_A; use hal::pac::{CorePeripherals, Peripherals}; -use hal::prelude::*; #[entry] fn main() -> ! { @@ -67,10 +71,10 @@ fn main() -> ! { // Blink the red led to show that a character has arrived red_led.set_high().unwrap(); - delay.delay_ms(2u16); + delay.delay_ms(2); red_led.set_low().unwrap(); } - Err(_) => delay.delay_ms(5u16), + Err(_) => delay.delay_ms(5), }; } } diff --git a/boards/metro_m4/Cargo.toml b/boards/metro_m4/Cargo.toml index 1ca44e6090c2..483a061541fa 100644 --- a/boards/metro_m4/Cargo.toml +++ b/boards/metro_m4/Cargo.toml @@ -33,6 +33,8 @@ features = ["critical-section-single-core"] [dev-dependencies] cortex-m = "0.7" +embedded-hal = "1.0" +embedded-hal-nb = "1.0" usbd-serial = "0.2" panic-probe = "0.3" panic-halt = "0.2" diff --git a/boards/metro_m4/examples/neopixel_blink.rs b/boards/metro_m4/examples/neopixel_blink.rs index 1196499853b2..ed52cf8d2c67 100644 --- a/boards/metro_m4/examples/neopixel_blink.rs +++ b/boards/metro_m4/examples/neopixel_blink.rs @@ -14,9 +14,10 @@ use panic_semihosting as _; use bsp::entry; use hal::clock::GenericClockController; use hal::delay::Delay; -use hal::prelude::*; +use hal::ehal::delay::DelayNs; use hal::time::Hertz; use hal::timer::TimerCounter; +use hal::timer_traits::InterruptDrivenTimer; use pac::{CorePeripherals, Peripherals}; use ws2812_timer_delay as ws2812; @@ -49,11 +50,11 @@ fn main() -> ! { neopixel .write(brightness(data.iter().cloned(), 32)) .unwrap(); - delay.delay_ms(250u8); + delay.delay_ms(250); let data2 = [RGB8::default(); 1]; neopixel .write(brightness(data2.iter().cloned(), 32)) .unwrap(); - delay.delay_ms(250u8); + delay.delay_ms(250); } } diff --git a/boards/metro_m4/examples/neopixel_rainbow.rs b/boards/metro_m4/examples/neopixel_rainbow.rs index 29a0ed91fe32..761bdd4a08b7 100644 --- a/boards/metro_m4/examples/neopixel_rainbow.rs +++ b/boards/metro_m4/examples/neopixel_rainbow.rs @@ -14,9 +14,10 @@ use panic_semihosting as _; use bsp::entry; use hal::clock::GenericClockController; use hal::delay::Delay; -use hal::prelude::*; +use hal::ehal::delay::DelayNs; use hal::time::Hertz; use hal::timer::TimerCounter; +use hal::timer_traits::InterruptDrivenTimer; use pac::{CorePeripherals, Peripherals}; use smart_leds::{ @@ -54,7 +55,7 @@ fn main() -> ! { val: 32, })]; neopixel.write(colors.iter().cloned()).unwrap(); - delay.delay_ms(5u8); + delay.delay_ms(5); } } } diff --git a/boards/metro_m4/examples/serial.rs b/boards/metro_m4/examples/serial.rs index b671ba90f1ec..50ce36e66848 100644 --- a/boards/metro_m4/examples/serial.rs +++ b/boards/metro_m4/examples/serial.rs @@ -13,8 +13,11 @@ use panic_semihosting as _; use bsp::{entry, periph_alias, pin_alias}; use hal::clock::GenericClockController; use hal::delay::Delay; +use hal::ehal::delay::DelayNs; +use hal::ehal_nb::serial::Write; +use hal::fugit::RateExtU32; +use hal::nb; use hal::pac::{CorePeripherals, Peripherals}; -use hal::prelude::*; #[entry] fn main() -> ! { @@ -49,6 +52,6 @@ fn main() -> ! { // `Result<(), Error>` nb::block!(uart.write(*byte)).unwrap(); } - delay.delay_ms(1000u16); + delay.delay_ms(1000); } } diff --git a/boards/metro_m4/examples/spi.rs b/boards/metro_m4/examples/spi.rs index 56266536d16f..09980afe4a36 100644 --- a/boards/metro_m4/examples/spi.rs +++ b/boards/metro_m4/examples/spi.rs @@ -13,8 +13,11 @@ use panic_semihosting as _; use bsp::{entry, periph_alias}; use hal::clock::GenericClockController; use hal::delay::Delay; +use hal::ehal::delay::DelayNs; +use hal::ehal_nb::serial::Write; +use hal::fugit::RateExtU32; +use hal::nb; use hal::pac::{CorePeripherals, Peripherals}; -use hal::prelude::*; #[entry] fn main() -> ! { @@ -41,8 +44,8 @@ fn main() -> ! { loop { for byte in b"Hello, world!" { - nb::block!(spi.send(*byte)).unwrap(); + nb::block!(spi.write(*byte)).unwrap(); } - delay.delay_ms(1000u16); + delay.delay_ms(1000); } } diff --git a/boards/metro_m4/examples/timer.rs b/boards/metro_m4/examples/timer.rs index c2a90b71ecc4..3ddff29493b6 100644 --- a/boards/metro_m4/examples/timer.rs +++ b/boards/metro_m4/examples/timer.rs @@ -12,10 +12,12 @@ use panic_semihosting as _; use bsp::entry; use hal::clock::GenericClockController; +use hal::ehal::digital::OutputPin; +use hal::nb; use hal::pac::Peripherals; -use hal::prelude::*; use hal::time::Hertz; use hal::timer::TimerCounter; +use hal::timer_traits::InterruptDrivenTimer; use nb::block; diff --git a/boards/samd11_bare/examples/serial.rs b/boards/samd11_bare/examples/serial.rs index 375e76414d23..a47350fb3b2f 100644 --- a/boards/samd11_bare/examples/serial.rs +++ b/boards/samd11_bare/examples/serial.rs @@ -6,7 +6,10 @@ use samd11_bare as bsp; use bsp::entry; use hal::clock::GenericClockController; -use hal::prelude::*; +use hal::ehal::delay::DelayNs; +use hal::ehal_nb::serial::Write; +use hal::fugit::RateExtU32; +use hal::nb; #[cfg(not(feature = "use_semihosting"))] use panic_halt as _; @@ -61,6 +64,6 @@ fn main() -> ! { // `Result<(), Error>` nb::block!(uart.write(*byte)).unwrap(); } - delay.delay_ms(1000u16); + delay.delay_ms(1000); } } diff --git a/boards/samd11_bare/examples/timer.rs b/boards/samd11_bare/examples/timer.rs index 15be06be8233..6026dcad8a4e 100644 --- a/boards/samd11_bare/examples/timer.rs +++ b/boards/samd11_bare/examples/timer.rs @@ -13,9 +13,11 @@ use bsp::pac; use bsp::entry; use hal::clock::GenericClockController; -use hal::prelude::*; +use hal::ehal::digital::OutputPin; +use hal::nb; use hal::time::Hertz; use hal::timer::TimerCounter; +use hal::timer_traits::InterruptDrivenTimer; use pac::Peripherals; #[entry] diff --git a/hal/src/delay.rs b/hal/src/delay.rs index af74664f9262..f11c2857c306 100644 --- a/hal/src/delay.rs +++ b/hal/src/delay.rs @@ -4,7 +4,8 @@ use cortex_m::peripheral::syst::SystClkSource; use cortex_m::peripheral::SYST; use crate::clock::GenericClockController; -use crate::ehal_02::blocking::delay::{DelayMs, DelayUs}; +use crate::ehal::delay::DelayNs; +use crate::ehal_02; use crate::time::Hertz; /// System timer (SysTick) as a delay provider @@ -30,25 +31,14 @@ impl Delay { } } -impl DelayMs<u32> for Delay { - fn delay_ms(&mut self, ms: u32) { - self.delay_us(ms * 1_000); - } -} - -impl DelayMs<u16> for Delay { - fn delay_ms(&mut self, ms: u16) { - self.delay_ms(ms as u32); +impl DelayNs for Delay { + // The default method is delay_ns. If we don't provide implementations for delay_us and delay_ms, the trait impl + // will use delay_ns to implement the other two methods. As the delay implementation is actually defined in terms + // of microseconds, we need to provide implementations for all three methods. + fn delay_ns(&mut self, ns: u32) { + self.delay_us(ns / 1000); } -} -impl DelayMs<u8> for Delay { - fn delay_ms(&mut self, ms: u8) { - self.delay_ms(ms as u32); - } -} - -impl DelayUs<u32> for Delay { fn delay_us(&mut self, us: u32) { // The SysTick Reload Value register supports values between 1 and 0x00FFFFFF. const MAX_RVR: u32 = 0x00FF_FFFF; @@ -74,16 +64,44 @@ impl DelayUs<u32> for Delay { self.syst.disable_counter(); } } + + fn delay_ms(&mut self, ms: u32) { + self.delay_us(ms * 1000); + } +} + +impl ehal_02::blocking::delay::DelayMs<u32> for Delay { + fn delay_ms(&mut self, ms: u32) { + <Self as DelayNs>::delay_us(self, ms * 1_000); + } +} + +impl ehal_02::blocking::delay::DelayMs<u16> for Delay { + fn delay_ms(&mut self, ms: u16) { + <Self as ehal_02::blocking::delay::DelayMs<u32>>::delay_ms(self, ms as u32); + } +} + +impl ehal_02::blocking::delay::DelayMs<u8> for Delay { + fn delay_ms(&mut self, ms: u8) { + <Self as ehal_02::blocking::delay::DelayMs<u32>>::delay_ms(self, ms as u32); + } +} + +impl ehal_02::blocking::delay::DelayUs<u32> for Delay { + fn delay_us(&mut self, us: u32) { + <Self as DelayNs>::delay_us(self, us); + } } -impl DelayUs<u16> for Delay { +impl ehal_02::blocking::delay::DelayUs<u16> for Delay { fn delay_us(&mut self, us: u16) { - self.delay_us(us as u32) + <Self as ehal_02::blocking::delay::DelayUs<u32>>::delay_us(self, us as u32); } } -impl DelayUs<u8> for Delay { +impl ehal_02::blocking::delay::DelayUs<u8> for Delay { fn delay_us(&mut self, us: u8) { - self.delay_us(us as u32) + <Self as ehal_02::blocking::delay::DelayUs<u32>>::delay_us(self, us as u32); } } diff --git a/hal/src/lib.rs b/hal/src/lib.rs index 3c8b3ac3ca9f..b96934e528a5 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -2,8 +2,10 @@ use embedded_hal_02 as ehal_02; pub use embedded_hal_1 as ehal; +pub use embedded_hal_nb as ehal_nb; pub use embedded_io; pub use fugit; +pub use nb; pub use paste; pub mod typelevel; diff --git a/hal/src/prelude.rs b/hal/src/prelude.rs index 10271f207feb..e68cca365ac9 100644 --- a/hal/src/prelude.rs +++ b/hal/src/prelude.rs @@ -1,6 +1,6 @@ //! Import the prelude to gain convenient access to helper traits pub use crate::eic::pin::EicPin; -pub use crate::timer_traits::InterruptDrivenTimer as _atsamd_hal_timer_traits_InterruptDrivenTimer; +pub use crate::timer_traits::InterruptDrivenTimer; pub use fugit::ExtU32 as _; pub use fugit::RateExtU32 as _; @@ -11,5 +11,3 @@ pub use crate::ehal_02::digital::v2::OutputPin as _atsamd_hal_embedded_hal_digit pub use crate::ehal_02::digital::v2::ToggleableOutputPin as _atsamd_hal_embedded_hal_digital_v2_ToggleableOutputPin; pub use crate::ehal_02::prelude::*; - -pub use nb; From 3130bacfa5de89634c9a2564c214f1b7ce286bc6 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Mon, 29 Apr 2024 16:15:54 -0400 Subject: [PATCH 26/30] rustfmt --- hal/src/delay.rs | 5 +++-- hal/src/sercom/spi.rs | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/hal/src/delay.rs b/hal/src/delay.rs index f11c2857c306..b683a97c8da9 100644 --- a/hal/src/delay.rs +++ b/hal/src/delay.rs @@ -32,8 +32,9 @@ impl Delay { } impl DelayNs for Delay { - // The default method is delay_ns. If we don't provide implementations for delay_us and delay_ms, the trait impl - // will use delay_ns to implement the other two methods. As the delay implementation is actually defined in terms + // The default method is delay_ns. If we don't provide implementations for + // delay_us and delay_ms, the trait impl will use delay_ns to implement the + // other two methods. As the delay implementation is actually defined in terms // of microseconds, we need to provide implementations for all three methods. fn delay_ns(&mut self, ns: u32) { self.delay_us(ns / 1000); diff --git a/hal/src/sercom/spi.rs b/hal/src/sercom/spi.rs index 81ad21cd4ca2..356cff25f54b 100644 --- a/hal/src/sercom/spi.rs +++ b/hal/src/sercom/spi.rs @@ -1297,7 +1297,8 @@ where self.config } - /// Block until at least one of the flags specified in `flags`, or `ERROR`, is set. + /// Block until at least one of the flags specified in `flags`, or `ERROR`, + /// is set. /// /// # Returns `Err(Error)` if an error is detected. fn block_on_flags(&mut self, flags: Flags) -> Result<(), Error> { From b9591cbd44369c81306af8bd0fa52b8a41267fbb Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Mon, 29 Apr 2024 16:22:05 -0400 Subject: [PATCH 27/30] Fix feather_m4 compilation --- boards/feather_m4/examples/serial.rs | 2 +- boards/feather_m4/examples/uart.rs | 2 +- boards/feather_m4/examples/uart_poll_echo.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/boards/feather_m4/examples/serial.rs b/boards/feather_m4/examples/serial.rs index 5d54cbdfeebe..6351ffead447 100644 --- a/boards/feather_m4/examples/serial.rs +++ b/boards/feather_m4/examples/serial.rs @@ -13,7 +13,7 @@ use bsp::{entry, periph_alias, pin_alias}; use hal::clock::GenericClockController; use hal::delay::Delay; use hal::ehal::delay::DelayNs; -use hal::embedded_hal_nb::serial::Write; +use hal::ehal_nb::serial::Write; use hal::fugit::RateExtU32; use hal::nb; use hal::pac::gclk::genctrl::SRCSELECT_A; diff --git a/boards/feather_m4/examples/uart.rs b/boards/feather_m4/examples/uart.rs index a2fe007febe2..be57264a23cc 100644 --- a/boards/feather_m4/examples/uart.rs +++ b/boards/feather_m4/examples/uart.rs @@ -13,7 +13,7 @@ use feather_m4 as bsp; use bsp::{entry, periph_alias, pin_alias}; use hal::clock::GenericClockController; use hal::dmac::{DmaController, PriorityLevel}; -use hal::embedded_hal_nb::serial::{Read, Write}; +use hal::ehal_nb::serial::{Read, Write}; use hal::fugit::RateExtU32; use hal::nb; diff --git a/boards/feather_m4/examples/uart_poll_echo.rs b/boards/feather_m4/examples/uart_poll_echo.rs index bb467e1ee365..5b4414ed5832 100644 --- a/boards/feather_m4/examples/uart_poll_echo.rs +++ b/boards/feather_m4/examples/uart_poll_echo.rs @@ -21,7 +21,7 @@ use hal::clock::GenericClockController; use hal::delay::Delay; use hal::ehal::delay::DelayNs; use hal::ehal::digital::OutputPin; -use hal::embedded_hal_nb::serial::{Read, Write}; +use hal::ehal_nb::serial::{Read, Write}; use hal::fugit::RateExtU32; use hal::nb; use hal::pac::gclk::genctrl::SRCSELECT_A; From a2097a58a13d4defb982ca4cdfe0b073383bf6a1 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Mon, 29 Apr 2024 16:27:39 -0400 Subject: [PATCH 28/30] Fix metro_m4 spi example --- boards/metro_m4/examples/spi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/metro_m4/examples/spi.rs b/boards/metro_m4/examples/spi.rs index 09980afe4a36..beb3021bcc24 100644 --- a/boards/metro_m4/examples/spi.rs +++ b/boards/metro_m4/examples/spi.rs @@ -14,7 +14,7 @@ use bsp::{entry, periph_alias}; use hal::clock::GenericClockController; use hal::delay::Delay; use hal::ehal::delay::DelayNs; -use hal::ehal_nb::serial::Write; +use hal::ehal_nb::spi::FullDuplex; use hal::fugit::RateExtU32; use hal::nb; use hal::pac::{CorePeripherals, Peripherals}; From 88a5b9c38a47f66cfb07e3aa010336051fad60b7 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Tue, 30 Apr 2024 21:14:04 -0400 Subject: [PATCH 29/30] Fix metro_m4 i2c example --- boards/metro_m4/examples/i2c.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/boards/metro_m4/examples/i2c.rs b/boards/metro_m4/examples/i2c.rs index 93efdd97b96e..9c30c3be0b52 100644 --- a/boards/metro_m4/examples/i2c.rs +++ b/boards/metro_m4/examples/i2c.rs @@ -19,8 +19,8 @@ use pac::Peripherals; use hal::clock::GenericClockController; use hal::dmac::{DmaController, PriorityLevel}; -use hal::ehal::blocking::i2c::WriteRead; -use hal::prelude::*; +use hal::ehal::i2c::I2c; +use hal::fugit::RateExtU32; use hal::sercom::i2c; const LENGTH: usize = 1; @@ -59,7 +59,7 @@ fn main() -> ! { let pads = i2c::Pads::new(sda, scl); let i2c_sercom = periph_alias!(peripherals.i2c_sercom); let mut i2c = i2c::Config::new(&mclk, i2c_sercom, pads, sercom5_clock.freq()) - .baud(100.khz()) + .baud(100.kHz()) .enable(); let mut buffer = [0x00; 1]; From 94c55b83c101354629ab082c60227d1e9493e22e Mon Sep 17 00:00:00 2001 From: Justin Beaurivage <justin@wearableavionics.com> Date: Tue, 30 Apr 2024 21:23:59 -0400 Subject: [PATCH 30/30] Reexport dma feature in T1 BSPs and fix i2c examples --- boards/metro_m0/Cargo.toml | 4 +++- boards/metro_m0/examples/i2c.rs | 6 +++--- boards/metro_m4/Cargo.toml | 4 +++- boards/samd11_bare/Cargo.toml | 4 +++- boards/samd11_bare/examples/i2c.rs | 6 +++--- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/boards/metro_m0/Cargo.toml b/boards/metro_m0/Cargo.toml index fb21b447df34..bbcaa5a9e0d2 100644 --- a/boards/metro_m0/Cargo.toml +++ b/boards/metro_m0/Cargo.toml @@ -41,6 +41,8 @@ cortex-m-rtic = "1.0" [features] # ask the HAL to enable atsamd21g support default = ["rt", "atsamd-hal/samd21g"] +dma = ["atsamd-hal/dma"] +max-channels = ["dma", "atsamd-hal/max-channels"] rt = ["cortex-m-rt", "atsamd-hal/samd21g-rt"] rtic = ["atsamd-hal/rtic"] use_rtt = ["atsamd-hal/use_rtt"] @@ -71,4 +73,4 @@ name = "blinky_basic" [[example]] name = "i2c" -required-features = ["atsamd-hal/dma"] +required-features = ["dma"] diff --git a/boards/metro_m0/examples/i2c.rs b/boards/metro_m0/examples/i2c.rs index c6add5dfe4cb..eca5fd5889a1 100644 --- a/boards/metro_m0/examples/i2c.rs +++ b/boards/metro_m0/examples/i2c.rs @@ -19,8 +19,8 @@ use pac::Peripherals; use hal::clock::GenericClockController; use hal::dmac::{DmaController, PriorityLevel}; -use hal::ehal::blocking::i2c::WriteRead; -use hal::prelude::*; +use hal::ehal::i2c::I2c; +use hal::fugit::RateExtU32; use hal::sercom::i2c; const LENGTH: usize = 1; @@ -57,7 +57,7 @@ fn main() -> ! { let sercom3_clock = &clocks.sercom3_core(&gclk0).unwrap(); let pads = i2c::Pads::new(sda, scl); let mut i2c = i2c::Config::new(&pm, peripherals.SERCOM3, pads, sercom3_clock.freq()) - .baud(100.khz()) + .baud(100.kHz()) .enable(); let mut buffer = [0x00; 1]; diff --git a/boards/metro_m4/Cargo.toml b/boards/metro_m4/Cargo.toml index 483a061541fa..7f2bcd0d64f8 100644 --- a/boards/metro_m4/Cargo.toml +++ b/boards/metro_m4/Cargo.toml @@ -50,6 +50,8 @@ version = "0.3" [features] # ask the HAL to enable atsamd51j support default = ["rt", "atsamd-hal/samd51j"] +dma = ["atsamd-hal/dma"] +max-channels = ["dma", "atsamd-hal/max-channels"] rt = ["cortex-m-rt", "atsamd-hal/samd51j-rt"] usb = ["atsamd-hal/usb", "usb-device"] @@ -99,4 +101,4 @@ required-features = ["usb"] [[example]] name = "i2c" -required-features = ["atsamd-hal/dma"] +required-features = ["dma"] diff --git a/boards/samd11_bare/Cargo.toml b/boards/samd11_bare/Cargo.toml index c7defb95bb2a..068aaea8c1a7 100644 --- a/boards/samd11_bare/Cargo.toml +++ b/boards/samd11_bare/Cargo.toml @@ -36,6 +36,8 @@ rtt-target = { version = "0.3.0", features = ["cortex-m"] } [features] # ask the HAL to enable atsamd11c support default = ["rt", "atsamd-hal/samd11c"] +dma = ["atsamd-hal/dma"] +max-channels = ["dma", "atsamd-hal/max-channels"] rt = ["cortex-m-rt", "atsamd-hal/samd11c-rt"] use_semihosting = [] @@ -63,4 +65,4 @@ name = "timer" [[example]] name = "i2c" -required-features = ["atsamd-hal/dma"] +required-features = ["dma"] diff --git a/boards/samd11_bare/examples/i2c.rs b/boards/samd11_bare/examples/i2c.rs index ce6e7a35e742..7c5d37c14e28 100644 --- a/boards/samd11_bare/examples/i2c.rs +++ b/boards/samd11_bare/examples/i2c.rs @@ -19,8 +19,8 @@ use pac::Peripherals; use hal::clock::GenericClockController; use hal::dmac::{DmaController, PriorityLevel}; -use hal::ehal::blocking::i2c::WriteRead; -use hal::prelude::*; +use hal::ehal::i2c::I2c; +use hal::fugit::RateExtU32; use hal::sercom::i2c; const LENGTH: usize = 1; @@ -57,7 +57,7 @@ fn main() -> ! { let sercom0_clock = &clocks.sercom0_core(&gclk0).unwrap(); let pads = i2c::Pads::new(sda, scl); let mut i2c = i2c::Config::new(&pm, peripherals.SERCOM0, pads, sercom0_clock.freq()) - .baud(100.khz()) + .baud(100.kHz()) .enable(); let mut buffer = [0x00; 1];