From c682d43fe42592c609b153d729c46acdef0c37ff Mon Sep 17 00:00:00 2001
From: Robin Mueller <robin.mueller.m@gmail.com>
Date: Fri, 14 Feb 2025 09:44:13 +0100
Subject: [PATCH] HAL update

---
 board-tests/src/main.rs        |  19 +--
 va108xx-hal/CHANGELOG.md       |  10 ++
 va108xx-hal/Cargo.toml         |   2 +-
 va108xx-hal/src/gpio/asynch.rs |   2 +-
 va108xx-hal/src/gpio/dynpin.rs |  25 +--
 va108xx-hal/src/gpio/pin.rs    |  67 ++++++--
 va108xx-hal/src/gpio/reg.rs    |   8 +-
 va108xx-hal/src/i2c.rs         | 281 +--------------------------------
 va108xx-hal/src/lib.rs         |   3 +-
 va108xx-hal/src/spi.rs         |   7 +
 10 files changed, 102 insertions(+), 322 deletions(-)

diff --git a/board-tests/src/main.rs b/board-tests/src/main.rs
index d59e3ac..7f9d71c 100644
--- a/board-tests/src/main.rs
+++ b/board-tests/src/main.rs
@@ -122,14 +122,14 @@ fn main() -> ! {
         }
         TestCase::Pulse => {
             let mut output_pulsed = pinsa.pa0.into_push_pull_output();
-            output_pulsed.pulse_mode(true, PinState::Low);
+            output_pulsed.configure_pulse_mode(true, PinState::Low);
             rprintln!("Pulsing high 10 times..");
             output_pulsed.set_low().unwrap();
             for _ in 0..10 {
                 output_pulsed.set_high().unwrap();
                 cortex_m::asm::delay(25_000_000);
             }
-            output_pulsed.pulse_mode(true, PinState::High);
+            output_pulsed.configure_pulse_mode(true, PinState::High);
             rprintln!("Pulsing low 10 times..");
             for _ in 0..10 {
                 output_pulsed.set_low().unwrap();
@@ -137,15 +137,12 @@ fn main() -> ! {
             }
         }
         TestCase::DelayGpio => {
-            let mut out_0 = pinsa
-                .pa0
-                .into_readable_push_pull_output()
-                .delay(true, false);
-            let mut out_1 = pinsa
-                .pa1
-                .into_readable_push_pull_output()
-                .delay(false, true);
-            let mut out_2 = pinsa.pa3.into_readable_push_pull_output().delay(true, true);
+            let mut out_0 = pinsa.pa0.into_readable_push_pull_output();
+            out_0.configure_delay(true, false);
+            let mut out_1 = pinsa.pa1.into_readable_push_pull_output();
+            out_1.configure_delay(false, true);
+            let mut out_2 = pinsa.pa3.into_readable_push_pull_output();
+            out_2.configure_delay(true, true);
             for _ in 0..20 {
                 out_0.toggle().unwrap();
                 out_1.toggle().unwrap();
diff --git a/va108xx-hal/CHANGELOG.md b/va108xx-hal/CHANGELOG.md
index d8f35fb..cd01c09 100644
--- a/va108xx-hal/CHANGELOG.md
+++ b/va108xx-hal/CHANGELOG.md
@@ -8,6 +8,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 
 ## [unreleased]
 
+## [v0.10.0]
+
+## Added
+
+- A lot of missing `defmt::Format` implementations.
+
+## Changed
+
+- Missing GPIO API replacements from `x` to `configure_x`
+
 ## [v0.9.0]
 
 ## Fixed
diff --git a/va108xx-hal/Cargo.toml b/va108xx-hal/Cargo.toml
index 26ea489..6209983 100644
--- a/va108xx-hal/Cargo.toml
+++ b/va108xx-hal/Cargo.toml
@@ -42,7 +42,7 @@ portable-atomic = "1"
 [features]
 default = ["rt"]
 rt = ["va108xx/rt"]
-defmt = ["dep:defmt", "fugit/defmt"]
+defmt = ["dep:defmt", "fugit/defmt", "embedded-hal/defmt-03"]
 
 [package.metadata.docs.rs]
 all-features = true
diff --git a/va108xx-hal/src/gpio/asynch.rs b/va108xx-hal/src/gpio/asynch.rs
index 0e5a478..40ccd14 100644
--- a/va108xx-hal/src/gpio/asynch.rs
+++ b/va108xx-hal/src/gpio/asynch.rs
@@ -115,7 +115,7 @@ impl InputPinFuture {
 
         EDGE_DETECTION[pin_id_to_offset(pin.id())]
             .store(false, core::sync::atomic::Ordering::Relaxed);
-        pin.interrupt_edge(
+        pin.configure_edge_interrupt(
             edge,
             InterruptConfig::new(irq, true, true),
             Some(sys_cfg),
diff --git a/va108xx-hal/src/gpio/dynpin.rs b/va108xx-hal/src/gpio/dynpin.rs
index 20447da..4dc56ee 100644
--- a/va108xx-hal/src/gpio/dynpin.rs
+++ b/va108xx-hal/src/gpio/dynpin.rs
@@ -181,6 +181,7 @@ pub struct DynPinId {
 /// This `struct` takes ownership of a [`DynPinId`] and provides an API to
 /// access the corresponding regsiters.
 #[derive(Debug)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub(crate) struct DynRegisters(DynPinId);
 
 // [`DynRegisters`] takes ownership of the [`DynPinId`], and [`DynPin`]
@@ -392,11 +393,15 @@ impl DynPin {
     ///  - Delay 2: 2
     ///  - Delay 1 + Delay 2: 3
     #[inline]
-    pub fn delay(self, delay_1: bool, delay_2: bool) -> Result<Self, InvalidPinTypeError> {
+    pub fn configure_delay(
+        &mut self,
+        delay_1: bool,
+        delay_2: bool,
+    ) -> Result<(), InvalidPinTypeError> {
         match self.mode {
             DynPinMode::Output(_) => {
-                self.regs.delay(delay_1, delay_2);
-                Ok(self)
+                self.regs.configure_delay(delay_1, delay_2);
+                Ok(())
             }
             _ => Err(InvalidPinTypeError(self.mode)),
         }
@@ -406,7 +411,7 @@ impl DynPin {
     /// When configured for pulse mode, a given pin will set the non-default state for exactly
     /// one clock cycle before returning to the configured default state
     #[inline]
-    pub fn pulse_mode(
+    pub fn configure_pulse_mode(
         &mut self,
         enable: bool,
         default_state: PinState,
@@ -422,14 +427,14 @@ impl DynPin {
 
     /// See p.37 and p.38 of the programmers guide for more information.
     #[inline]
-    pub fn filter_type(
+    pub fn configure_filter_type(
         &mut self,
         filter: FilterType,
         clksel: FilterClkSel,
     ) -> Result<(), InvalidPinTypeError> {
         match self.mode {
             DynPinMode::Input(_) => {
-                self.regs.filter_type(filter, clksel);
+                self.regs.configure_filter_type(filter, clksel);
                 Ok(())
             }
             _ => Err(InvalidPinTypeError(self.mode)),
@@ -437,7 +442,7 @@ impl DynPin {
     }
 
     #[inline]
-    pub fn interrupt_edge(
+    pub fn configure_edge_interrupt(
         &mut self,
         edge_type: InterruptEdge,
         irq_cfg: InterruptConfig,
@@ -446,7 +451,7 @@ impl DynPin {
     ) -> Result<(), InvalidPinTypeError> {
         match self.mode {
             DynPinMode::Input(_) | DynPinMode::Output(_) => {
-                self.regs.interrupt_edge(edge_type);
+                self.regs.configure_edge_interrupt(edge_type);
                 self.irq_enb(irq_cfg, syscfg, irqsel);
                 Ok(())
             }
@@ -455,7 +460,7 @@ impl DynPin {
     }
 
     #[inline]
-    pub fn interrupt_level(
+    pub fn configure_level_interrupt(
         &mut self,
         level_type: InterruptLevel,
         irq_cfg: InterruptConfig,
@@ -464,7 +469,7 @@ impl DynPin {
     ) -> Result<(), InvalidPinTypeError> {
         match self.mode {
             DynPinMode::Input(_) | DynPinMode::Output(_) => {
-                self.regs.interrupt_level(level_type);
+                self.regs.configure_level_interrupt(level_type);
                 self.irq_enb(irq_cfg, syscfg, irqsel);
                 Ok(())
             }
diff --git a/va108xx-hal/src/gpio/pin.rs b/va108xx-hal/src/gpio/pin.rs
index a02fd19..14ab13b 100644
--- a/va108xx-hal/src/gpio/pin.rs
+++ b/va108xx-hal/src/gpio/pin.rs
@@ -89,6 +89,7 @@ use paste::paste;
 //==================================================================================================
 
 #[derive(Debug, PartialEq, Eq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub enum InterruptEdge {
     HighToLow,
     LowToHigh,
@@ -96,12 +97,14 @@ pub enum InterruptEdge {
 }
 
 #[derive(Debug, PartialEq, Eq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub enum InterruptLevel {
     Low = 0,
     High = 1,
 }
 
 #[derive(Debug, PartialEq, Eq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub enum PinState {
     Low = 0,
     High = 1,
@@ -353,6 +356,7 @@ impl<I: PinId, M: PinMode> Pin<I, M> {
         }
     }
 
+    #[inline]
     pub fn id(&self) -> DynPinId {
         self.inner.id()
     }
@@ -482,11 +486,6 @@ impl<I: PinId, M: PinMode> Pin<I, M> {
         self.inner.regs.write_pin(false)
     }
 
-    #[inline]
-    pub(crate) fn _toggle_with_toggle_reg(&mut self) {
-        self.inner.regs.toggle();
-    }
-
     #[inline]
     pub(crate) fn _is_low(&self) -> bool {
         !self.inner.regs.read_pin()
@@ -599,7 +598,7 @@ impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
         syscfg: Option<&mut Sysconfig>,
         irqsel: Option<&mut Irqsel>,
     ) {
-        self.inner.regs.interrupt_edge(edge_type);
+        self.inner.regs.configure_edge_interrupt(edge_type);
         self.irq_enb(irq_cfg, syscfg, irqsel);
     }
 
@@ -610,7 +609,7 @@ impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
         syscfg: Option<&mut Sysconfig>,
         irqsel: Option<&mut Irqsel>,
     ) {
-        self.inner.regs.interrupt_level(level_type);
+        self.inner.regs.configure_level_interrupt(level_type);
         self.irq_enb(irq_cfg, syscfg, irqsel);
     }
 }
@@ -622,23 +621,34 @@ impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
     ///  - Delay 2: 2
     ///  - Delay 1 + Delay 2: 3
     #[inline]
-    pub fn delay(self, delay_1: bool, delay_2: bool) -> Self {
-        self.inner.regs.delay(delay_1, delay_2);
-        self
+    pub fn configure_delay(&mut self, delay_1: bool, delay_2: bool) {
+        self.inner.regs.configure_delay(delay_1, delay_2);
     }
 
     #[inline]
     pub fn toggle_with_toggle_reg(&mut self) {
-        self._toggle_with_toggle_reg()
+        self.inner.regs.toggle()
+    }
+
+    #[deprecated(
+        since = "0.9.0",
+        note = "Please use the `configure_pulse_mode` method instead"
+    )]
+    pub fn pulse_mode(&mut self, enable: bool, default_state: PinState) {
+        self.configure_pulse_mode(enable, default_state);
     }
 
     /// See p.52 of the programmers guide for more information.
     /// When configured for pulse mode, a given pin will set the non-default state for exactly
     /// one clock cycle before returning to the configured default state
-    pub fn pulse_mode(&mut self, enable: bool, default_state: PinState) {
+    pub fn configure_pulse_mode(&mut self, enable: bool, default_state: PinState) {
         self.inner.regs.pulse_mode(enable, default_state);
     }
 
+    #[deprecated(
+        since = "0.9.0",
+        note = "Please use the `configure_edge_interrupt` method instead"
+    )]
     pub fn interrupt_edge(
         &mut self,
         edge_type: InterruptEdge,
@@ -646,18 +656,43 @@ impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
         syscfg: Option<&mut Sysconfig>,
         irqsel: Option<&mut Irqsel>,
     ) {
-        self.inner.regs.interrupt_edge(edge_type);
+        self.inner.regs.configure_edge_interrupt(edge_type);
         self.irq_enb(irq_cfg, syscfg, irqsel);
     }
 
-    pub fn interrupt_level(
+    pub fn configure_edge_interrupt(
+        &mut self,
+        edge_type: InterruptEdge,
+        irq_cfg: InterruptConfig,
+        syscfg: Option<&mut Sysconfig>,
+        irqsel: Option<&mut Irqsel>,
+    ) {
+        self.inner.regs.configure_edge_interrupt(edge_type);
+        self.irq_enb(irq_cfg, syscfg, irqsel);
+    }
+
+    #[deprecated(
+        since = "0.9.0",
+        note = "Please use the `configure_level_interrupt` method instead"
+    )]
+    pub fn level_interrupt(
         &mut self,
         level_type: InterruptLevel,
         irq_cfg: InterruptConfig,
         syscfg: Option<&mut Sysconfig>,
         irqsel: Option<&mut Irqsel>,
     ) {
-        self.inner.regs.interrupt_level(level_type);
+        self.configure_level_interrupt(level_type, irq_cfg, syscfg, irqsel);
+    }
+
+    pub fn configure_level_interrupt(
+        &mut self,
+        level_type: InterruptLevel,
+        irq_cfg: InterruptConfig,
+        syscfg: Option<&mut Sysconfig>,
+        irqsel: Option<&mut Irqsel>,
+    ) {
+        self.inner.regs.configure_level_interrupt(level_type);
         self.irq_enb(irq_cfg, syscfg, irqsel);
     }
 }
@@ -666,7 +701,7 @@ impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
     /// See p.37 and p.38 of the programmers guide for more information.
     #[inline]
     pub fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
-        self.inner.regs.filter_type(filter, clksel);
+        self.inner.regs.configure_filter_type(filter, clksel);
     }
 }
 
diff --git a/va108xx-hal/src/gpio/reg.rs b/va108xx-hal/src/gpio/reg.rs
index 55ec595..d8d4993 100644
--- a/va108xx-hal/src/gpio/reg.rs
+++ b/va108xx-hal/src/gpio/reg.rs
@@ -240,7 +240,7 @@ pub(super) unsafe trait RegisterInterface {
     /// Only useful for interrupt pins. Configure whether to use edges or level as interrupt soure
     /// When using edge mode, it is possible to generate interrupts on both edges as well
     #[inline]
-    fn interrupt_edge(&mut self, edge_type: InterruptEdge) {
+    fn configure_edge_interrupt(&mut self, edge_type: InterruptEdge) {
         unsafe {
             self.port_reg()
                 .irq_sen()
@@ -267,7 +267,7 @@ pub(super) unsafe trait RegisterInterface {
 
     /// Configure which edge or level type triggers an interrupt
     #[inline]
-    fn interrupt_level(&mut self, level: InterruptLevel) {
+    fn configure_level_interrupt(&mut self, level: InterruptLevel) {
         unsafe {
             self.port_reg()
                 .irq_sen()
@@ -286,7 +286,7 @@ pub(super) unsafe trait RegisterInterface {
 
     /// Only useful for input pins
     #[inline]
-    fn filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
+    fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
         self.iocfg_port().modify(|_, w| {
             // Safety: Only write to register for this Pin ID
             unsafe {
@@ -349,7 +349,7 @@ pub(super) unsafe trait RegisterInterface {
     }
 
     /// Only useful for output pins
-    fn delay(&self, delay_1: bool, delay_2: bool) {
+    fn configure_delay(&mut self, delay_1: bool, delay_2: bool) {
         let portreg = self.port_reg();
         unsafe {
             if delay_1 {
diff --git a/va108xx-hal/src/i2c.rs b/va108xx-hal/src/i2c.rs
index e33e93f..4ed9373 100644
--- a/va108xx-hal/src/i2c.rs
+++ b/va108xx-hal/src/i2c.rs
@@ -36,8 +36,6 @@ pub struct InvalidTimingParamsError;
 #[derive(Debug, PartialEq, Eq, thiserror::Error)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub enum Error {
-    //#[error("Invalid timing parameters")]
-    //InvalidTimingParams,
     #[error("arbitration lost")]
     ArbitrationLost,
     #[error("nack address")]
@@ -82,6 +80,7 @@ impl embedded_hal::i2c::Error for Error {
 }
 
 #[derive(Debug, PartialEq, Copy, Clone)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 enum I2cCmd {
     Start = 0b00,
     Stop = 0b10,
@@ -252,6 +251,8 @@ impl Default for MasterConfig {
 
 impl Sealed for MasterConfig {}
 
+#[derive(Debug)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub struct SlaveConfig {
     pub tx_fe_mode: FifoEmptyMode,
     pub rx_fe_mode: FifoEmptyMode,
@@ -455,13 +456,6 @@ impl<I2c: Instance> I2cBase<I2c> {
     }
 }
 
-// Unique mode to use the loopback functionality
-// pub struct I2cLoopback<I2C> {
-//     i2c_base: I2cBase<I2C>,
-//     master_cfg: MasterConfig,
-//     slave_cfg: SlaveConfig,
-// }
-
 //==================================================================================================
 // I2C Master
 //==================================================================================================
@@ -673,275 +667,6 @@ impl<I2c: Instance, Addr> I2cMaster<I2c, Addr> {
     }
 }
 
-/*
-macro_rules! i2c_master {
-    ($($I2CX:path: ($i2cx:ident, $clk_enb:path),)+) => {
-        $(
-            impl<ADDR> I2cMaster<$I2CX, ADDR> {
-                pub fn $i2cx(
-                    i2c: $I2CX,
-                    cfg: MasterConfig,
-                    sys_clk: impl Into<Hertz> + Copy,
-                    speed_mode: I2cSpeed,
-                    sys_cfg: Option<&mut pac::Sysconfig>,
-                ) -> Self {
-                    I2cMaster {
-                        i2c_base: I2cBase::$i2cx(
-                            i2c,
-                            sys_clk,
-                            speed_mode,
-                            Some(&cfg),
-                            None,
-                            sys_cfg
-                        ),
-                        _addr: PhantomData,
-                    }
-                    .enable_master()
-                }
-
-                #[inline]
-                pub fn cancel_transfer(&self) {
-                    self.i2c_base
-                        .i2c
-                        .cmd()
-                        .write(|w| unsafe { w.bits(I2cCmd::Cancel as u32) });
-                }
-
-                #[inline]
-                pub fn clear_tx_fifo(&self) {
-                    self.i2c_base.i2c.fifo_clr().write(|w| w.txfifo().set_bit());
-                }
-
-                #[inline]
-                pub fn clear_rx_fifo(&self) {
-                    self.i2c_base.i2c.fifo_clr().write(|w| w.rxfifo().set_bit());
-                }
-
-                #[inline]
-                pub fn enable_master(self) -> Self {
-                    self.i2c_base.i2c.ctrl().modify(|_, w| w.enable().set_bit());
-                    self
-                }
-
-                #[inline]
-                pub fn disable_master(self) -> Self {
-                    self.i2c_base.i2c.ctrl().modify(|_, w| w.enable().clear_bit());
-                    self
-                }
-
-                #[inline(always)]
-                fn load_fifo(&self, word: u8) {
-                    self.i2c_base
-                        .i2c
-                        .data()
-                        .write(|w| unsafe { w.bits(word as u32) });
-                }
-
-                #[inline(always)]
-                fn read_fifo(&self) -> u8 {
-                    self.i2c_base.i2c.data().read().bits() as u8
-                }
-
-                fn error_handler_write(&mut self, init_cmd: &I2cCmd) {
-                    self.clear_tx_fifo();
-                    if *init_cmd == I2cCmd::Start {
-                        self.i2c_base.stop_cmd()
-                    }
-                }
-
-                fn write_base(
-                    &mut self,
-                    addr: I2cAddress,
-                    init_cmd: I2cCmd,
-                    bytes: impl IntoIterator<Item = u8>,
-                ) -> Result<(), Error> {
-                    let mut iter = bytes.into_iter();
-                    // Load address
-                    let (addr, addr_mode_bit) = I2cBase::<$I2CX>::unwrap_addr(addr);
-                    self.i2c_base.i2c.address().write(|w| unsafe {
-                        w.bits(I2cDirection::Send as u32 | (addr << 1) as u32 | addr_mode_bit)
-                    });
-
-                    self.i2c_base
-                        .i2c
-                        .cmd()
-                        .write(|w| unsafe { w.bits(init_cmd as u32) });
-                    let mut load_if_next_available = || {
-                        if let Some(next_byte) = iter.next() {
-                            self.load_fifo(next_byte);
-                        }
-                    };
-                    loop {
-                        let status_reader = self.i2c_base.i2c.status().read();
-                        if status_reader.arblost().bit_is_set() {
-                            self.error_handler_write(&init_cmd);
-                            return Err(Error::ArbitrationLost);
-                        } else if status_reader.nackaddr().bit_is_set() {
-                            self.error_handler_write(&init_cmd);
-                            return Err(Error::NackAddr);
-                        } else if status_reader.nackdata().bit_is_set() {
-                            self.error_handler_write(&init_cmd);
-                            return Err(Error::NackData);
-                        } else if status_reader.idle().bit_is_set() {
-                            return Ok(());
-                        } else {
-                            while !status_reader.txnfull().bit_is_set() {
-                                load_if_next_available();
-                            }
-                        }
-                    }
-                }
-
-                fn write_from_buffer(
-                    &mut self,
-                    init_cmd: I2cCmd,
-                    addr: I2cAddress,
-                    output: &[u8],
-                ) -> Result<(), Error> {
-                    let len = output.len();
-                    // It should theoretically possible to transfer larger data sizes by tracking
-                    // the number of sent words and setting it to 0x7fe as soon as only that many
-                    // bytes are remaining. However, large transfer like this are not common. This
-                    // feature will therefore not be supported for now.
-                    if len > 0x7fe {
-                        return Err(Error::DataTooLarge);
-                    }
-                    // Load number of words
-                    self.i2c_base
-                        .i2c
-                        .words()
-                        .write(|w| unsafe { w.bits(len as u32) });
-                    let mut bytes = output.iter();
-                    // FIFO has a depth of 16. We load slightly above the trigger level
-                    // but not all of it because the transaction might fail immediately
-                    const FILL_DEPTH: usize = 12;
-
-                    // load the FIFO
-                    for _ in 0..core::cmp::min(FILL_DEPTH, len) {
-                        self.load_fifo(*bytes.next().unwrap());
-                    }
-
-                    self.write_base(addr, init_cmd, output.iter().cloned())
-                }
-
-                fn read_internal(&mut self, addr: I2cAddress, buffer: &mut [u8]) -> Result<(), Error> {
-                    let len = buffer.len();
-                    // It should theoretically possible to transfer larger data sizes by tracking
-                    // the number of sent words and setting it to 0x7fe as soon as only that many
-                    // bytes are remaining. However, large transfer like this are not common. This
-                    // feature will therefore not be supported for now.
-                    if len > 0x7fe {
-                        return Err(Error::DataTooLarge);
-                    }
-                    // Clear the receive FIFO
-                    self.clear_rx_fifo();
-
-                    // Load number of words
-                    self.i2c_base
-                        .i2c
-                        .words()
-                        .write(|w| unsafe { w.bits(len as u32) });
-                    let (addr, addr_mode_bit) = match addr {
-                        I2cAddress::Regular(addr) => (addr as u16, 0 << 15),
-                        I2cAddress::TenBit(addr) => (addr, 1 << 15),
-                    };
-                    // Load address
-                    self.i2c_base.i2c.address().write(|w| unsafe {
-                        w.bits(I2cDirection::Read as u32 | (addr << 1) as u32 | addr_mode_bit)
-                    });
-
-                    let mut buf_iter = buffer.iter_mut();
-                    let mut read_bytes = 0;
-                    // Start receive transfer
-                    self.i2c_base
-                        .i2c
-                        .cmd()
-                        .write(|w| unsafe { w.bits(I2cCmd::StartWithStop as u32) });
-                    let mut read_if_next_available = || {
-                        if let Some(next_byte) = buf_iter.next() {
-                            *next_byte = self.read_fifo();
-                        }
-                    };
-                    loop {
-                        let status_reader = self.i2c_base.i2c.status().read();
-                        if status_reader.arblost().bit_is_set() {
-                            self.clear_rx_fifo();
-                            return Err(Error::ArbitrationLost);
-                        } else if status_reader.nackaddr().bit_is_set() {
-                            self.clear_rx_fifo();
-                            return Err(Error::NackAddr);
-                        } else if status_reader.idle().bit_is_set() {
-                            if read_bytes != len {
-                                return Err(Error::InsufficientDataReceived);
-                            }
-                            return Ok(());
-                        } else if status_reader.rxnempty().bit_is_set() {
-                            read_if_next_available();
-                            read_bytes += 1;
-                        }
-                    }
-                }
-            }
-
-            //======================================================================================
-            // Embedded HAL I2C implementations
-            //======================================================================================
-
-            impl embedded_hal::i2c::ErrorType for I2cMaster<$I2CX, SevenBitAddress> {
-                type Error = Error;
-            }
-            impl embedded_hal::i2c::I2c for I2cMaster<$I2CX, SevenBitAddress> {
-                fn transaction(
-                    &mut self,
-                    address: SevenBitAddress,
-                    operations: &mut [Operation<'_>],
-                ) -> Result<(), Self::Error> {
-                    for operation in operations {
-                        match operation {
-                            Operation::Read(buf) => self.read_internal(I2cAddress::Regular(address), buf)?,
-                            Operation::Write(buf) => self.write_from_buffer(
-                                I2cCmd::StartWithStop,
-                                I2cAddress::Regular(address),
-                                buf,
-                            )?,
-                        }
-                    }
-                    Ok(())
-                }
-            }
-
-            impl embedded_hal::i2c::ErrorType for I2cMaster<$I2CX, TenBitAddress> {
-                type Error = Error;
-            }
-            impl embedded_hal::i2c::I2c<TenBitAddress> for I2cMaster<$I2CX, TenBitAddress> {
-                fn transaction(
-                    &mut self,
-                    address: TenBitAddress,
-                    operations: &mut [Operation<'_>],
-                ) -> Result<(), Self::Error> {
-                    for operation in operations {
-                        match operation {
-                            Operation::Read(buf) => self.read_internal(I2cAddress::TenBit(address), buf)?,
-                            Operation::Write(buf) => self.write_from_buffer(
-                                I2cCmd::StartWithStop,
-                                I2cAddress::TenBit(address),
-                                buf,
-                            )?,
-                        }
-                    }
-                    Ok(())
-                }
-            }
-        )+
-    }
-}
-
-i2c_master!(
-    pac::I2ca: (i2ca, PeripheralClocks::I2c0),
-    pac::I2cb: (i2cb, PeripheralClocks::I2c1),
-);
-*/
-
 //======================================================================================
 // Embedded HAL I2C implementations
 //======================================================================================
diff --git a/va108xx-hal/src/lib.rs b/va108xx-hal/src/lib.rs
index 9da8768..b146c77 100644
--- a/va108xx-hal/src/lib.rs
+++ b/va108xx-hal/src/lib.rs
@@ -31,7 +31,7 @@ pub enum PortSel {
     PortB,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub enum PeripheralSelect {
     PortA = 0,
@@ -54,6 +54,7 @@ pub enum PeripheralSelect {
 /// Cortex-M0 NVIC. Both are generally necessary for IRQs to work, but the user might want to
 /// perform those steps themselves.
 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub struct InterruptConfig {
     /// Interrupt target vector. Should always be set, might be required for disabling IRQs
     pub id: pac::Interrupt,
diff --git a/va108xx-hal/src/spi.rs b/va108xx-hal/src/spi.rs
index 48052ef..b213a7f 100644
--- a/va108xx-hal/src/spi.rs
+++ b/va108xx-hal/src/spi.rs
@@ -33,6 +33,7 @@ use embedded_hal::spi::{Mode, MODE_0};
 const FILL_DEPTH: usize = 12;
 
 pub const BMSTART_BMSTOP_MASK: u32 = 1 << 31;
+pub const BMSKIPDATA_MASK: u32 = 1 << 30;
 
 pub const DEFAULT_CLK_DIV: u16 = 2;
 
@@ -288,6 +289,7 @@ pub trait TransferConfigProvider {
 /// This struct contains all configuration parameter which are transfer specific
 /// and might change for transfers to different SPI slaves
 #[derive(Copy, Clone, Debug)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub struct TransferConfigWithHwcs<HwCs> {
     pub hw_cs: Option<HwCs>,
     pub cfg: TransferConfig,
@@ -296,6 +298,7 @@ pub struct TransferConfigWithHwcs<HwCs> {
 /// Type erased variant of the transfer configuration. This is required to avoid generics in
 /// the SPI constructor.
 #[derive(Copy, Clone, Debug)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub struct TransferConfig {
     pub clk_cfg: Option<SpiClkConfig>,
     pub mode: Option<Mode>,
@@ -383,6 +386,8 @@ impl<HwCs: HwCsProvider> TransferConfigProvider for TransferConfigWithHwcs<HwCs>
 }
 
 /// Configuration options for the whole SPI bus. See Programmer Guide p.92 for more details
+#[derive(Debug)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub struct SpiConfig {
     clk: SpiClkConfig,
     // SPI mode configuration
@@ -532,6 +537,7 @@ pub struct Spi<SpiInstance, Pins, Word = u8> {
     pins: Pins,
 }
 
+#[inline(always)]
 pub fn mode_to_cpo_cph_bit(mode: embedded_hal::spi::Mode) -> (bool, bool) {
     match mode {
         embedded_hal::spi::MODE_0 => (false, false),
@@ -575,6 +581,7 @@ impl SpiClkConfig {
 }
 
 #[derive(Debug, thiserror::Error)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub enum SpiClkConfigError {
     #[error("division by zero")]
     DivIsZero,