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 - [![Crates.io](https://img.shields.io/crate
 
 | Chip family | Documented features   |
 |:------------|:----------------------|
-| [samd11c]   | samd11c unproven      |
-| [samd11d]   | samd11d unproven      |
-| [samd21g]   | samd21g unproven usb  |
-| [samd21j]   | samd21j unproven usb  |
-| [samd51g]   | samd51g unproven usb  |
-| [samd51j]   | samd51j unproven usb  |
-| [samd51n]   | samd51n unproven usb  |
-| [samd51p]   | samd51p unproven usb  |
+| [samd11c]   | samd11c               |
+| [samd11d]   | samd11d               |
+| [samd21g]   | samd21g usb           |
+| [samd21j]   | samd21j usb           |
+| [samd51g]   | samd51g usb           |
+| [samd51j]   | samd51j usb           |
+| [samd51n]   | samd51n usb           |
+| [samd51p]   | samd51p usb           |
 
 [samd11c]: https://atsamd-rs.github.io/docs/samd11c/thumbv6m-none-eabi/doc/atsamd_hal/index.html
 [samd11d]: https://atsamd-rs.github.io/docs/samd11d/thumbv6m-none-eabi/doc/atsamd_hal/index.html
diff --git a/boards/atsame54_xpro/Cargo.toml b/boards/atsame54_xpro/Cargo.toml
index fc721f0fdf3f..ad427bcce310 100644
--- a/boards/atsame54_xpro/Cargo.toml
+++ b/boards/atsame54_xpro/Cargo.toml
@@ -38,9 +38,8 @@ panic-rtt-target = { version = "0.1", features = ["cortex-m"] }
 rtt-target = { version = "0.3", features = ["cortex-m"] }
 
 [features]
-default = ["rt", "atsamd-hal/same54p", "atsamd-hal/unproven"]
+default = ["rt", "atsamd-hal/same54p"]
 rt = ["cortex-m-rt", "atsamd-hal/same54p-rt"]
-unproven = ["atsamd-hal/unproven"]
 usb = ["atsamd-hal/usb", "usb-device"]
 can = ["atsamd-hal/can"]
 
diff --git a/boards/feather_m0/Cargo.toml b/boards/feather_m0/Cargo.toml
index 1f802aca4129..e1408fb85623 100644
--- a/boards/feather_m0/Cargo.toml
+++ b/boards/feather_m0/Cargo.toml
@@ -53,7 +53,6 @@ panic-semihosting = "0.5"
 # ask the HAL to enable atsamd21g support
 default = ["rt", "atsamd-hal/samd21g"]
 rt = ["cortex-m-rt", "atsamd-hal/samd21g-rt"]
-unproven = ["atsamd-hal/unproven"]
 use_rtt = ["atsamd-hal/use_rtt"]
 usb = ["atsamd-hal/usb", "usb-device"]
 # Enable pins for the radio on "RadioFruits" with RFM95, RFM96, RFM69
@@ -87,11 +86,9 @@ name = "timers"
 
 [[example]]
 name = "pwm"
-required-features = ["unproven"]
 
 [[example]]
 name = "adc"
-required-features = ["unproven"]
 
 [[example]]
 name = "ssd1306_graphicsmode_128x64_i2c"
@@ -113,7 +110,7 @@ name = "ssd1306_terminalmode_128x64_spi"
 
 [[example]]
 name = "usb_echo"
-required-features = ["usb", "unproven"]
+required-features = ["usb"]
 
 [[example]]
 name = "sleeping_timer"
@@ -127,15 +124,15 @@ required-features = ["dma"]
 
 [[example]]
 name = "clock"
-required-features = ["usb", "unproven"]
+required-features = ["usb"]
 
 [[example]]
 name = "adalogger"
-required-features = ["adalogger", "usb", "sdmmc", "unproven"]
+required-features = ["adalogger", "usb", "sdmmc"]
 
 [[example]]
 name = "blinky_rtic"
-required-features = ["rtic", "unproven"]
+required-features = ["rtic"]
 
 [[example]]
 name = "uart"
diff --git a/boards/feather_m4/Cargo.toml b/boards/feather_m4/Cargo.toml
index b8f7fbede7f8..03ea190917f2 100644
--- a/boards/feather_m4/Cargo.toml
+++ b/boards/feather_m4/Cargo.toml
@@ -45,9 +45,8 @@ heapless = "0.7"
 # ask the HAL to enable atsamd51j support
 default = ["rt", "atsamd-hal/samd51j"]
 rt = ["cortex-m-rt", "atsamd-hal/samd51j-rt"]
-unproven = ["atsamd-hal/unproven"]
 usb = ["atsamd-hal/usb", "usb-device"]
-dma = ["atsamd-hal/dma", "unproven"]
+dma = ["atsamd-hal/dma"]
 max-channels = ["dma", "atsamd-hal/dma"]
 
 
@@ -64,7 +63,6 @@ opt-level = "s"
 
 [[example]]
 name = "pwm"
-required-features = ["unproven"]
 
 [[example]]
 name = "usb_echo"
@@ -80,15 +78,15 @@ required-features = ["dma"]
 
 [[example]]
 name = "pukcc_test"
-required-features = ["unproven", "usb"]
+required-features = ["usb"]
 
 [[example]]
 name = "nvm_dsu"
-required-features = ["unproven", "usb"]
+required-features = ["usb"]
 
 [[example]]
 name = "smart_eeprom"
-required-features = ["unproven", "usb"]
+required-features = [ "usb"]
 
 [[example]]
 name = "i2c"
diff --git a/boards/feather_m4/examples/pwm.rs b/boards/feather_m4/examples/pwm.rs
index 5bc77252596e..2b887e4466c9 100644
--- a/boards/feather_m4/examples/pwm.rs
+++ b/boards/feather_m4/examples/pwm.rs
@@ -2,8 +2,6 @@
 #![no_main]
 
 // Pulse Width Modulation
-//
-// cargo build --features="unproven"
 
 use bsp::hal;
 use feather_m4 as bsp;
diff --git a/boards/metro_m0/Cargo.toml b/boards/metro_m0/Cargo.toml
index e14644a312c1..fb21b447df34 100644
--- a/boards/metro_m0/Cargo.toml
+++ b/boards/metro_m0/Cargo.toml
@@ -43,7 +43,6 @@ cortex-m-rtic = "1.0"
 default = ["rt", "atsamd-hal/samd21g"]
 rt = ["cortex-m-rt", "atsamd-hal/samd21g-rt"]
 rtic = ["atsamd-hal/rtic"]
-unproven = ["atsamd-hal/unproven"]
 use_rtt = ["atsamd-hal/use_rtt"]
 usb = ["atsamd-hal/usb", "usb-device"]
 use_semihosting = []
@@ -61,11 +60,11 @@ opt-level = "s"
 
 [[example]]
 name = "usb_echo"
-required-features = ["usb", "unproven"]
+required-features = ["usb"]
 
 [[example]]
 name = "blinky_rtic"
-required-features = ["rtic", "unproven"]
+required-features = ["rtic"]
 
 [[example]]
 name = "blinky_basic"
diff --git a/boards/metro_m4/Cargo.toml b/boards/metro_m4/Cargo.toml
index 2722c9a728b9..1ca44e6090c2 100644
--- a/boards/metro_m4/Cargo.toml
+++ b/boards/metro_m4/Cargo.toml
@@ -49,7 +49,6 @@ version = "0.3"
 # ask the HAL to enable atsamd51j support
 default = ["rt", "atsamd-hal/samd51j"]
 rt = ["cortex-m-rt", "atsamd-hal/samd51j-rt"]
-unproven = ["atsamd-hal/unproven"]
 usb = ["atsamd-hal/usb", "usb-device"]
 
 [profile.dev]
@@ -76,7 +75,6 @@ name = "neopixel_rainbow"
 
 [[example]]
 name = "pwm"
-required-features = ["unproven"]
 
 [[example]]
 name = "serial"
@@ -89,14 +87,13 @@ name = "timer"
 
 [[example]]
 name = "adc"
-required-features = ["unproven"]
 
 [[example]]
 name = "trng"
 
 [[example]]
 name = "usb_logging"
-required-features = ["usb", "unproven"]
+required-features = ["usb"]
 
 [[example]]
 name = "i2c"
diff --git a/boards/samd11_bare/Cargo.toml b/boards/samd11_bare/Cargo.toml
index 74d7810b3ae5..c7defb95bb2a 100644
--- a/boards/samd11_bare/Cargo.toml
+++ b/boards/samd11_bare/Cargo.toml
@@ -37,7 +37,6 @@ rtt-target = { version = "0.3.0", features = ["cortex-m"] }
 # ask the HAL to enable atsamd11c support
 default = ["rt", "atsamd-hal/samd11c"]
 rt = ["cortex-m-rt", "atsamd-hal/samd11c-rt"]
-unproven = ["atsamd-hal/unproven"]
 use_semihosting = []
 
 [profile.release]
@@ -48,14 +47,13 @@ opt-level = "s"
 
 [[example]]
 name = "adc"
-required-features = ["unproven", "rt", "use_semihosting"]
+required-features = ["rt", "use_semihosting"]
 
 [[example]]
 name = "blinky_basic"
 
 [[example]]
 name = "pwm"
-required-features = ["unproven"]
 
 [[example]]
 name = "serial"
diff --git a/boards/samd11_bare/README.md b/boards/samd11_bare/README.md
index de966c9faf62..c8ff68eb05f7 100644
--- a/boards/samd11_bare/README.md
+++ b/boards/samd11_bare/README.md
@@ -23,7 +23,7 @@ Cargo flash needs to know the specific id of your chip, but its included in the
 
 Then cargo flash simply replaces your cargo build command!
 ```bash
-$ cargo flash --example blinky_basic --features unproven --release
+$ cargo flash --example blinky_basic --release
 ```
 
 ## Debugging: probe-run
@@ -42,7 +42,7 @@ $ cargo install probe-run
 
 Then simply use your ide's run or play button, or run:
 ```bash
-$ cargo run --release --example adc --features=unproven
+$ cargo run --release --example adc 
     Finished release [optimized + debuginfo] target(s) 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];