From 0febc24de73f8cf2bd0e3a7e7409f19aeaf00b1c Mon Sep 17 00:00:00 2001
From: Karun <karun@nautilusdefense.com>
Date: Mon, 22 Apr 2024 10:22:04 -0400
Subject: [PATCH 01/14] Initial fill out of driver without IO considerations

---
 embassy-stm32/build.rs         |  32 +++
 embassy-stm32/src/lib.rs       |   2 +
 embassy-stm32/src/tsc/enums.rs | 100 +++++++++
 embassy-stm32/src/tsc/mod.rs   | 357 +++++++++++++++++++++++++++++++++
 4 files changed, 491 insertions(+)
 create mode 100644 embassy-stm32/src/tsc/enums.rs
 create mode 100644 embassy-stm32/src/tsc/mod.rs

diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index ba118f338..a84af258e 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -1030,6 +1030,38 @@ fn main() {
         (("octospi", "NCS"), quote!(crate::ospi::NSSPin)),
         (("octospi", "CLK"), quote!(crate::ospi::SckPin)),
         (("octospi", "NCLK"), quote!(crate::ospi::NckPin)),
+        (("tsc", "G1_IO1"), quote!(crate::ospi::G1IO1Pin)),
+        (("tsc", "G1_IO2"), quote!(crate::ospi::G1IO2Pin)),
+        (("tsc", "G1_IO3"), quote!(crate::ospi::G1IO3Pin)),
+        (("tsc", "G1_IO4"), quote!(crate::ospi::G1IO4Pin)),
+        (("tsc", "G2_IO1"), quote!(crate::ospi::G2IO1Pin)),
+        (("tsc", "G2_IO2"), quote!(crate::ospi::G2IO2Pin)),
+        (("tsc", "G2_IO3"), quote!(crate::ospi::G2IO3Pin)),
+        (("tsc", "G2_IO4"), quote!(crate::ospi::G2IO4Pin)),
+        (("tsc", "G3_IO1"), quote!(crate::ospi::G3IO1Pin)),
+        (("tsc", "G3_IO2"), quote!(crate::ospi::G3IO2Pin)),
+        (("tsc", "G3_IO3"), quote!(crate::ospi::G3IO3Pin)),
+        (("tsc", "G3_IO4"), quote!(crate::ospi::G3IO4Pin)),
+        (("tsc", "G4_IO1"), quote!(crate::ospi::G4IO1Pin)),
+        (("tsc", "G4_IO2"), quote!(crate::ospi::G4IO2Pin)),
+        (("tsc", "G4_IO3"), quote!(crate::ospi::G4IO3Pin)),
+        (("tsc", "G4_IO4"), quote!(crate::ospi::G4IO4Pin)),
+        (("tsc", "G5_IO1"), quote!(crate::ospi::G5IO1Pin)),
+        (("tsc", "G5_IO2"), quote!(crate::ospi::G5IO2Pin)),
+        (("tsc", "G5_IO3"), quote!(crate::ospi::G5IO3Pin)),
+        (("tsc", "G5_IO4"), quote!(crate::ospi::G5IO4Pin)),
+        (("tsc", "G6_IO1"), quote!(crate::ospi::G6IO1Pin)),
+        (("tsc", "G6_IO2"), quote!(crate::ospi::G6IO2Pin)),
+        (("tsc", "G6_IO3"), quote!(crate::ospi::G6IO3Pin)),
+        (("tsc", "G6_IO4"), quote!(crate::ospi::G6IO4Pin)),
+        (("tsc", "G7_IO1"), quote!(crate::ospi::G7IO1Pin)),
+        (("tsc", "G7_IO2"), quote!(crate::ospi::G7IO2Pin)),
+        (("tsc", "G7_IO3"), quote!(crate::ospi::G7IO3Pin)),
+        (("tsc", "G7_IO4"), quote!(crate::ospi::G7IO4Pin)),
+        (("tsc", "G8_IO1"), quote!(crate::ospi::G8IO1Pin)),
+        (("tsc", "G8_IO2"), quote!(crate::ospi::G8IO2Pin)),
+        (("tsc", "G8_IO3"), quote!(crate::ospi::G8IO3Pin)),
+        (("tsc", "G8_IO4"), quote!(crate::ospi::G8IO4Pin)),
     ].into();
 
     for p in METADATA.peripherals {
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 1f4e9ab1e..dd89618ef 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -103,6 +103,8 @@ pub mod sdmmc;
 pub mod spi;
 #[cfg(ucpd)]
 pub mod ucpd;
+#[cfg(tsc)]
+pub mod tsc;
 #[cfg(uid)]
 pub mod uid;
 #[cfg(usart)]
diff --git a/embassy-stm32/src/tsc/enums.rs b/embassy-stm32/src/tsc/enums.rs
new file mode 100644
index 000000000..6dfc8709c
--- /dev/null
+++ b/embassy-stm32/src/tsc/enums.rs
@@ -0,0 +1,100 @@
+/// Charge transfer pulse cycles
+#[allow(missing_docs)]
+#[derive(Copy, Clone)]
+pub enum ChargeTransferPulseCycle {
+    _1,
+    _2,
+    _3,
+    _4,
+    _5,
+    _6,
+    _7,
+    _8,
+    _9,
+    _10,
+    _11,
+    _12,
+    _13,
+    _14,
+    _15,
+    _16,
+}
+
+impl Into<u8> for ChargeTransferPulseCycle {
+    fn into(self) -> u8 {
+        match self {
+            ChargeTransferPulseCycle::_1 => 0,
+            ChargeTransferPulseCycle::_2 => 1,
+            ChargeTransferPulseCycle::_3 => 2,
+            ChargeTransferPulseCycle::_4 => 3,
+            ChargeTransferPulseCycle::_5 => 4,
+            ChargeTransferPulseCycle::_6 => 5,
+            ChargeTransferPulseCycle::_7 => 6,
+            ChargeTransferPulseCycle::_8 => 7,
+            ChargeTransferPulseCycle::_9 => 8,
+            ChargeTransferPulseCycle::_10 => 9,
+            ChargeTransferPulseCycle::_11 => 10,
+            ChargeTransferPulseCycle::_12 => 11,
+            ChargeTransferPulseCycle::_13 => 12,
+            ChargeTransferPulseCycle::_14 => 13,
+            ChargeTransferPulseCycle::_15 => 14,
+            ChargeTransferPulseCycle::_16 => 15,
+        }
+    }
+}
+
+/// Prescaler divider
+#[allow(missing_docs)]
+#[derive(Copy, Clone)]
+pub enum PGPrescalerDivider {
+    _1,
+    _2,
+    _4,
+    _8,
+    _16,
+    _32,
+    _64,
+    _128,
+}
+
+impl Into<u8> for PGPrescalerDivider {
+    fn into(self) -> u8 {
+        match self {
+            PGPrescalerDivider::_1 => 0,
+            PGPrescalerDivider::_2 => 1,
+            PGPrescalerDivider::_4 => 2,
+            PGPrescalerDivider::_8 => 3,
+            PGPrescalerDivider::_16 => 4,
+            PGPrescalerDivider::_32 => 5,
+            PGPrescalerDivider::_64 => 6,
+            PGPrescalerDivider::_128 => 7,
+        }
+    }
+}
+
+/// Max count
+#[allow(missing_docs)]
+#[derive(Copy, Clone)]
+pub enum MaxCount {
+    _255,
+    _511,
+    _1023,
+    _2047,
+    _4095,
+    _8191,
+    _16383,
+}
+
+impl Into<u8> for MaxCount {
+    fn into(self) -> u8 {
+        match self {
+            MaxCount::_255 => 0,
+            MaxCount::_511 => 1,
+            MaxCount::_1023 => 2,
+            MaxCount::_2047 => 3,
+            MaxCount::_4095 => 4,
+            MaxCount::_8191 => 5,
+            MaxCount::_16383 => 6,
+        }
+    }
+}
diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
new file mode 100644
index 000000000..6bff642fa
--- /dev/null
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -0,0 +1,357 @@
+//! TSC Peripheral Interface
+
+#![macro_use]
+
+pub mod enums;
+
+use crate::gpio::AnyPin;
+use crate::{pac::tsc::Tsc as Regs, rcc::RccPeripheral};
+use crate::{peripherals, Peripheral};
+use embassy_hal_internal::{into_ref, PeripheralRef};
+
+pub use enums::*;
+
+#[derive(Debug)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum Error {
+    /// Test error for TSC
+    Test,
+}
+
+pub enum PinType {
+    Channel,
+    Sample,
+    Shield,
+}
+
+pub struct TscGroup {}
+
+pub enum State {
+    Reset,
+    Ready,
+    Busy,
+    Error,
+}
+
+pub enum GroupStatus {
+    Ongoing,
+    Complete,
+}
+
+pub enum Group {
+    One,
+    Two,
+    Three,
+    Four,
+    Five,
+    Six,
+    Seven,
+    Eight,
+}
+
+impl Into<usize> for Group {
+    fn into(self) -> usize {
+        match self {
+            Group::One => 0,
+            Group::Two => 1,
+            Group::Three => 2,
+            Group::Four => 3,
+            Group::Five => 4,
+            Group::Six => 5,
+            Group::Seven => 6,
+            Group::Eight => 7,
+        }
+    }
+}
+
+pub struct Config {
+    pub ct_pulse_high_length: ChargeTransferPulseCycle,
+    pub ct_pulse_low_length: ChargeTransferPulseCycle,
+    pub spread_spectrum: bool,
+    pub spread_spectrum_deviation: u8,
+    pub spread_spectrum_prescaler: bool,
+    pub pulse_generator_prescaler: PGPrescalerDivider,
+    pub max_count_value: u8,
+    pub io_default_mode: bool,
+    pub synchro_pin_polarity: bool,
+    pub acquisition_mode: bool,
+    pub max_count_interrupt: bool,
+    pub channel_ios: u32,
+    pub shield_ios: u32,
+    pub sampling_ios: u32,
+}
+
+pub struct TSC<'d, T: Instance> {
+    _peri: PeripheralRef<'d, T>,
+    state: State,
+    config: Config,
+}
+
+impl<'d, T: Instance> TSC<'d, T> {
+    pub fn new(peri: impl Peripheral<P = T> + 'd, config: Config) -> Self {
+        into_ref!(peri);
+
+        // Need to check valid pin configuration input
+        // Need to configure pin
+        Self::new_inner(peri, config)
+    }
+
+    fn new_inner(peri: impl Peripheral<P = T> + 'd, config: Config) -> Self {
+        into_ref!(peri);
+
+        T::enable_and_reset();
+
+        T::REGS.cr().modify(|w| {
+            w.set_tsce(true);
+            w.set_ctph(config.ct_pulse_high_length.into());
+            w.set_ctpl(config.ct_pulse_low_length.into());
+            w.set_sse(config.spread_spectrum);
+            w.set_ssd(config.spread_spectrum_deviation);
+            w.set_sspsc(config.spread_spectrum_prescaler);
+            w.set_pgpsc(config.pulse_generator_prescaler.into());
+            w.set_mcv(config.max_count_value);
+            w.set_syncpol(config.synchro_pin_polarity);
+            w.set_am(config.acquisition_mode)
+        });
+
+        // Set IO configuration
+        // Disable Schmitt trigger hysteresis on all used TSC IOs
+        // T::REGS.iohcr().modify(|w| {
+        //     w.
+        // });
+
+        // Set channel and shield IOs
+        // T::REGS.ioccr().modify(|w| {});
+
+        // Set sampling IOs
+        // T::REGS.ioscr().modify(|w| {
+        //     w.set_g1_io1(val)
+        // });
+
+        // Set the groups to be acquired
+        // T::REGS.iogcsr().modify(|w| {
+        //     w.set_g1e(val);
+        // });
+
+        // Disable interrupts
+        T::REGS.ier().modify(|w| {
+            w.set_eoaie(false);
+            w.set_mceie(false);
+        });
+
+        // Clear flags
+        T::REGS.icr().modify(|w| {
+            w.set_eoaic(true);
+            w.set_mceic(true);
+        });
+
+        Self {
+            _peri: peri,
+            state: State::Ready,
+            config,
+        }
+    }
+
+    pub fn start(&mut self) {
+        self.state = State::Busy;
+
+        // Disable interrupts
+        T::REGS.ier().modify(|w| {
+            w.set_eoaie(false);
+            w.set_mceie(false);
+        });
+
+        // Clear flags
+        T::REGS.icr().modify(|w| {
+            w.set_eoaic(true);
+            w.set_mceic(true);
+        });
+
+        // Set the touch sensing IOs not acquired to the default mode
+        T::REGS.cr().modify(|w| {
+            w.set_iodef(self.config.io_default_mode);
+        });
+
+        // Start the acquisition
+        T::REGS.cr().modify(|w| {
+            w.set_start(true);
+        });
+    }
+
+    pub fn start_it(&mut self) {
+        self.state = State::Busy;
+
+        // Enable interrupts
+        T::REGS.ier().modify(|w| {
+            w.set_eoaie(true);
+            w.set_mceie(self.config.max_count_interrupt);
+        });
+
+        // Clear flags
+        T::REGS.icr().modify(|w| {
+            w.set_eoaic(true);
+            w.set_mceic(true);
+        });
+
+        // Set the touch sensing IOs not acquired to the default mode
+        T::REGS.cr().modify(|w| {
+            w.set_iodef(self.config.io_default_mode);
+        });
+
+        // Start the acquisition
+        T::REGS.cr().modify(|w| {
+            w.set_start(true);
+        });
+    }
+
+    pub fn stop(&mut self) {
+        T::REGS.cr().modify(|w| {
+            w.set_start(false);
+        });
+
+        // Set the touch sensing IOs in low power mode
+        T::REGS.cr().modify(|w| {
+            w.set_iodef(false);
+        });
+
+        // Clear flags
+        T::REGS.icr().modify(|w| {
+            w.set_eoaic(true);
+            w.set_mceic(true);
+        });
+
+        self.state = State::Ready;
+    }
+
+    pub fn stop_it(&mut self) {
+        T::REGS.cr().modify(|w| {
+            w.set_start(false);
+        });
+
+        // Set the touch sensing IOs in low power mode
+        T::REGS.cr().modify(|w| {
+            w.set_iodef(false);
+        });
+
+        // Disable interrupts
+        T::REGS.ier().modify(|w| {
+            w.set_eoaie(false);
+            w.set_mceie(false);
+        });
+
+        // Clear flags
+        T::REGS.icr().modify(|w| {
+            w.set_eoaic(true);
+            w.set_mceic(true);
+        });
+
+        self.state = State::Ready;
+    }
+
+    pub fn poll_for_acquisition(&mut self) {
+        while self.get_state() == State::Busy {}
+    }
+
+    pub fn get_state(&mut self) -> State {
+        if self.state == State::Busy {
+            if T::REGS.isr().read().eoaf() {
+                if T::REGS.isr().read().mcef() {
+                    self.state = State::Error
+                } else {
+                    self.state = State::Ready
+                }
+            }
+        }
+        self.state
+    }
+
+    pub fn group_get_status(&mut self, index: Group) -> GroupStatus {
+        // Status bits are set by hardware when the acquisition on the corresponding
+        // enabled analog IO group is complete, cleared when new acquisition is started
+        let status = match index {
+            Group::One => T::REGS.iogcsr().read().g1s(),
+            Group::Two => T::REGS.iogcsr().read().g2s(),
+            Group::Three => T::REGS.iogcsr().read().g3s(),
+            Group::Four => T::REGS.iogcsr().read().g4s(),
+            Group::Five => T::REGS.iogcsr().read().g5s(),
+            Group::Six => T::REGS.iogcsr().read().g6s(),
+            Group::Seven => T::REGS.iogcsr().read().g7s(),
+            Group::Eight => T::REGS.iogcsr().read().g8s(),
+        };
+        match status {
+            true => GroupStatus::Complete,
+            false => GroupStatus::Ongoing,
+        }
+    }
+
+    pub fn group_get_value(&mut self, index: Group) -> u16 {
+        T::REGS.iogcr(index.into()).read().cnt()
+    }
+
+    // pub fn configure_io()
+
+    pub fn discharge_io(&mut self, status: bool) {
+        // Set the touch sensing IOs in low power mode
+        T::REGS.cr().modify(|w| {
+            w.set_iodef(!status);
+        });
+    }
+}
+
+impl<'d, T: Instance> Drop for TSC<'d, T> {
+    fn drop(&mut self) {
+        //  Need to figure out what to do with the IOs
+        T::disable();
+    }
+}
+
+pub(crate) trait SealedInstance {
+    const REGS: Regs;
+}
+
+/// TSC instance trait
+#[allow(private_bounds)]
+pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {}
+
+foreach_peripheral!(
+    (tsc, $inst:ident) => {
+        impl SealedInstance for peripherals::$inst {
+            const REGS: Regs = crate::pac::$inst;
+        }
+
+        impl Instance for peripherals::$inst {}
+    };
+);
+
+pin_trait!(G1IO1Pin, Instance);
+pin_trait!(G1IO2Pin, Instance);
+pin_trait!(G1IO3Pin, Instance);
+pin_trait!(G1IO4Pin, Instance);
+pin_trait!(G2IO1Pin, Instance);
+pin_trait!(G2IO2Pin, Instance);
+pin_trait!(G2IO3Pin, Instance);
+pin_trait!(G2IO4Pin, Instance);
+pin_trait!(G3IO1Pin, Instance);
+pin_trait!(G3IO2Pin, Instance);
+pin_trait!(G3IO3Pin, Instance);
+pin_trait!(G3IO4Pin, Instance);
+pin_trait!(G4IO1Pin, Instance);
+pin_trait!(G4IO2Pin, Instance);
+pin_trait!(G4IO3Pin, Instance);
+pin_trait!(G4IO4Pin, Instance);
+pin_trait!(G5IO1Pin, Instance);
+pin_trait!(G5IO2Pin, Instance);
+pin_trait!(G5IO3Pin, Instance);
+pin_trait!(G5IO4Pin, Instance);
+pin_trait!(G6IO1Pin, Instance);
+pin_trait!(G6IO2Pin, Instance);
+pin_trait!(G6IO3Pin, Instance);
+pin_trait!(G6IO4Pin, Instance);
+pin_trait!(G7IO1Pin, Instance);
+pin_trait!(G7IO2Pin, Instance);
+pin_trait!(G7IO3Pin, Instance);
+pin_trait!(G7IO4Pin, Instance);
+pin_trait!(G8IO1Pin, Instance);
+pin_trait!(G8IO2Pin, Instance);
+pin_trait!(G8IO3Pin, Instance);
+pin_trait!(G8IO4Pin, Instance);

From bef76ee05744077cf9a14df23947eb6de4a8346d Mon Sep 17 00:00:00 2001
From: Karun <karun@nautilusdefense.com>
Date: Wed, 17 Apr 2024 12:58:45 -0400
Subject: [PATCH 02/14] initial set of io changes

---
 embassy-stm32/src/tsc/mod.rs | 73 +++++++++++++++++++++++++++++++++++-
 1 file changed, 71 insertions(+), 2 deletions(-)

diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
index 6bff642fa..1a8aabbc6 100644
--- a/embassy-stm32/src/tsc/mod.rs
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -81,14 +81,81 @@ pub struct Config {
     pub sampling_ios: u32,
 }
 
+pub struct TscPin<'d, T> {
+    pin: PeripheralRef<'d, AnyPin>,
+    role: PinType,
+}
+
+pub struct PinGroup<'d, A, B, C, D> {
+    d1: Option<TscPin<'d, A>>,
+    d2: Option<TscPin<'d, B>>,
+    d3: Option<TscPin<'d, C>>,
+    d4: Option<TscPin<'d, D>>,
+}
+
 pub struct TSC<'d, T: Instance> {
     _peri: PeripheralRef<'d, T>,
+    g1: Option<PinGroup<'d, AnyPin, AnyPin, AnyPin, AnyPin>>,
+    g2: Option<PinGroup<'d, AnyPin, AnyPin, AnyPin, AnyPin>>,
+    g3: Option<PinGroup<'d, AnyPin, AnyPin, AnyPin, AnyPin>>,
+    g4: Option<PinGroup<'d, AnyPin, AnyPin, AnyPin, AnyPin>>,
+    g5: Option<PinGroup<'d, AnyPin, AnyPin, AnyPin, AnyPin>>,
+    g6: Option<PinGroup<'d, AnyPin, AnyPin, AnyPin, AnyPin>>,
+    g7: Option<PinGroup<'d, AnyPin, AnyPin, AnyPin, AnyPin>>,
+    g8: Option<PinGroup<'d, AnyPin, AnyPin, AnyPin, AnyPin>>,
     state: State,
     config: Config,
 }
 
 impl<'d, T: Instance> TSC<'d, T> {
-    pub fn new(peri: impl Peripheral<P = T> + 'd, config: Config) -> Self {
+    pub fn new(
+        peri: impl Peripheral<P = T> + 'd,
+        g1: Option<
+            PinGroup<
+                'd,
+                impl Peripheral<P = impl G1IO1Pin<T>> + 'd,
+                impl Peripheral<P = impl G1IO2Pin<T>> + 'd,
+                impl Peripheral<P = impl G1IO3Pin<T>> + 'd,
+                impl Peripheral<P = impl G1IO4Pin<T>> + 'd,
+            >,
+        >,
+
+        g2_d1: Option<impl Peripheral<P = impl G2IO1Pin<T>> + 'd>,
+        g2_d2: Option<impl Peripheral<P = impl G2IO2Pin<T>> + 'd>,
+        g2_d3: Option<impl Peripheral<P = impl G2IO3Pin<T>> + 'd>,
+        g2_d4: Option<impl Peripheral<P = impl G2IO4Pin<T>> + 'd>,
+
+        g3_d1: Option<impl Peripheral<P = impl G3IO1Pin<T>> + 'd>,
+        g3_d2: Option<impl Peripheral<P = impl G3IO2Pin<T>> + 'd>,
+        g3_d3: Option<impl Peripheral<P = impl G3IO3Pin<T>> + 'd>,
+        g3_d4: Option<impl Peripheral<P = impl G3IO4Pin<T>> + 'd>,
+
+        g4_d1: Option<impl Peripheral<P = impl G4IO1Pin<T>> + 'd>,
+        g4_d2: Option<impl Peripheral<P = impl G4IO2Pin<T>> + 'd>,
+        g4_d3: Option<impl Peripheral<P = impl G4IO3Pin<T>> + 'd>,
+        g4_d4: Option<impl Peripheral<P = impl G4IO4Pin<T>> + 'd>,
+
+        g5_d1: Option<impl Peripheral<P = impl G5IO1Pin<T>> + 'd>,
+        g5_d2: Option<impl Peripheral<P = impl G5IO2Pin<T>> + 'd>,
+        g5_d3: Option<impl Peripheral<P = impl G5IO3Pin<T>> + 'd>,
+        g5_d4: Option<impl Peripheral<P = impl G5IO4Pin<T>> + 'd>,
+
+        g6_d1: Option<impl Peripheral<P = impl G6IO1Pin<T>> + 'd>,
+        g6_d2: Option<impl Peripheral<P = impl G6IO2Pin<T>> + 'd>,
+        g6_d3: Option<impl Peripheral<P = impl G6IO3Pin<T>> + 'd>,
+        g6_d4: Option<impl Peripheral<P = impl G6IO4Pin<T>> + 'd>,
+
+        g7_d1: Option<impl Peripheral<P = impl G7IO1Pin<T>> + 'd>,
+        g7_d2: Option<impl Peripheral<P = impl G7IO2Pin<T>> + 'd>,
+        g7_d3: Option<impl Peripheral<P = impl G7IO3Pin<T>> + 'd>,
+        g7_d4: Option<impl Peripheral<P = impl G7IO4Pin<T>> + 'd>,
+
+        g8_d1: Option<impl Peripheral<P = impl G8IO1Pin<T>> + 'd>,
+        g8_d2: Option<impl Peripheral<P = impl G8IO2Pin<T>> + 'd>,
+        g8_d3: Option<impl Peripheral<P = impl G8IO3Pin<T>> + 'd>,
+        g8_d4: Option<impl Peripheral<P = impl G8IO4Pin<T>> + 'd>,
+        config: Config,
+    ) -> Self {
         into_ref!(peri);
 
         // Need to check valid pin configuration input
@@ -96,6 +163,8 @@ impl<'d, T: Instance> TSC<'d, T> {
         Self::new_inner(peri, config)
     }
 
+    fn filter_group() -> Result<PinGroup<'d>, ()> {}
+
     fn new_inner(peri: impl Peripheral<P = T> + 'd, config: Config) -> Self {
         into_ref!(peri);
 
@@ -111,7 +180,7 @@ impl<'d, T: Instance> TSC<'d, T> {
             w.set_pgpsc(config.pulse_generator_prescaler.into());
             w.set_mcv(config.max_count_value);
             w.set_syncpol(config.synchro_pin_polarity);
-            w.set_am(config.acquisition_mode)
+            w.set_am(config.acquisition_mode);
         });
 
         // Set IO configuration

From bcd923a4b003224b67ac2a2c472730f3a05e7590 Mon Sep 17 00:00:00 2001
From: Karun <karun@nautilusdefense.com>
Date: Fri, 19 Apr 2024 11:20:04 -0400
Subject: [PATCH 03/14] fix create build pin traits

---
 embassy-stm32/build.rs | 64 +++++++++++++++++++++---------------------
 1 file changed, 32 insertions(+), 32 deletions(-)

diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index a84af258e..8b6720ae8 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -1030,38 +1030,38 @@ fn main() {
         (("octospi", "NCS"), quote!(crate::ospi::NSSPin)),
         (("octospi", "CLK"), quote!(crate::ospi::SckPin)),
         (("octospi", "NCLK"), quote!(crate::ospi::NckPin)),
-        (("tsc", "G1_IO1"), quote!(crate::ospi::G1IO1Pin)),
-        (("tsc", "G1_IO2"), quote!(crate::ospi::G1IO2Pin)),
-        (("tsc", "G1_IO3"), quote!(crate::ospi::G1IO3Pin)),
-        (("tsc", "G1_IO4"), quote!(crate::ospi::G1IO4Pin)),
-        (("tsc", "G2_IO1"), quote!(crate::ospi::G2IO1Pin)),
-        (("tsc", "G2_IO2"), quote!(crate::ospi::G2IO2Pin)),
-        (("tsc", "G2_IO3"), quote!(crate::ospi::G2IO3Pin)),
-        (("tsc", "G2_IO4"), quote!(crate::ospi::G2IO4Pin)),
-        (("tsc", "G3_IO1"), quote!(crate::ospi::G3IO1Pin)),
-        (("tsc", "G3_IO2"), quote!(crate::ospi::G3IO2Pin)),
-        (("tsc", "G3_IO3"), quote!(crate::ospi::G3IO3Pin)),
-        (("tsc", "G3_IO4"), quote!(crate::ospi::G3IO4Pin)),
-        (("tsc", "G4_IO1"), quote!(crate::ospi::G4IO1Pin)),
-        (("tsc", "G4_IO2"), quote!(crate::ospi::G4IO2Pin)),
-        (("tsc", "G4_IO3"), quote!(crate::ospi::G4IO3Pin)),
-        (("tsc", "G4_IO4"), quote!(crate::ospi::G4IO4Pin)),
-        (("tsc", "G5_IO1"), quote!(crate::ospi::G5IO1Pin)),
-        (("tsc", "G5_IO2"), quote!(crate::ospi::G5IO2Pin)),
-        (("tsc", "G5_IO3"), quote!(crate::ospi::G5IO3Pin)),
-        (("tsc", "G5_IO4"), quote!(crate::ospi::G5IO4Pin)),
-        (("tsc", "G6_IO1"), quote!(crate::ospi::G6IO1Pin)),
-        (("tsc", "G6_IO2"), quote!(crate::ospi::G6IO2Pin)),
-        (("tsc", "G6_IO3"), quote!(crate::ospi::G6IO3Pin)),
-        (("tsc", "G6_IO4"), quote!(crate::ospi::G6IO4Pin)),
-        (("tsc", "G7_IO1"), quote!(crate::ospi::G7IO1Pin)),
-        (("tsc", "G7_IO2"), quote!(crate::ospi::G7IO2Pin)),
-        (("tsc", "G7_IO3"), quote!(crate::ospi::G7IO3Pin)),
-        (("tsc", "G7_IO4"), quote!(crate::ospi::G7IO4Pin)),
-        (("tsc", "G8_IO1"), quote!(crate::ospi::G8IO1Pin)),
-        (("tsc", "G8_IO2"), quote!(crate::ospi::G8IO2Pin)),
-        (("tsc", "G8_IO3"), quote!(crate::ospi::G8IO3Pin)),
-        (("tsc", "G8_IO4"), quote!(crate::ospi::G8IO4Pin)),
+        (("tsc", "G1_IO1"), quote!(crate::tsc::G1IO1Pin)),
+        (("tsc", "G1_IO2"), quote!(crate::tsc::G1IO2Pin)),
+        (("tsc", "G1_IO3"), quote!(crate::tsc::G1IO3Pin)),
+        (("tsc", "G1_IO4"), quote!(crate::tsc::G1IO4Pin)),
+        (("tsc", "G2_IO1"), quote!(crate::tsc::G2IO1Pin)),
+        (("tsc", "G2_IO2"), quote!(crate::tsc::G2IO2Pin)),
+        (("tsc", "G2_IO3"), quote!(crate::tsc::G2IO3Pin)),
+        (("tsc", "G2_IO4"), quote!(crate::tsc::G2IO4Pin)),
+        (("tsc", "G3_IO1"), quote!(crate::tsc::G3IO1Pin)),
+        (("tsc", "G3_IO2"), quote!(crate::tsc::G3IO2Pin)),
+        (("tsc", "G3_IO3"), quote!(crate::tsc::G3IO3Pin)),
+        (("tsc", "G3_IO4"), quote!(crate::tsc::G3IO4Pin)),
+        (("tsc", "G4_IO1"), quote!(crate::tsc::G4IO1Pin)),
+        (("tsc", "G4_IO2"), quote!(crate::tsc::G4IO2Pin)),
+        (("tsc", "G4_IO3"), quote!(crate::tsc::G4IO3Pin)),
+        (("tsc", "G4_IO4"), quote!(crate::tsc::G4IO4Pin)),
+        (("tsc", "G5_IO1"), quote!(crate::tsc::G5IO1Pin)),
+        (("tsc", "G5_IO2"), quote!(crate::tsc::G5IO2Pin)),
+        (("tsc", "G5_IO3"), quote!(crate::tsc::G5IO3Pin)),
+        (("tsc", "G5_IO4"), quote!(crate::tsc::G5IO4Pin)),
+        (("tsc", "G6_IO1"), quote!(crate::tsc::G6IO1Pin)),
+        (("tsc", "G6_IO2"), quote!(crate::tsc::G6IO2Pin)),
+        (("tsc", "G6_IO3"), quote!(crate::tsc::G6IO3Pin)),
+        (("tsc", "G6_IO4"), quote!(crate::tsc::G6IO4Pin)),
+        (("tsc", "G7_IO1"), quote!(crate::tsc::G7IO1Pin)),
+        (("tsc", "G7_IO2"), quote!(crate::tsc::G7IO2Pin)),
+        (("tsc", "G7_IO3"), quote!(crate::tsc::G7IO3Pin)),
+        (("tsc", "G7_IO4"), quote!(crate::tsc::G7IO4Pin)),
+        (("tsc", "G8_IO1"), quote!(crate::tsc::G8IO1Pin)),
+        (("tsc", "G8_IO2"), quote!(crate::tsc::G8IO2Pin)),
+        (("tsc", "G8_IO3"), quote!(crate::tsc::G8IO3Pin)),
+        (("tsc", "G8_IO4"), quote!(crate::tsc::G8IO4Pin)),
     ].into();
 
     for p in METADATA.peripherals {

From 0b606b57f101b4c8081e76de86c7224763deb9e1 Mon Sep 17 00:00:00 2001
From: Karun <karun@nautilusdefense.com>
Date: Fri, 19 Apr 2024 11:20:24 -0400
Subject: [PATCH 04/14] Add crate documentation

---
 embassy-stm32/src/tsc/mod.rs | 141 +++++++++++++++++++++++++++--------
 1 file changed, 109 insertions(+), 32 deletions(-)

diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
index 1a8aabbc6..60dd734c4 100644
--- a/embassy-stm32/src/tsc/mod.rs
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -2,6 +2,7 @@
 
 #![macro_use]
 
+/// Enums defined for peripheral parameters
 pub mod enums;
 
 use crate::gpio::AnyPin;
@@ -11,6 +12,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
 
 pub use enums::*;
 
+/// Error type defined for TSC
 #[derive(Debug)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub enum Error {
@@ -18,26 +20,45 @@ pub enum Error {
     Test,
 }
 
+/// Pin type definition to control IO parameters
 pub enum PinType {
+    /// Sensing channel pin connected to an electrode
     Channel,
+    /// Sampling capacitor pin, one required for every pin group
     Sample,
+    /// Shield pin connected to capacitive sensing shield
     Shield,
 }
 
+/// Unclear
 pub struct TscGroup {}
 
+/// Peripheral state
+#[derive(PartialEq, Clone, Copy)]
 pub enum State {
+    /// Peripheral is being setup or reconfigured
     Reset,
+    /// Ready to start acquisition
     Ready,
+    /// In process of sensor acquisition
     Busy,
+    /// Error occured during acquisition
     Error,
 }
 
+/// Individual group status checked after acquisition reported as complete
+/// For groups with multiple channel pins, may take longer because acquisitions
+/// are done sequentially. Check this status before pulling count for each
+/// sampled channel
 pub enum GroupStatus {
+    /// Acquisition for channel still in progress
     Ongoing,
+    /// Acquisition either not started or complete
     Complete,
 }
 
+/// Group identifier used to interrogate status
+#[allow(missing_docs)]
 pub enum Group {
     One,
     Two,
@@ -64,61 +85,99 @@ impl Into<usize> for Group {
     }
 }
 
+/// Peripheral configuration
+#[derive(Clone, Copy)]
 pub struct Config {
+    /// Duration of high state of the charge transfer pulse
     pub ct_pulse_high_length: ChargeTransferPulseCycle,
+    /// Duration of the low state of the charge transfer pulse
     pub ct_pulse_low_length: ChargeTransferPulseCycle,
+    /// Enable/disable of spread spectrum feature
     pub spread_spectrum: bool,
+    /// Adds variable number of periods of the SS clk to pulse high state
     pub spread_spectrum_deviation: u8,
+    /// Selects AHB clock divider used to generate SS clk
     pub spread_spectrum_prescaler: bool,
+    /// Selects AHB clock divider used to generate pulse generator clk
     pub pulse_generator_prescaler: PGPrescalerDivider,
-    pub max_count_value: u8,
+    /// Maximum number of charge tranfer pulses that can be generated before error
+    pub max_count_value: MaxCount,
+    /// Defines config of all IOs when no ongoing acquisition
     pub io_default_mode: bool,
+    /// Polarity of sync input pin
     pub synchro_pin_polarity: bool,
+    /// Acquisition starts when start bit is set or with sync pin input
     pub acquisition_mode: bool,
+    /// Enable max count interrupt
     pub max_count_interrupt: bool,
-    pub channel_ios: u32,
-    pub shield_ios: u32,
-    pub sampling_ios: u32,
 }
 
+impl Default for Config {
+    fn default() -> Self {
+        Self {
+            ct_pulse_high_length: ChargeTransferPulseCycle::_1,
+            ct_pulse_low_length: ChargeTransferPulseCycle::_1,
+            spread_spectrum: false,
+            spread_spectrum_deviation: 0,
+            spread_spectrum_prescaler: false,
+            pulse_generator_prescaler: PGPrescalerDivider::_1,
+            max_count_value: MaxCount::_255,
+            io_default_mode: false,
+            synchro_pin_polarity: false,
+            acquisition_mode: false,
+            max_count_interrupt: false,
+        }
+    }
+}
+
+/// Pin struct that maintains usage
+#[allow(missing_docs)]
 pub struct TscPin<'d, T> {
-    pin: PeripheralRef<'d, AnyPin>,
+    pin: PeripheralRef<'d, T>,
     role: PinType,
 }
 
-pub struct PinGroup<'d, A, B, C, D> {
-    d1: Option<TscPin<'d, A>>,
-    d2: Option<TscPin<'d, B>>,
-    d3: Option<TscPin<'d, C>>,
-    d4: Option<TscPin<'d, D>>,
+/// Input structure for constructor containing peripherals
+#[allow(missing_docs)]
+pub struct PeriPin<T> {
+    pub pin: T,
+    pub role: PinType,
 }
 
-pub struct TSC<'d, T: Instance> {
+/// Pin group definition
+/// Pins are organized into groups of four IOs, all groups with a
+/// sampling channel must also have a sampling capacitor channel.
+#[allow(missing_docs)]
+pub struct PinGroup<'d, A> {
+    pub d1: Option<TscPin<'d, A>>,
+    pub d2: Option<TscPin<'d, A>>,
+    pub d3: Option<TscPin<'d, A>>,
+    pub d4: Option<TscPin<'d, A>>,
+}
+
+/// TSC driver
+pub struct Tsc<'d, T: Instance> {
     _peri: PeripheralRef<'d, T>,
-    g1: Option<PinGroup<'d, AnyPin, AnyPin, AnyPin, AnyPin>>,
-    g2: Option<PinGroup<'d, AnyPin, AnyPin, AnyPin, AnyPin>>,
-    g3: Option<PinGroup<'d, AnyPin, AnyPin, AnyPin, AnyPin>>,
-    g4: Option<PinGroup<'d, AnyPin, AnyPin, AnyPin, AnyPin>>,
-    g5: Option<PinGroup<'d, AnyPin, AnyPin, AnyPin, AnyPin>>,
-    g6: Option<PinGroup<'d, AnyPin, AnyPin, AnyPin, AnyPin>>,
-    g7: Option<PinGroup<'d, AnyPin, AnyPin, AnyPin, AnyPin>>,
-    g8: Option<PinGroup<'d, AnyPin, AnyPin, AnyPin, AnyPin>>,
+    g1: Option<PinGroup<'d, AnyPin>>,
+    g2: Option<PinGroup<'d, AnyPin>>,
+    g3: Option<PinGroup<'d, AnyPin>>,
+    g4: Option<PinGroup<'d, AnyPin>>,
+    g5: Option<PinGroup<'d, AnyPin>>,
+    g6: Option<PinGroup<'d, AnyPin>>,
+    g7: Option<PinGroup<'d, AnyPin>>,
+    g8: Option<PinGroup<'d, AnyPin>>,
     state: State,
     config: Config,
 }
 
-impl<'d, T: Instance> TSC<'d, T> {
+impl<'d, T: Instance> Tsc<'d, T> {
+    /// Create new TSC driver
     pub fn new(
         peri: impl Peripheral<P = T> + 'd,
-        g1: Option<
-            PinGroup<
-                'd,
-                impl Peripheral<P = impl G1IO1Pin<T>> + 'd,
-                impl Peripheral<P = impl G1IO2Pin<T>> + 'd,
-                impl Peripheral<P = impl G1IO3Pin<T>> + 'd,
-                impl Peripheral<P = impl G1IO4Pin<T>> + 'd,
-            >,
-        >,
+        // g1_d1: Option<PeriPin<impl Peripheral<P = impl G1IO1Pin<T>> + 'd>>,
+        g1_d2: Option<PeriPin<impl Peripheral<P = impl G1IO2Pin<T>> + 'd>>,
+        g1_d3: Option<PeriPin<impl Peripheral<P = impl G1IO3Pin<T>> + 'd>>,
+        g1_d4: Option<impl Peripheral<P = impl G1IO4Pin<T>> + 'd>,
 
         g2_d1: Option<impl Peripheral<P = impl G2IO1Pin<T>> + 'd>,
         g2_d2: Option<impl Peripheral<P = impl G2IO2Pin<T>> + 'd>,
@@ -154,6 +213,7 @@ impl<'d, T: Instance> TSC<'d, T> {
         g8_d2: Option<impl Peripheral<P = impl G8IO2Pin<T>> + 'd>,
         g8_d3: Option<impl Peripheral<P = impl G8IO3Pin<T>> + 'd>,
         g8_d4: Option<impl Peripheral<P = impl G8IO4Pin<T>> + 'd>,
+
         config: Config,
     ) -> Self {
         into_ref!(peri);
@@ -163,7 +223,7 @@ impl<'d, T: Instance> TSC<'d, T> {
         Self::new_inner(peri, config)
     }
 
-    fn filter_group() -> Result<PinGroup<'d>, ()> {}
+    // fn filter_group() -> Option<PinGroup<'d>> {}
 
     fn new_inner(peri: impl Peripheral<P = T> + 'd, config: Config) -> Self {
         into_ref!(peri);
@@ -178,7 +238,7 @@ impl<'d, T: Instance> TSC<'d, T> {
             w.set_ssd(config.spread_spectrum_deviation);
             w.set_sspsc(config.spread_spectrum_prescaler);
             w.set_pgpsc(config.pulse_generator_prescaler.into());
-            w.set_mcv(config.max_count_value);
+            w.set_mcv(config.max_count_value.into());
             w.set_syncpol(config.synchro_pin_polarity);
             w.set_am(config.acquisition_mode);
         });
@@ -216,11 +276,20 @@ impl<'d, T: Instance> TSC<'d, T> {
 
         Self {
             _peri: peri,
+            g1: None,
+            g2: None,
+            g3: None,
+            g4: None,
+            g5: None,
+            g6: None,
+            g7: None,
+            g8: None,
             state: State::Ready,
             config,
         }
     }
 
+    /// Start charge transfer acquisition
     pub fn start(&mut self) {
         self.state = State::Busy;
 
@@ -247,6 +316,7 @@ impl<'d, T: Instance> TSC<'d, T> {
         });
     }
 
+    /// Start charge transfer acquisition with interrupts enabled
     pub fn start_it(&mut self) {
         self.state = State::Busy;
 
@@ -273,6 +343,7 @@ impl<'d, T: Instance> TSC<'d, T> {
         });
     }
 
+    /// Stop charge transfer acquisition
     pub fn stop(&mut self) {
         T::REGS.cr().modify(|w| {
             w.set_start(false);
@@ -292,6 +363,7 @@ impl<'d, T: Instance> TSC<'d, T> {
         self.state = State::Ready;
     }
 
+    /// Stop charge transfer acquisition and clear interrupts
     pub fn stop_it(&mut self) {
         T::REGS.cr().modify(|w| {
             w.set_start(false);
@@ -317,10 +389,12 @@ impl<'d, T: Instance> TSC<'d, T> {
         self.state = State::Ready;
     }
 
+    /// Wait for end of acquisition
     pub fn poll_for_acquisition(&mut self) {
         while self.get_state() == State::Busy {}
     }
 
+    /// Get current state of acquisition
     pub fn get_state(&mut self) -> State {
         if self.state == State::Busy {
             if T::REGS.isr().read().eoaf() {
@@ -334,6 +408,7 @@ impl<'d, T: Instance> TSC<'d, T> {
         self.state
     }
 
+    /// Get the individual group status to check acquisition complete
     pub fn group_get_status(&mut self, index: Group) -> GroupStatus {
         // Status bits are set by hardware when the acquisition on the corresponding
         // enabled analog IO group is complete, cleared when new acquisition is started
@@ -353,12 +428,14 @@ impl<'d, T: Instance> TSC<'d, T> {
         }
     }
 
+    /// Get the count for the acquisiton, valid once group status is set
     pub fn group_get_value(&mut self, index: Group) -> u16 {
         T::REGS.iogcr(index.into()).read().cnt()
     }
 
     // pub fn configure_io()
 
+    /// Discharge the IOs for subsequent acquisition
     pub fn discharge_io(&mut self, status: bool) {
         // Set the touch sensing IOs in low power mode
         T::REGS.cr().modify(|w| {
@@ -367,7 +444,7 @@ impl<'d, T: Instance> TSC<'d, T> {
     }
 }
 
-impl<'d, T: Instance> Drop for TSC<'d, T> {
+impl<'d, T: Instance> Drop for Tsc<'d, T> {
     fn drop(&mut self) {
         //  Need to figure out what to do with the IOs
         T::disable();

From 87d2c66ef4be5396663f6f1724f3a15da31d0482 Mon Sep 17 00:00:00 2001
From: Karun <karun@nautilusdefense.com>
Date: Fri, 19 Apr 2024 13:33:10 -0400
Subject: [PATCH 05/14] Add io pin masking

---
 embassy-stm32/src/tsc/enums.rs |  92 +++++++++++++++++++++++++++++
 embassy-stm32/src/tsc/mod.rs   | 102 +++++++++++++++++++--------------
 2 files changed, 152 insertions(+), 42 deletions(-)

diff --git a/embassy-stm32/src/tsc/enums.rs b/embassy-stm32/src/tsc/enums.rs
index 6dfc8709c..56df4173a 100644
--- a/embassy-stm32/src/tsc/enums.rs
+++ b/embassy-stm32/src/tsc/enums.rs
@@ -1,3 +1,95 @@
+use core::ops::BitOr;
+
+/// Pin defines
+#[allow(missing_docs)]
+pub enum TscIOPin {
+    Group1Io1,
+    Group1Io2,
+    Group1Io3,
+    Group1Io4,
+    Group2Io1,
+    Group2Io2,
+    Group2Io3,
+    Group2Io4,
+    Group3Io1,
+    Group3Io2,
+    Group3Io3,
+    Group3Io4,
+    Group4Io1,
+    Group4Io2,
+    Group4Io3,
+    Group4Io4,
+    Group5Io1,
+    Group5Io2,
+    Group5Io3,
+    Group5Io4,
+    Group6Io1,
+    Group6Io2,
+    Group6Io3,
+    Group6Io4,
+    Group7Io1,
+    Group7Io2,
+    Group7Io3,
+    Group7Io4,
+    Group8Io1,
+    Group8Io2,
+    Group8Io3,
+    Group8Io4,
+}
+
+impl BitOr<TscIOPin> for u32 {
+    type Output = u32;
+    fn bitor(self, rhs: TscIOPin) -> Self::Output {
+        self | rhs as u32
+    }
+}
+
+impl BitOr for TscIOPin {
+    type Output = u32;
+    fn bitor(self, rhs: Self) -> Self::Output {
+        self as u32 | rhs as u32
+    }
+}
+
+impl Into<u32> for TscIOPin {
+    fn into(self) -> u32 {
+        match self {
+            TscIOPin::Group1Io1 => 0x00000001,
+            TscIOPin::Group1Io2 => 0x00000002,
+            TscIOPin::Group1Io3 => 0x00000004,
+            TscIOPin::Group1Io4 => 0x00000008,
+            TscIOPin::Group2Io1 => 0x00000010,
+            TscIOPin::Group2Io2 => 0x00000020,
+            TscIOPin::Group2Io3 => 0x00000040,
+            TscIOPin::Group2Io4 => 0x00000080,
+            TscIOPin::Group3Io1 => 0x00000100,
+            TscIOPin::Group3Io2 => 0x00000200,
+            TscIOPin::Group3Io3 => 0x00000400,
+            TscIOPin::Group3Io4 => 0x00000800,
+            TscIOPin::Group4Io1 => 0x00001000,
+            TscIOPin::Group4Io2 => 0x00002000,
+            TscIOPin::Group4Io3 => 0x00004000,
+            TscIOPin::Group4Io4 => 0x00008000,
+            TscIOPin::Group5Io1 => 0x00010000,
+            TscIOPin::Group5Io2 => 0x00020000,
+            TscIOPin::Group5Io3 => 0x00040000,
+            TscIOPin::Group5Io4 => 0x00080000,
+            TscIOPin::Group6Io1 => 0x00100000,
+            TscIOPin::Group6Io2 => 0x00200000,
+            TscIOPin::Group6Io3 => 0x00400000,
+            TscIOPin::Group6Io4 => 0x00800000,
+            TscIOPin::Group7Io1 => 0x01000000,
+            TscIOPin::Group7Io2 => 0x02000000,
+            TscIOPin::Group7Io3 => 0x04000000,
+            TscIOPin::Group7Io4 => 0x08000000,
+            TscIOPin::Group8Io1 => 0x10000000,
+            TscIOPin::Group8Io2 => 0x20000000,
+            TscIOPin::Group8Io3 => 0x40000000,
+            TscIOPin::Group8Io4 => 0x80000000,
+        }
+    }
+}
+
 /// Charge transfer pulse cycles
 #[allow(missing_docs)]
 #[derive(Copy, Clone)]
diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
index 60dd734c4..91cf7187a 100644
--- a/embassy-stm32/src/tsc/mod.rs
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -6,12 +6,15 @@
 pub mod enums;
 
 use crate::gpio::AnyPin;
+use crate::pac::tsc::regs;
 use crate::{pac::tsc::Tsc as Regs, rcc::RccPeripheral};
 use crate::{peripherals, Peripheral};
 use embassy_hal_internal::{into_ref, PeripheralRef};
 
 pub use enums::*;
 
+const TSC_NUM_GROUPS: u32 = 8;
+
 /// Error type defined for TSC
 #[derive(Debug)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -110,6 +113,12 @@ pub struct Config {
     pub acquisition_mode: bool,
     /// Enable max count interrupt
     pub max_count_interrupt: bool,
+    /// Channel IO mask
+    pub channel_ios: u32,
+    /// Shield IO mask
+    pub shield_ios: u32,
+    /// Sampling IO mask
+    pub sampling_ios: u32,
 }
 
 impl Default for Config {
@@ -126,6 +135,9 @@ impl Default for Config {
             synchro_pin_polarity: false,
             acquisition_mode: false,
             max_count_interrupt: false,
+            channel_ios: 0,
+            shield_ios: 0,
+            sampling_ios: 0,
         }
     }
 }
@@ -175,45 +187,44 @@ impl<'d, T: Instance> Tsc<'d, T> {
     pub fn new(
         peri: impl Peripheral<P = T> + 'd,
         // g1_d1: Option<PeriPin<impl Peripheral<P = impl G1IO1Pin<T>> + 'd>>,
-        g1_d2: Option<PeriPin<impl Peripheral<P = impl G1IO2Pin<T>> + 'd>>,
-        g1_d3: Option<PeriPin<impl Peripheral<P = impl G1IO3Pin<T>> + 'd>>,
-        g1_d4: Option<impl Peripheral<P = impl G1IO4Pin<T>> + 'd>,
+        // g1_d2: Option<PeriPin<impl Peripheral<P = impl G1IO2Pin<T>> + 'd>>,
+        // g1_d3: Option<PeriPin<impl Peripheral<P = impl G1IO3Pin<T>> + 'd>>,
+        // g1_d4: Option<PeriPin<impl Peripheral<P = impl G1IO4Pin<T>> + 'd>>,
 
-        g2_d1: Option<impl Peripheral<P = impl G2IO1Pin<T>> + 'd>,
-        g2_d2: Option<impl Peripheral<P = impl G2IO2Pin<T>> + 'd>,
-        g2_d3: Option<impl Peripheral<P = impl G2IO3Pin<T>> + 'd>,
-        g2_d4: Option<impl Peripheral<P = impl G2IO4Pin<T>> + 'd>,
+        // g2_d1: Option<impl Peripheral<P = impl G2IO1Pin<T>> + 'd>,
+        // g2_d2: Option<impl Peripheral<P = impl G2IO2Pin<T>> + 'd>,
+        // g2_d3: Option<impl Peripheral<P = impl G2IO3Pin<T>> + 'd>,
+        // g2_d4: Option<impl Peripheral<P = impl G2IO4Pin<T>> + 'd>,
 
-        g3_d1: Option<impl Peripheral<P = impl G3IO1Pin<T>> + 'd>,
-        g3_d2: Option<impl Peripheral<P = impl G3IO2Pin<T>> + 'd>,
-        g3_d3: Option<impl Peripheral<P = impl G3IO3Pin<T>> + 'd>,
-        g3_d4: Option<impl Peripheral<P = impl G3IO4Pin<T>> + 'd>,
+        // g3_d1: Option<impl Peripheral<P = impl G3IO1Pin<T>> + 'd>,
+        // g3_d2: Option<impl Peripheral<P = impl G3IO2Pin<T>> + 'd>,
+        // g3_d3: Option<impl Peripheral<P = impl G3IO3Pin<T>> + 'd>,
+        // g3_d4: Option<impl Peripheral<P = impl G3IO4Pin<T>> + 'd>,
 
-        g4_d1: Option<impl Peripheral<P = impl G4IO1Pin<T>> + 'd>,
-        g4_d2: Option<impl Peripheral<P = impl G4IO2Pin<T>> + 'd>,
-        g4_d3: Option<impl Peripheral<P = impl G4IO3Pin<T>> + 'd>,
-        g4_d4: Option<impl Peripheral<P = impl G4IO4Pin<T>> + 'd>,
+        // g4_d1: Option<impl Peripheral<P = impl G4IO1Pin<T>> + 'd>,
+        // g4_d2: Option<impl Peripheral<P = impl G4IO2Pin<T>> + 'd>,
+        // g4_d3: Option<impl Peripheral<P = impl G4IO3Pin<T>> + 'd>,
+        // g4_d4: Option<impl Peripheral<P = impl G4IO4Pin<T>> + 'd>,
 
-        g5_d1: Option<impl Peripheral<P = impl G5IO1Pin<T>> + 'd>,
-        g5_d2: Option<impl Peripheral<P = impl G5IO2Pin<T>> + 'd>,
-        g5_d3: Option<impl Peripheral<P = impl G5IO3Pin<T>> + 'd>,
-        g5_d4: Option<impl Peripheral<P = impl G5IO4Pin<T>> + 'd>,
+        // g5_d1: Option<impl Peripheral<P = impl G5IO1Pin<T>> + 'd>,
+        // g5_d2: Option<impl Peripheral<P = impl G5IO2Pin<T>> + 'd>,
+        // g5_d3: Option<impl Peripheral<P = impl G5IO3Pin<T>> + 'd>,
+        // g5_d4: Option<impl Peripheral<P = impl G5IO4Pin<T>> + 'd>,
 
-        g6_d1: Option<impl Peripheral<P = impl G6IO1Pin<T>> + 'd>,
-        g6_d2: Option<impl Peripheral<P = impl G6IO2Pin<T>> + 'd>,
-        g6_d3: Option<impl Peripheral<P = impl G6IO3Pin<T>> + 'd>,
-        g6_d4: Option<impl Peripheral<P = impl G6IO4Pin<T>> + 'd>,
+        // g6_d1: Option<impl Peripheral<P = impl G6IO1Pin<T>> + 'd>,
+        // g6_d2: Option<impl Peripheral<P = impl G6IO2Pin<T>> + 'd>,
+        // g6_d3: Option<impl Peripheral<P = impl G6IO3Pin<T>> + 'd>,
+        // g6_d4: Option<impl Peripheral<P = impl G6IO4Pin<T>> + 'd>,
 
-        g7_d1: Option<impl Peripheral<P = impl G7IO1Pin<T>> + 'd>,
-        g7_d2: Option<impl Peripheral<P = impl G7IO2Pin<T>> + 'd>,
-        g7_d3: Option<impl Peripheral<P = impl G7IO3Pin<T>> + 'd>,
-        g7_d4: Option<impl Peripheral<P = impl G7IO4Pin<T>> + 'd>,
-
-        g8_d1: Option<impl Peripheral<P = impl G8IO1Pin<T>> + 'd>,
-        g8_d2: Option<impl Peripheral<P = impl G8IO2Pin<T>> + 'd>,
-        g8_d3: Option<impl Peripheral<P = impl G8IO3Pin<T>> + 'd>,
-        g8_d4: Option<impl Peripheral<P = impl G8IO4Pin<T>> + 'd>,
+        // g7_d1: Option<impl Peripheral<P = impl G7IO1Pin<T>> + 'd>,
+        // g7_d2: Option<impl Peripheral<P = impl G7IO2Pin<T>> + 'd>,
+        // g7_d3: Option<impl Peripheral<P = impl G7IO3Pin<T>> + 'd>,
+        // g7_d4: Option<impl Peripheral<P = impl G7IO4Pin<T>> + 'd>,
 
+        // g8_d1: Option<impl Peripheral<P = impl G8IO1Pin<T>> + 'd>,
+        // g8_d2: Option<impl Peripheral<P = impl G8IO2Pin<T>> + 'd>,
+        // g8_d3: Option<impl Peripheral<P = impl G8IO3Pin<T>> + 'd>,
+        // g8_d4: Option<impl Peripheral<P = impl G8IO4Pin<T>> + 'd>,
         config: Config,
     ) -> Self {
         into_ref!(peri);
@@ -224,6 +235,15 @@ impl<'d, T: Instance> Tsc<'d, T> {
     }
 
     // fn filter_group() -> Option<PinGroup<'d>> {}
+    fn extract_groups(io_mask: u32) -> u32 {
+        let mut groups: u32 = 0;
+        for idx in 0..TSC_NUM_GROUPS {
+            if io_mask & (0x0F << idx * 4) != 0 {
+                groups |= 1 << idx
+            }
+        }
+        groups
+    }
 
     fn new_inner(peri: impl Peripheral<P = T> + 'd, config: Config) -> Self {
         into_ref!(peri);
@@ -245,22 +265,20 @@ impl<'d, T: Instance> Tsc<'d, T> {
 
         // Set IO configuration
         // Disable Schmitt trigger hysteresis on all used TSC IOs
-        // T::REGS.iohcr().modify(|w| {
-        //     w.
-        // });
+        T::REGS
+            .iohcr()
+            .write(|w| w.0 = config.channel_ios | config.shield_ios | config.sampling_ios);
 
         // Set channel and shield IOs
-        // T::REGS.ioccr().modify(|w| {});
+        T::REGS.ioccr().write(|w| w.0 = config.channel_ios | config.shield_ios);
 
         // Set sampling IOs
-        // T::REGS.ioscr().modify(|w| {
-        //     w.set_g1_io1(val)
-        // });
+        T::REGS.ioscr().write(|w| w.0 = config.sampling_ios);
 
         // Set the groups to be acquired
-        // T::REGS.iogcsr().modify(|w| {
-        //     w.set_g1e(val);
-        // });
+        T::REGS
+            .iogcsr()
+            .write(|w| w.0 = Self::extract_groups(config.channel_ios));
 
         // Disable interrupts
         T::REGS.ier().modify(|w| {

From af357d2ad08c82b35811bb603eae4e3fa3df87a0 Mon Sep 17 00:00:00 2001
From: Karun <karun@nautilusdefense.com>
Date: Fri, 19 Apr 2024 14:58:24 -0400
Subject: [PATCH 06/14] Prevent invalid config sets

---
 embassy-stm32/src/tsc/enums.rs | 23 +++++++++++++++++++++--
 embassy-stm32/src/tsc/mod.rs   | 22 +++++++++++++++++-----
 2 files changed, 38 insertions(+), 7 deletions(-)

diff --git a/embassy-stm32/src/tsc/enums.rs b/embassy-stm32/src/tsc/enums.rs
index 56df4173a..bc8e9d2f5 100644
--- a/embassy-stm32/src/tsc/enums.rs
+++ b/embassy-stm32/src/tsc/enums.rs
@@ -90,9 +90,28 @@ impl Into<u32> for TscIOPin {
     }
 }
 
+/// Spread Spectrum Deviation
+#[derive(Copy, Clone)]
+pub struct SSDeviation(u8);
+impl SSDeviation {
+    /// Create new deviation value, acceptable inputs are 1-128
+    pub fn new(val: u8) -> Result<Self, ()> {
+        if val == 0 || val > 128 {
+            return Err(());
+        }
+        Ok(Self(val - 1))
+    }
+}
+
+impl Into<u8> for SSDeviation {
+    fn into(self) -> u8 {
+        self.0
+    }
+}
+
 /// Charge transfer pulse cycles
 #[allow(missing_docs)]
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, PartialEq)]
 pub enum ChargeTransferPulseCycle {
     _1,
     _2,
@@ -137,7 +156,7 @@ impl Into<u8> for ChargeTransferPulseCycle {
 
 /// Prescaler divider
 #[allow(missing_docs)]
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, PartialEq)]
 pub enum PGPrescalerDivider {
     _1,
     _2,
diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
index 91cf7187a..8da0e87ab 100644
--- a/embassy-stm32/src/tsc/mod.rs
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -6,7 +6,6 @@
 pub mod enums;
 
 use crate::gpio::AnyPin;
-use crate::pac::tsc::regs;
 use crate::{pac::tsc::Tsc as Regs, rcc::RccPeripheral};
 use crate::{peripherals, Peripheral};
 use embassy_hal_internal::{into_ref, PeripheralRef};
@@ -98,7 +97,7 @@ pub struct Config {
     /// Enable/disable of spread spectrum feature
     pub spread_spectrum: bool,
     /// Adds variable number of periods of the SS clk to pulse high state
-    pub spread_spectrum_deviation: u8,
+    pub spread_spectrum_deviation: SSDeviation,
     /// Selects AHB clock divider used to generate SS clk
     pub spread_spectrum_prescaler: bool,
     /// Selects AHB clock divider used to generate pulse generator clk
@@ -127,7 +126,7 @@ impl Default for Config {
             ct_pulse_high_length: ChargeTransferPulseCycle::_1,
             ct_pulse_low_length: ChargeTransferPulseCycle::_1,
             spread_spectrum: false,
-            spread_spectrum_deviation: 0,
+            spread_spectrum_deviation: SSDeviation::new(0).unwrap(),
             spread_spectrum_prescaler: false,
             pulse_generator_prescaler: PGPrescalerDivider::_1,
             max_count_value: MaxCount::_255,
@@ -255,9 +254,22 @@ impl<'d, T: Instance> Tsc<'d, T> {
             w.set_ctph(config.ct_pulse_high_length.into());
             w.set_ctpl(config.ct_pulse_low_length.into());
             w.set_sse(config.spread_spectrum);
-            w.set_ssd(config.spread_spectrum_deviation);
+            // Prevent invalid configuration for pulse generator prescaler
+            if config.ct_pulse_low_length == ChargeTransferPulseCycle::_1
+                && (config.pulse_generator_prescaler == PGPrescalerDivider::_1
+                    || config.pulse_generator_prescaler == PGPrescalerDivider::_2)
+            {
+                w.set_pgpsc(PGPrescalerDivider::_4.into());
+            } else if config.ct_pulse_low_length == ChargeTransferPulseCycle::_2
+                && config.pulse_generator_prescaler == PGPrescalerDivider::_1
+            {
+                w.set_pgpsc(PGPrescalerDivider::_2.into());
+            } else {
+                w.set_pgpsc(config.pulse_generator_prescaler.into());
+            }
+            w.set_ssd(config.spread_spectrum_deviation.into());
             w.set_sspsc(config.spread_spectrum_prescaler);
-            w.set_pgpsc(config.pulse_generator_prescaler.into());
+
             w.set_mcv(config.max_count_value.into());
             w.set_syncpol(config.synchro_pin_polarity);
             w.set_am(config.acquisition_mode);

From fd69247d702d01a8e3c976a48bba4e44422d2cae Mon Sep 17 00:00:00 2001
From: Karun <karun@nautilusdefense.com>
Date: Fri, 19 Apr 2024 18:43:00 -0400
Subject: [PATCH 07/14] hyperspecific constructor

---
 embassy-stm32/src/tsc/mod.rs | 139 ++++++++++++++++++++++++++++++-----
 1 file changed, 119 insertions(+), 20 deletions(-)

diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
index 8da0e87ab..301d6f900 100644
--- a/embassy-stm32/src/tsc/mod.rs
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -5,7 +5,7 @@
 /// Enums defined for peripheral parameters
 pub mod enums;
 
-use crate::gpio::AnyPin;
+use crate::gpio::{low_level::AFType, AnyPin, Pull};
 use crate::{pac::tsc::Tsc as Regs, rcc::RccPeripheral};
 use crate::{peripherals, Peripheral};
 use embassy_hal_internal::{into_ref, PeripheralRef};
@@ -186,22 +186,21 @@ impl<'d, T: Instance> Tsc<'d, T> {
     pub fn new(
         peri: impl Peripheral<P = T> + 'd,
         // g1_d1: Option<PeriPin<impl Peripheral<P = impl G1IO1Pin<T>> + 'd>>,
-        // g1_d2: Option<PeriPin<impl Peripheral<P = impl G1IO2Pin<T>> + 'd>>,
-        // g1_d3: Option<PeriPin<impl Peripheral<P = impl G1IO3Pin<T>> + 'd>>,
+        g1_d2: Option<PeriPin<impl Peripheral<P = impl G1IO2Pin<T>> + 'd>>,
+        g1_d3: Option<PeriPin<impl Peripheral<P = impl G1IO3Pin<T>> + 'd>>,
         // g1_d4: Option<PeriPin<impl Peripheral<P = impl G1IO4Pin<T>> + 'd>>,
 
         // g2_d1: Option<impl Peripheral<P = impl G2IO1Pin<T>> + 'd>,
         // g2_d2: Option<impl Peripheral<P = impl G2IO2Pin<T>> + 'd>,
-        // g2_d3: Option<impl Peripheral<P = impl G2IO3Pin<T>> + 'd>,
-        // g2_d4: Option<impl Peripheral<P = impl G2IO4Pin<T>> + 'd>,
+        g2_d3: Option<PeriPin<impl Peripheral<P = impl G2IO3Pin<T>> + 'd>>,
+        g2_d4: Option<PeriPin<impl Peripheral<P = impl G2IO4Pin<T>> + 'd>>,
 
         // g3_d1: Option<impl Peripheral<P = impl G3IO1Pin<T>> + 'd>,
         // g3_d2: Option<impl Peripheral<P = impl G3IO2Pin<T>> + 'd>,
         // g3_d3: Option<impl Peripheral<P = impl G3IO3Pin<T>> + 'd>,
         // g3_d4: Option<impl Peripheral<P = impl G3IO4Pin<T>> + 'd>,
-
-        // g4_d1: Option<impl Peripheral<P = impl G4IO1Pin<T>> + 'd>,
-        // g4_d2: Option<impl Peripheral<P = impl G4IO2Pin<T>> + 'd>,
+        g4_d1: Option<PeriPin<impl Peripheral<P = impl G4IO1Pin<T>> + 'd>>,
+        g4_d2: Option<PeriPin<impl Peripheral<P = impl G4IO2Pin<T>> + 'd>>,
         // g4_d3: Option<impl Peripheral<P = impl G4IO3Pin<T>> + 'd>,
         // g4_d4: Option<impl Peripheral<P = impl G4IO4Pin<T>> + 'd>,
 
@@ -226,13 +225,102 @@ impl<'d, T: Instance> Tsc<'d, T> {
         // g8_d4: Option<impl Peripheral<P = impl G8IO4Pin<T>> + 'd>,
         config: Config,
     ) -> Self {
-        into_ref!(peri);
+        let g1_d2 = g1_d2.unwrap();
+        let g1_d2_pin = g1_d2.pin;
+        let g1_d3 = g1_d3.unwrap();
+        let g1_d3_pin = g1_d3.pin;
+        let g2_d3 = g2_d3.unwrap();
+        let g2_d3_pin = g2_d3.pin;
+        let g2_d4 = g2_d4.unwrap();
+        let g2_d4_pin = g2_d4.pin;
+        let g4_d1 = g4_d1.unwrap();
+        let g4_d1_pin = g4_d1.pin;
+        let g4_d2 = g4_d2.unwrap();
+        let g4_d2_pin = g4_d2.pin;
+        into_ref!(peri, g1_d2_pin, g1_d3_pin, g2_d3_pin, g2_d4_pin, g4_d1_pin, g4_d2_pin);
+
+        // Configure pins
+        match g1_d2.role {
+            PinType::Channel => g1_d2_pin.set_as_af_pull(g1_d2_pin.af_num(), AFType::OutputPushPull, Pull::None),
+            PinType::Sample => g1_d2_pin.set_as_af_pull(g1_d2_pin.af_num(), AFType::OutputOpenDrain, Pull::None),
+            PinType::Shield => g1_d2_pin.set_as_af_pull(g1_d2_pin.af_num(), AFType::OutputPushPull, Pull::None),
+        }
+        match g1_d3.role {
+            PinType::Channel => g1_d3_pin.set_as_af_pull(g1_d3_pin.af_num(), AFType::OutputPushPull, Pull::None),
+            PinType::Sample => g1_d3_pin.set_as_af_pull(g1_d3_pin.af_num(), AFType::OutputOpenDrain, Pull::None),
+            PinType::Shield => g1_d3_pin.set_as_af_pull(g1_d3_pin.af_num(), AFType::OutputPushPull, Pull::None),
+        }
+        let g1 = PinGroup {
+            d1: None,
+            d2: Some(TscPin {
+                pin: g1_d2_pin.map_into(),
+                role: g1_d2.role,
+            }),
+            d3: Some(TscPin {
+                pin: g1_d3_pin.map_into(),
+                role: g1_d3.role,
+            }),
+            d4: None,
+        };
+
+        match g2_d3.role {
+            PinType::Channel => g2_d3_pin.set_as_af_pull(g2_d3_pin.af_num(), AFType::OutputPushPull, Pull::None),
+            PinType::Sample => g2_d3_pin.set_as_af_pull(g2_d3_pin.af_num(), AFType::OutputOpenDrain, Pull::None),
+            PinType::Shield => g2_d3_pin.set_as_af_pull(g2_d3_pin.af_num(), AFType::OutputPushPull, Pull::None),
+        }
+        match g2_d4.role {
+            PinType::Channel => g2_d4_pin.set_as_af_pull(g2_d4_pin.af_num(), AFType::OutputPushPull, Pull::None),
+            PinType::Sample => g2_d4_pin.set_as_af_pull(g2_d4_pin.af_num(), AFType::OutputOpenDrain, Pull::None),
+            PinType::Shield => g2_d4_pin.set_as_af_pull(g2_d4_pin.af_num(), AFType::OutputPushPull, Pull::None),
+        }
+        let g2 = PinGroup {
+            d1: None,
+            d2: None,
+            d3: Some(TscPin {
+                pin: g2_d3_pin.map_into(),
+                role: g2_d3.role,
+            }),
+            d4: Some(TscPin {
+                pin: g2_d4_pin.map_into(),
+                role: g2_d4.role,
+            }),
+        };
+
+        match g4_d1.role {
+            PinType::Channel => g4_d1_pin.set_as_af_pull(g4_d1_pin.af_num(), AFType::OutputPushPull, Pull::None),
+            PinType::Sample => g4_d1_pin.set_as_af_pull(g4_d1_pin.af_num(), AFType::OutputOpenDrain, Pull::None),
+            PinType::Shield => g4_d1_pin.set_as_af_pull(g4_d1_pin.af_num(), AFType::OutputPushPull, Pull::None),
+        }
+        match g4_d2.role {
+            PinType::Channel => g4_d2_pin.set_as_af_pull(g4_d2_pin.af_num(), AFType::OutputPushPull, Pull::None),
+            PinType::Sample => g4_d2_pin.set_as_af_pull(g4_d2_pin.af_num(), AFType::OutputOpenDrain, Pull::None),
+            PinType::Shield => g4_d2_pin.set_as_af_pull(g4_d2_pin.af_num(), AFType::OutputPushPull, Pull::None),
+        }
+        let g4 = PinGroup {
+            d1: Some(TscPin {
+                pin: g4_d1_pin.map_into(),
+                role: g4_d1.role,
+            }),
+            d2: Some(TscPin {
+                pin: g4_d2_pin.map_into(),
+                role: g4_d2.role,
+            }),
+            d3: None,
+            d4: None,
+        };
 
         // Need to check valid pin configuration input
-        // Need to configure pin
-        Self::new_inner(peri, config)
+        Self::new_inner(peri, Some(g1), Some(g2), None, Some(g4), None, None, None, None, config)
     }
 
+    // fn configure_pin<'b, G: Pin>(pin: PeripheralRef<'b, G>, role: PinType) {
+    //     match role {
+    //         PinType::Channel => pin.set_as_af_pull(pin.af_num(), AFType::OutputPushPull, Pull::None),
+    //         PinType::Sample => {}
+    //         PinType::Shield => {}
+    //     }
+    // }
+
     // fn filter_group() -> Option<PinGroup<'d>> {}
     fn extract_groups(io_mask: u32) -> u32 {
         let mut groups: u32 = 0;
@@ -244,7 +332,18 @@ impl<'d, T: Instance> Tsc<'d, T> {
         groups
     }
 
-    fn new_inner(peri: impl Peripheral<P = T> + 'd, config: Config) -> Self {
+    fn new_inner(
+        peri: impl Peripheral<P = T> + 'd,
+        g1: Option<PinGroup<'d, AnyPin>>,
+        g2: Option<PinGroup<'d, AnyPin>>,
+        g3: Option<PinGroup<'d, AnyPin>>,
+        g4: Option<PinGroup<'d, AnyPin>>,
+        g5: Option<PinGroup<'d, AnyPin>>,
+        g6: Option<PinGroup<'d, AnyPin>>,
+        g7: Option<PinGroup<'d, AnyPin>>,
+        g8: Option<PinGroup<'d, AnyPin>>,
+        config: Config,
+    ) -> Self {
         into_ref!(peri);
 
         T::enable_and_reset();
@@ -306,14 +405,14 @@ impl<'d, T: Instance> Tsc<'d, T> {
 
         Self {
             _peri: peri,
-            g1: None,
-            g2: None,
-            g3: None,
-            g4: None,
-            g5: None,
-            g6: None,
-            g7: None,
-            g8: None,
+            g1,
+            g2,
+            g3,
+            g4,
+            g5,
+            g6,
+            g7,
+            g8,
             state: State::Ready,
             config,
         }

From 253f6c42eeada0bc9e40582fd968214d8f8bd761 Mon Sep 17 00:00:00 2001
From: Karun <karun@nautilusdefense.com>
Date: Mon, 22 Apr 2024 12:36:17 -0400
Subject: [PATCH 08/14] Address versioning and format issues raised by CI

---
 embassy-stm32/src/lib.rs       |  4 ++--
 embassy-stm32/src/tsc/enums.rs | 16 ++++++++++++++
 embassy-stm32/src/tsc/mod.rs   | 38 +++++++++++++++++++++++++++-------
 3 files changed, 49 insertions(+), 9 deletions(-)

diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index dd89618ef..2bda2cf79 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -101,10 +101,10 @@ pub mod sai;
 pub mod sdmmc;
 #[cfg(spi)]
 pub mod spi;
-#[cfg(ucpd)]
-pub mod ucpd;
 #[cfg(tsc)]
 pub mod tsc;
+#[cfg(ucpd)]
+pub mod ucpd;
 #[cfg(uid)]
 pub mod uid;
 #[cfg(usart)]
diff --git a/embassy-stm32/src/tsc/enums.rs b/embassy-stm32/src/tsc/enums.rs
index bc8e9d2f5..bdb384900 100644
--- a/embassy-stm32/src/tsc/enums.rs
+++ b/embassy-stm32/src/tsc/enums.rs
@@ -27,13 +27,21 @@ pub enum TscIOPin {
     Group6Io2,
     Group6Io3,
     Group6Io4,
+    #[cfg(any(tsc_v2, tsc_v3))]
     Group7Io1,
+    #[cfg(any(tsc_v2, tsc_v3))]
     Group7Io2,
+    #[cfg(any(tsc_v2, tsc_v3))]
     Group7Io3,
+    #[cfg(any(tsc_v2, tsc_v3))]
     Group7Io4,
+    #[cfg(tsc_v3)]
     Group8Io1,
+    #[cfg(tsc_v3)]
     Group8Io2,
+    #[cfg(tsc_v3)]
     Group8Io3,
+    #[cfg(tsc_v3)]
     Group8Io4,
 }
 
@@ -78,13 +86,21 @@ impl Into<u32> for TscIOPin {
             TscIOPin::Group6Io2 => 0x00200000,
             TscIOPin::Group6Io3 => 0x00400000,
             TscIOPin::Group6Io4 => 0x00800000,
+            #[cfg(any(tsc_v2, tsc_v3))]
             TscIOPin::Group7Io1 => 0x01000000,
+            #[cfg(any(tsc_v2, tsc_v3))]
             TscIOPin::Group7Io2 => 0x02000000,
+            #[cfg(any(tsc_v2, tsc_v3))]
             TscIOPin::Group7Io3 => 0x04000000,
+            #[cfg(any(tsc_v2, tsc_v3))]
             TscIOPin::Group7Io4 => 0x08000000,
+            #[cfg(tsc_v3)]
             TscIOPin::Group8Io1 => 0x10000000,
+            #[cfg(tsc_v3)]
             TscIOPin::Group8Io2 => 0x20000000,
+            #[cfg(tsc_v3)]
             TscIOPin::Group8Io3 => 0x40000000,
+            #[cfg(tsc_v3)]
             TscIOPin::Group8Io4 => 0x80000000,
         }
     }
diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
index 301d6f900..8642da0e1 100644
--- a/embassy-stm32/src/tsc/mod.rs
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -5,13 +5,14 @@
 /// Enums defined for peripheral parameters
 pub mod enums;
 
-use crate::gpio::{low_level::AFType, AnyPin, Pull};
-use crate::{pac::tsc::Tsc as Regs, rcc::RccPeripheral};
+pub use enums::*;
+
+use crate::gpio::{AFType, AnyPin, Pull};
+use crate::pac::tsc::Tsc as Regs;
+use crate::rcc::RccPeripheral;
 use crate::{peripherals, Peripheral};
 use embassy_hal_internal::{into_ref, PeripheralRef};
 
-pub use enums::*;
-
 const TSC_NUM_GROUPS: u32 = 8;
 
 /// Error type defined for TSC
@@ -68,7 +69,9 @@ pub enum Group {
     Four,
     Five,
     Six,
+    #[cfg(any(tsc_v2, tsc_v3))]
     Seven,
+    #[cfg(tsc_v3)]
     Eight,
 }
 
@@ -81,7 +84,9 @@ impl Into<usize> for Group {
             Group::Four => 3,
             Group::Five => 4,
             Group::Six => 5,
+            #[cfg(any(tsc_v2, tsc_v3))]
             Group::Seven => 6,
+            #[cfg(tsc_v3)]
             Group::Eight => 7,
         }
     }
@@ -175,7 +180,9 @@ pub struct Tsc<'d, T: Instance> {
     g4: Option<PinGroup<'d, AnyPin>>,
     g5: Option<PinGroup<'d, AnyPin>>,
     g6: Option<PinGroup<'d, AnyPin>>,
+    #[cfg(any(tsc_v2, tsc_v3))]
     g7: Option<PinGroup<'d, AnyPin>>,
+    #[cfg(tsc_v3)]
     g8: Option<PinGroup<'d, AnyPin>>,
     state: State,
     config: Config,
@@ -310,7 +317,20 @@ impl<'d, T: Instance> Tsc<'d, T> {
         };
 
         // Need to check valid pin configuration input
-        Self::new_inner(peri, Some(g1), Some(g2), None, Some(g4), None, None, None, None, config)
+        Self::new_inner(
+            peri,
+            Some(g1),
+            Some(g2),
+            None,
+            Some(g4),
+            None,
+            None,
+            #[cfg(any(tsc_v2, tsc_v3))]
+            None,
+            #[cfg(tsc_v3)]
+            None,
+            config,
+        )
     }
 
     // fn configure_pin<'b, G: Pin>(pin: PeripheralRef<'b, G>, role: PinType) {
@@ -340,8 +360,8 @@ impl<'d, T: Instance> Tsc<'d, T> {
         g4: Option<PinGroup<'d, AnyPin>>,
         g5: Option<PinGroup<'d, AnyPin>>,
         g6: Option<PinGroup<'d, AnyPin>>,
-        g7: Option<PinGroup<'d, AnyPin>>,
-        g8: Option<PinGroup<'d, AnyPin>>,
+        #[cfg(any(tsc_v2, tsc_v3))] g7: Option<PinGroup<'d, AnyPin>>,
+        #[cfg(tsc_v3)] g8: Option<PinGroup<'d, AnyPin>>,
         config: Config,
     ) -> Self {
         into_ref!(peri);
@@ -411,7 +431,9 @@ impl<'d, T: Instance> Tsc<'d, T> {
             g4,
             g5,
             g6,
+            #[cfg(any(tsc_v2, tsc_v3))]
             g7,
+            #[cfg(tsc_v3)]
             g8,
             state: State::Ready,
             config,
@@ -548,7 +570,9 @@ impl<'d, T: Instance> Tsc<'d, T> {
             Group::Four => T::REGS.iogcsr().read().g4s(),
             Group::Five => T::REGS.iogcsr().read().g5s(),
             Group::Six => T::REGS.iogcsr().read().g6s(),
+            #[cfg(any(tsc_v2, tsc_v3))]
             Group::Seven => T::REGS.iogcsr().read().g7s(),
+            #[cfg(tsc_v3)]
             Group::Eight => T::REGS.iogcsr().read().g8s(),
         };
         match status {

From 4bf2178de700e9a03aebcf161f36e2e36fb0581f Mon Sep 17 00:00:00 2001
From: Karun <karun@nautilusdefense.com>
Date: Mon, 22 Apr 2024 12:40:08 -0400
Subject: [PATCH 09/14] remove remaining warnings

---
 embassy-stm32/src/tsc/mod.rs | 35 ++++++++++++++++++-----------------
 1 file changed, 18 insertions(+), 17 deletions(-)

diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
index 8642da0e1..ad0f1cca0 100644
--- a/embassy-stm32/src/tsc/mod.rs
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -5,13 +5,13 @@
 /// Enums defined for peripheral parameters
 pub mod enums;
 
+use embassy_hal_internal::{into_ref, PeripheralRef};
 pub use enums::*;
 
 use crate::gpio::{AFType, AnyPin, Pull};
 use crate::pac::tsc::Tsc as Regs;
 use crate::rcc::RccPeripheral;
 use crate::{peripherals, Peripheral};
-use embassy_hal_internal::{into_ref, PeripheralRef};
 
 const TSC_NUM_GROUPS: u32 = 8;
 
@@ -148,6 +148,7 @@ impl Default for Config {
 
 /// Pin struct that maintains usage
 #[allow(missing_docs)]
+#[allow(dead_code)]
 pub struct TscPin<'d, T> {
     pin: PeripheralRef<'d, T>,
     role: PinType,
@@ -174,16 +175,16 @@ pub struct PinGroup<'d, A> {
 /// TSC driver
 pub struct Tsc<'d, T: Instance> {
     _peri: PeripheralRef<'d, T>,
-    g1: Option<PinGroup<'d, AnyPin>>,
-    g2: Option<PinGroup<'d, AnyPin>>,
-    g3: Option<PinGroup<'d, AnyPin>>,
-    g4: Option<PinGroup<'d, AnyPin>>,
-    g5: Option<PinGroup<'d, AnyPin>>,
-    g6: Option<PinGroup<'d, AnyPin>>,
+    _g1: Option<PinGroup<'d, AnyPin>>,
+    _g2: Option<PinGroup<'d, AnyPin>>,
+    _g3: Option<PinGroup<'d, AnyPin>>,
+    _g4: Option<PinGroup<'d, AnyPin>>,
+    _g5: Option<PinGroup<'d, AnyPin>>,
+    _g6: Option<PinGroup<'d, AnyPin>>,
     #[cfg(any(tsc_v2, tsc_v3))]
-    g7: Option<PinGroup<'d, AnyPin>>,
+    _g7: Option<PinGroup<'d, AnyPin>>,
     #[cfg(tsc_v3)]
-    g8: Option<PinGroup<'d, AnyPin>>,
+    _g8: Option<PinGroup<'d, AnyPin>>,
     state: State,
     config: Config,
 }
@@ -425,16 +426,16 @@ impl<'d, T: Instance> Tsc<'d, T> {
 
         Self {
             _peri: peri,
-            g1,
-            g2,
-            g3,
-            g4,
-            g5,
-            g6,
+            _g1: g1,
+            _g2: g2,
+            _g3: g3,
+            _g4: g4,
+            _g5: g5,
+            _g6: g6,
             #[cfg(any(tsc_v2, tsc_v3))]
-            g7,
+            _g7: g7,
             #[cfg(tsc_v3)]
-            g8,
+            _g8: g8,
             state: State::Ready,
             config,
         }

From 3cd6232d434861865864edd2dee5082d1b07029c Mon Sep 17 00:00:00 2001
From: Karun <karun@nautilusdefense.com>
Date: Mon, 22 Apr 2024 13:08:21 -0400
Subject: [PATCH 10/14] update num groups definition

---
 embassy-stm32/src/tsc/mod.rs | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
index ad0f1cca0..4b1987469 100644
--- a/embassy-stm32/src/tsc/mod.rs
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -13,6 +13,11 @@ use crate::pac::tsc::Tsc as Regs;
 use crate::rcc::RccPeripheral;
 use crate::{peripherals, Peripheral};
 
+#[cfg(tsc_v1)]
+const TSC_NUM_GROUPS: u32 = 6;
+#[cfg(tsc_v2)]
+const TSC_NUM_GROUPS: u32 = 7;
+#[cfg(tsc_v3)]
 const TSC_NUM_GROUPS: u32 = 8;
 
 /// Error type defined for TSC

From 0f8b3b8c65484a444d1dc9f6179ce3a60a63c06f Mon Sep 17 00:00:00 2001
From: Karun <karun@nautilusdefense.com>
Date: Thu, 2 May 2024 13:30:30 -0400
Subject: [PATCH 11/14] Functional touch sensing

---
 embassy-stm32/src/tsc/enums.rs |  15 +-
 embassy-stm32/src/tsc/mod.rs   | 356 ++++++++++++++++-----------------
 2 files changed, 189 insertions(+), 182 deletions(-)

diff --git a/embassy-stm32/src/tsc/enums.rs b/embassy-stm32/src/tsc/enums.rs
index bdb384900..0d34a43ec 100644
--- a/embassy-stm32/src/tsc/enums.rs
+++ b/embassy-stm32/src/tsc/enums.rs
@@ -48,14 +48,25 @@ pub enum TscIOPin {
 impl BitOr<TscIOPin> for u32 {
     type Output = u32;
     fn bitor(self, rhs: TscIOPin) -> Self::Output {
-        self | rhs as u32
+        let rhs: u32 = rhs.into();
+        self | rhs
+    }
+}
+
+impl BitOr<u32> for TscIOPin {
+    type Output = u32;
+    fn bitor(self, rhs: u32) -> Self::Output {
+        let val: u32 = self.into();
+        val | rhs
     }
 }
 
 impl BitOr for TscIOPin {
     type Output = u32;
     fn bitor(self, rhs: Self) -> Self::Output {
-        self as u32 | rhs as u32
+        let val: u32 = self.into();
+        let rhs: u32 = rhs.into();
+        val | rhs
     }
 }
 
diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
index 4b1987469..a37341b31 100644
--- a/embassy-stm32/src/tsc/mod.rs
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -5,10 +5,12 @@
 /// Enums defined for peripheral parameters
 pub mod enums;
 
+use core::marker::PhantomData;
+
 use embassy_hal_internal::{into_ref, PeripheralRef};
 pub use enums::*;
 
-use crate::gpio::{AFType, AnyPin, Pull};
+use crate::gpio::{AFType, AnyPin};
 use crate::pac::tsc::Tsc as Regs;
 use crate::rcc::RccPeripheral;
 use crate::{peripherals, Peripheral};
@@ -38,9 +40,6 @@ pub enum PinType {
     Shield,
 }
 
-/// Unclear
-pub struct TscGroup {}
-
 /// Peripheral state
 #[derive(PartialEq, Clone, Copy)]
 pub enum State {
@@ -58,6 +57,7 @@ pub enum State {
 /// For groups with multiple channel pins, may take longer because acquisitions
 /// are done sequentially. Check this status before pulling count for each
 /// sampled channel
+#[derive(PartialEq)]
 pub enum GroupStatus {
     /// Acquisition for channel still in progress
     Ongoing,
@@ -136,7 +136,7 @@ impl Default for Config {
             ct_pulse_high_length: ChargeTransferPulseCycle::_1,
             ct_pulse_low_length: ChargeTransferPulseCycle::_1,
             spread_spectrum: false,
-            spread_spectrum_deviation: SSDeviation::new(0).unwrap(),
+            spread_spectrum_deviation: SSDeviation::new(1).unwrap(),
             spread_spectrum_prescaler: false,
             pulse_generator_prescaler: PGPrescalerDivider::_1,
             max_count_value: MaxCount::_255,
@@ -153,43 +153,165 @@ impl Default for Config {
 
 /// Pin struct that maintains usage
 #[allow(missing_docs)]
-#[allow(dead_code)]
-pub struct TscPin<'d, T> {
-    pin: PeripheralRef<'d, T>,
-    role: PinType,
-}
-
-/// Input structure for constructor containing peripherals
-#[allow(missing_docs)]
-pub struct PeriPin<T> {
-    pub pin: T,
-    pub role: PinType,
+pub struct TscPin<'d, T, C> {
+    _pin: PeripheralRef<'d, AnyPin>,
+    _role: PinType,
+    phantom: PhantomData<(T, C)>,
 }
 
 /// Pin group definition
 /// Pins are organized into groups of four IOs, all groups with a
 /// sampling channel must also have a sampling capacitor channel.
 #[allow(missing_docs)]
-pub struct PinGroup<'d, A> {
-    pub d1: Option<TscPin<'d, A>>,
-    pub d2: Option<TscPin<'d, A>>,
-    pub d3: Option<TscPin<'d, A>>,
-    pub d4: Option<TscPin<'d, A>>,
+#[derive(Default)]
+pub struct PinGroup<'d, T, C> {
+    d1: Option<TscPin<'d, T, C>>,
+    d2: Option<TscPin<'d, T, C>>,
+    d3: Option<TscPin<'d, T, C>>,
+    d4: Option<TscPin<'d, T, C>>,
 }
 
+impl<'d, T: Instance, C> PinGroup<'d, T, C> {
+    /// Create new sensing group
+    pub fn new() -> Self {
+        Self {
+            d1: None,
+            d2: None,
+            d3: None,
+            d4: None,
+        }
+    }
+}
+
+macro_rules! group_impl {
+    ($group:ident, $trait1:ident, $trait2:ident, $trait3:ident, $trait4:ident) => {
+        impl<'d, T: Instance> PinGroup<'d, T, $group> {
+            #[doc = concat!("Create a new pin1 for ", stringify!($group), " TSC group instance.")]
+            pub fn set_io1(&mut self, pin: impl Peripheral<P = impl $trait1<T>> + 'd, role: PinType) {
+                into_ref!(pin);
+                critical_section::with(|_| {
+                    pin.set_low();
+                    pin.set_as_af(
+                        pin.af_num(),
+                        match role {
+                            PinType::Channel => AFType::OutputPushPull,
+                            PinType::Sample => AFType::OutputOpenDrain,
+                            PinType::Shield => AFType::OutputPushPull,
+                        },
+                    );
+                    self.d1 = Some(TscPin {
+                        _pin: pin.map_into(),
+                        _role: role,
+                        phantom: PhantomData,
+                    })
+                })
+            }
+
+            #[doc = concat!("Create a new pin2 for ", stringify!($group), " TSC group instance.")]
+            pub fn set_io2(&mut self, pin: impl Peripheral<P = impl $trait2<T>> + 'd, role: PinType) {
+                into_ref!(pin);
+                critical_section::with(|_| {
+                    pin.set_low();
+                    pin.set_as_af(
+                        pin.af_num(),
+                        match role {
+                            PinType::Channel => AFType::OutputPushPull,
+                            PinType::Sample => AFType::OutputOpenDrain,
+                            PinType::Shield => AFType::OutputPushPull,
+                        },
+                    );
+                    self.d2 = Some(TscPin {
+                        _pin: pin.map_into(),
+                        _role: role,
+                        phantom: PhantomData,
+                    })
+                })
+            }
+
+            #[doc = concat!("Create a new pin3 for ", stringify!($group), " TSC group instance.")]
+            pub fn set_io3(&mut self, pin: impl Peripheral<P = impl $trait3<T>> + 'd, role: PinType) {
+                into_ref!(pin);
+                critical_section::with(|_| {
+                    pin.set_low();
+                    pin.set_as_af(
+                        pin.af_num(),
+                        match role {
+                            PinType::Channel => AFType::OutputPushPull,
+                            PinType::Sample => AFType::OutputOpenDrain,
+                            PinType::Shield => AFType::OutputPushPull,
+                        },
+                    );
+                    self.d3 = Some(TscPin {
+                        _pin: pin.map_into(),
+                        _role: role,
+                        phantom: PhantomData,
+                    })
+                })
+            }
+
+            #[doc = concat!("Create a new pin4 for ", stringify!($group), " TSC group instance.")]
+            pub fn set_io4(&mut self, pin: impl Peripheral<P = impl $trait4<T>> + 'd, role: PinType) {
+                into_ref!(pin);
+                critical_section::with(|_| {
+                    pin.set_low();
+                    pin.set_as_af(
+                        pin.af_num(),
+                        match role {
+                            PinType::Channel => AFType::OutputPushPull,
+                            PinType::Sample => AFType::OutputOpenDrain,
+                            PinType::Shield => AFType::OutputPushPull,
+                        },
+                    );
+                    self.d4 = Some(TscPin {
+                        _pin: pin.map_into(),
+                        _role: role,
+                        phantom: PhantomData,
+                    })
+                })
+            }
+        }
+    };
+}
+
+group_impl!(G1, G1IO1Pin, G1IO2Pin, G1IO3Pin, G1IO4Pin);
+group_impl!(G2, G2IO1Pin, G2IO2Pin, G2IO3Pin, G2IO4Pin);
+group_impl!(G3, G3IO1Pin, G3IO2Pin, G3IO3Pin, G3IO4Pin);
+group_impl!(G4, G4IO1Pin, G4IO2Pin, G4IO3Pin, G4IO4Pin);
+group_impl!(G5, G5IO1Pin, G5IO2Pin, G5IO3Pin, G5IO4Pin);
+group_impl!(G6, G6IO1Pin, G6IO2Pin, G6IO3Pin, G6IO4Pin);
+group_impl!(G7, G7IO1Pin, G7IO2Pin, G7IO3Pin, G7IO4Pin);
+group_impl!(G8, G8IO1Pin, G8IO2Pin, G8IO3Pin, G8IO4Pin);
+
+/// Group 1 marker type.
+pub enum G1 {}
+/// Group 2 marker type.
+pub enum G2 {}
+/// Group 3 marker type.
+pub enum G3 {}
+/// Group 4 marker type.
+pub enum G4 {}
+/// Group 5 marker type.
+pub enum G5 {}
+/// Group 6 marker type.
+pub enum G6 {}
+/// Group 7 marker type.
+pub enum G7 {}
+/// Group 8 marker type.
+pub enum G8 {}
+
 /// TSC driver
 pub struct Tsc<'d, T: Instance> {
     _peri: PeripheralRef<'d, T>,
-    _g1: Option<PinGroup<'d, AnyPin>>,
-    _g2: Option<PinGroup<'d, AnyPin>>,
-    _g3: Option<PinGroup<'d, AnyPin>>,
-    _g4: Option<PinGroup<'d, AnyPin>>,
-    _g5: Option<PinGroup<'d, AnyPin>>,
-    _g6: Option<PinGroup<'d, AnyPin>>,
+    _g1: Option<PinGroup<'d, T, G1>>,
+    _g2: Option<PinGroup<'d, T, G2>>,
+    _g3: Option<PinGroup<'d, T, G3>>,
+    _g4: Option<PinGroup<'d, T, G4>>,
+    _g5: Option<PinGroup<'d, T, G5>>,
+    _g6: Option<PinGroup<'d, T, G6>>,
     #[cfg(any(tsc_v2, tsc_v3))]
-    _g7: Option<PinGroup<'d, AnyPin>>,
+    _g7: Option<PinGroup<'d, T, G7>>,
     #[cfg(tsc_v3)]
-    _g8: Option<PinGroup<'d, AnyPin>>,
+    _g8: Option<PinGroup<'d, T, G8>>,
     state: State,
     config: Config,
 }
@@ -198,156 +320,33 @@ impl<'d, T: Instance> Tsc<'d, T> {
     /// Create new TSC driver
     pub fn new(
         peri: impl Peripheral<P = T> + 'd,
-        // g1_d1: Option<PeriPin<impl Peripheral<P = impl G1IO1Pin<T>> + 'd>>,
-        g1_d2: Option<PeriPin<impl Peripheral<P = impl G1IO2Pin<T>> + 'd>>,
-        g1_d3: Option<PeriPin<impl Peripheral<P = impl G1IO3Pin<T>> + 'd>>,
-        // g1_d4: Option<PeriPin<impl Peripheral<P = impl G1IO4Pin<T>> + 'd>>,
-
-        // g2_d1: Option<impl Peripheral<P = impl G2IO1Pin<T>> + 'd>,
-        // g2_d2: Option<impl Peripheral<P = impl G2IO2Pin<T>> + 'd>,
-        g2_d3: Option<PeriPin<impl Peripheral<P = impl G2IO3Pin<T>> + 'd>>,
-        g2_d4: Option<PeriPin<impl Peripheral<P = impl G2IO4Pin<T>> + 'd>>,
-
-        // g3_d1: Option<impl Peripheral<P = impl G3IO1Pin<T>> + 'd>,
-        // g3_d2: Option<impl Peripheral<P = impl G3IO2Pin<T>> + 'd>,
-        // g3_d3: Option<impl Peripheral<P = impl G3IO3Pin<T>> + 'd>,
-        // g3_d4: Option<impl Peripheral<P = impl G3IO4Pin<T>> + 'd>,
-        g4_d1: Option<PeriPin<impl Peripheral<P = impl G4IO1Pin<T>> + 'd>>,
-        g4_d2: Option<PeriPin<impl Peripheral<P = impl G4IO2Pin<T>> + 'd>>,
-        // g4_d3: Option<impl Peripheral<P = impl G4IO3Pin<T>> + 'd>,
-        // g4_d4: Option<impl Peripheral<P = impl G4IO4Pin<T>> + 'd>,
-
-        // g5_d1: Option<impl Peripheral<P = impl G5IO1Pin<T>> + 'd>,
-        // g5_d2: Option<impl Peripheral<P = impl G5IO2Pin<T>> + 'd>,
-        // g5_d3: Option<impl Peripheral<P = impl G5IO3Pin<T>> + 'd>,
-        // g5_d4: Option<impl Peripheral<P = impl G5IO4Pin<T>> + 'd>,
-
-        // g6_d1: Option<impl Peripheral<P = impl G6IO1Pin<T>> + 'd>,
-        // g6_d2: Option<impl Peripheral<P = impl G6IO2Pin<T>> + 'd>,
-        // g6_d3: Option<impl Peripheral<P = impl G6IO3Pin<T>> + 'd>,
-        // g6_d4: Option<impl Peripheral<P = impl G6IO4Pin<T>> + 'd>,
-
-        // g7_d1: Option<impl Peripheral<P = impl G7IO1Pin<T>> + 'd>,
-        // g7_d2: Option<impl Peripheral<P = impl G7IO2Pin<T>> + 'd>,
-        // g7_d3: Option<impl Peripheral<P = impl G7IO3Pin<T>> + 'd>,
-        // g7_d4: Option<impl Peripheral<P = impl G7IO4Pin<T>> + 'd>,
-
-        // g8_d1: Option<impl Peripheral<P = impl G8IO1Pin<T>> + 'd>,
-        // g8_d2: Option<impl Peripheral<P = impl G8IO2Pin<T>> + 'd>,
-        // g8_d3: Option<impl Peripheral<P = impl G8IO3Pin<T>> + 'd>,
-        // g8_d4: Option<impl Peripheral<P = impl G8IO4Pin<T>> + 'd>,
+        g1: Option<PinGroup<'d, T, G1>>,
+        g2: Option<PinGroup<'d, T, G2>>,
+        g3: Option<PinGroup<'d, T, G3>>,
+        g4: Option<PinGroup<'d, T, G4>>,
+        g5: Option<PinGroup<'d, T, G5>>,
+        g6: Option<PinGroup<'d, T, G6>>,
+        #[cfg(any(tsc_v2, tsc_v3))] g7: Option<PinGroup<'d, T, G7>>,
+        #[cfg(tsc_v3)] g8: Option<PinGroup<'d, T, G8>>,
         config: Config,
     ) -> Self {
-        let g1_d2 = g1_d2.unwrap();
-        let g1_d2_pin = g1_d2.pin;
-        let g1_d3 = g1_d3.unwrap();
-        let g1_d3_pin = g1_d3.pin;
-        let g2_d3 = g2_d3.unwrap();
-        let g2_d3_pin = g2_d3.pin;
-        let g2_d4 = g2_d4.unwrap();
-        let g2_d4_pin = g2_d4.pin;
-        let g4_d1 = g4_d1.unwrap();
-        let g4_d1_pin = g4_d1.pin;
-        let g4_d2 = g4_d2.unwrap();
-        let g4_d2_pin = g4_d2.pin;
-        into_ref!(peri, g1_d2_pin, g1_d3_pin, g2_d3_pin, g2_d4_pin, g4_d1_pin, g4_d2_pin);
-
-        // Configure pins
-        match g1_d2.role {
-            PinType::Channel => g1_d2_pin.set_as_af_pull(g1_d2_pin.af_num(), AFType::OutputPushPull, Pull::None),
-            PinType::Sample => g1_d2_pin.set_as_af_pull(g1_d2_pin.af_num(), AFType::OutputOpenDrain, Pull::None),
-            PinType::Shield => g1_d2_pin.set_as_af_pull(g1_d2_pin.af_num(), AFType::OutputPushPull, Pull::None),
-        }
-        match g1_d3.role {
-            PinType::Channel => g1_d3_pin.set_as_af_pull(g1_d3_pin.af_num(), AFType::OutputPushPull, Pull::None),
-            PinType::Sample => g1_d3_pin.set_as_af_pull(g1_d3_pin.af_num(), AFType::OutputOpenDrain, Pull::None),
-            PinType::Shield => g1_d3_pin.set_as_af_pull(g1_d3_pin.af_num(), AFType::OutputPushPull, Pull::None),
-        }
-        let g1 = PinGroup {
-            d1: None,
-            d2: Some(TscPin {
-                pin: g1_d2_pin.map_into(),
-                role: g1_d2.role,
-            }),
-            d3: Some(TscPin {
-                pin: g1_d3_pin.map_into(),
-                role: g1_d3.role,
-            }),
-            d4: None,
-        };
-
-        match g2_d3.role {
-            PinType::Channel => g2_d3_pin.set_as_af_pull(g2_d3_pin.af_num(), AFType::OutputPushPull, Pull::None),
-            PinType::Sample => g2_d3_pin.set_as_af_pull(g2_d3_pin.af_num(), AFType::OutputOpenDrain, Pull::None),
-            PinType::Shield => g2_d3_pin.set_as_af_pull(g2_d3_pin.af_num(), AFType::OutputPushPull, Pull::None),
-        }
-        match g2_d4.role {
-            PinType::Channel => g2_d4_pin.set_as_af_pull(g2_d4_pin.af_num(), AFType::OutputPushPull, Pull::None),
-            PinType::Sample => g2_d4_pin.set_as_af_pull(g2_d4_pin.af_num(), AFType::OutputOpenDrain, Pull::None),
-            PinType::Shield => g2_d4_pin.set_as_af_pull(g2_d4_pin.af_num(), AFType::OutputPushPull, Pull::None),
-        }
-        let g2 = PinGroup {
-            d1: None,
-            d2: None,
-            d3: Some(TscPin {
-                pin: g2_d3_pin.map_into(),
-                role: g2_d3.role,
-            }),
-            d4: Some(TscPin {
-                pin: g2_d4_pin.map_into(),
-                role: g2_d4.role,
-            }),
-        };
-
-        match g4_d1.role {
-            PinType::Channel => g4_d1_pin.set_as_af_pull(g4_d1_pin.af_num(), AFType::OutputPushPull, Pull::None),
-            PinType::Sample => g4_d1_pin.set_as_af_pull(g4_d1_pin.af_num(), AFType::OutputOpenDrain, Pull::None),
-            PinType::Shield => g4_d1_pin.set_as_af_pull(g4_d1_pin.af_num(), AFType::OutputPushPull, Pull::None),
-        }
-        match g4_d2.role {
-            PinType::Channel => g4_d2_pin.set_as_af_pull(g4_d2_pin.af_num(), AFType::OutputPushPull, Pull::None),
-            PinType::Sample => g4_d2_pin.set_as_af_pull(g4_d2_pin.af_num(), AFType::OutputOpenDrain, Pull::None),
-            PinType::Shield => g4_d2_pin.set_as_af_pull(g4_d2_pin.af_num(), AFType::OutputPushPull, Pull::None),
-        }
-        let g4 = PinGroup {
-            d1: Some(TscPin {
-                pin: g4_d1_pin.map_into(),
-                role: g4_d1.role,
-            }),
-            d2: Some(TscPin {
-                pin: g4_d2_pin.map_into(),
-                role: g4_d2.role,
-            }),
-            d3: None,
-            d4: None,
-        };
-
         // Need to check valid pin configuration input
         Self::new_inner(
             peri,
-            Some(g1),
-            Some(g2),
-            None,
-            Some(g4),
-            None,
-            None,
+            g1,
+            g2,
+            g3,
+            g4,
+            g5,
+            g6,
             #[cfg(any(tsc_v2, tsc_v3))]
-            None,
+            g7,
             #[cfg(tsc_v3)]
-            None,
+            g8,
             config,
         )
     }
 
-    // fn configure_pin<'b, G: Pin>(pin: PeripheralRef<'b, G>, role: PinType) {
-    //     match role {
-    //         PinType::Channel => pin.set_as_af_pull(pin.af_num(), AFType::OutputPushPull, Pull::None),
-    //         PinType::Sample => {}
-    //         PinType::Shield => {}
-    //     }
-    // }
-
-    // fn filter_group() -> Option<PinGroup<'d>> {}
     fn extract_groups(io_mask: u32) -> u32 {
         let mut groups: u32 = 0;
         for idx in 0..TSC_NUM_GROUPS {
@@ -360,14 +359,14 @@ impl<'d, T: Instance> Tsc<'d, T> {
 
     fn new_inner(
         peri: impl Peripheral<P = T> + 'd,
-        g1: Option<PinGroup<'d, AnyPin>>,
-        g2: Option<PinGroup<'d, AnyPin>>,
-        g3: Option<PinGroup<'d, AnyPin>>,
-        g4: Option<PinGroup<'d, AnyPin>>,
-        g5: Option<PinGroup<'d, AnyPin>>,
-        g6: Option<PinGroup<'d, AnyPin>>,
-        #[cfg(any(tsc_v2, tsc_v3))] g7: Option<PinGroup<'d, AnyPin>>,
-        #[cfg(tsc_v3)] g8: Option<PinGroup<'d, AnyPin>>,
+        g1: Option<PinGroup<'d, T, G1>>,
+        g2: Option<PinGroup<'d, T, G2>>,
+        g3: Option<PinGroup<'d, T, G3>>,
+        g4: Option<PinGroup<'d, T, G4>>,
+        g5: Option<PinGroup<'d, T, G5>>,
+        g6: Option<PinGroup<'d, T, G6>>,
+        #[cfg(any(tsc_v2, tsc_v3))] g7: Option<PinGroup<'d, T, G7>>,
+        #[cfg(tsc_v3)] g8: Option<PinGroup<'d, T, G8>>,
         config: Config,
     ) -> Self {
         into_ref!(peri);
@@ -404,7 +403,7 @@ impl<'d, T: Instance> Tsc<'d, T> {
         // Disable Schmitt trigger hysteresis on all used TSC IOs
         T::REGS
             .iohcr()
-            .write(|w| w.0 = config.channel_ios | config.shield_ios | config.sampling_ios);
+            .write(|w| w.0 = !(config.channel_ios | config.shield_ios | config.sampling_ios));
 
         // Set channel and shield IOs
         T::REGS.ioccr().write(|w| w.0 = config.channel_ios | config.shield_ios);
@@ -592,8 +591,6 @@ impl<'d, T: Instance> Tsc<'d, T> {
         T::REGS.iogcr(index.into()).read().cnt()
     }
 
-    // pub fn configure_io()
-
     /// Discharge the IOs for subsequent acquisition
     pub fn discharge_io(&mut self, status: bool) {
         // Set the touch sensing IOs in low power mode
@@ -605,7 +602,6 @@ impl<'d, T: Instance> Tsc<'d, T> {
 
 impl<'d, T: Instance> Drop for Tsc<'d, T> {
     fn drop(&mut self) {
-        //  Need to figure out what to do with the IOs
         T::disable();
     }
 }

From 8e92e8718d513298fa87a51e4039ae11a4f6d502 Mon Sep 17 00:00:00 2001
From: Karun <karun@nautilusdefense.com>
Date: Fri, 3 May 2024 12:40:26 -0400
Subject: [PATCH 12/14] Add example documentation

---
 embassy-stm32/src/tsc/mod.rs | 60 ++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
index a37341b31..6b9d8fcf5 100644
--- a/embassy-stm32/src/tsc/mod.rs
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -1,4 +1,64 @@
 //! TSC Peripheral Interface
+//!
+//!
+//! # Example (stm32)
+//! ``` rust, ignore
+//!
+//! let mut device_config = embassy_stm32::Config::default();
+//! {
+//!     device_config.rcc.mux = ClockSrc::MSI(Msirange::RANGE_4MHZ);
+//! }
+//!
+//! let context = embassy_stm32::init(device_config);
+//!
+//! let config = tsc::Config {
+//!     ct_pulse_high_length: ChargeTransferPulseCycle::_2,
+//!     ct_pulse_low_length: ChargeTransferPulseCycle::_2,
+//!     spread_spectrum: false,
+//!     spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
+//!     spread_spectrum_prescaler: false,
+//!     pulse_generator_prescaler: PGPrescalerDivider::_4,
+//!     max_count_value: MaxCount::_8191,
+//!     io_default_mode: false,
+//!     synchro_pin_polarity: false,
+//!     acquisition_mode: false,
+//!     max_count_interrupt: false,
+//!     channel_ios: TscIOPin::Group2Io2 | TscIOPin::Group7Io3,
+//!     shield_ios: TscIOPin::Group1Io3.into(),
+//!     sampling_ios: TscIOPin::Group1Io2 | TscIOPin::Group2Io1 | TscIOPin::Group7Io2,
+//! };
+//!
+//! let mut g1: PinGroup<embassy_stm32::peripherals::TSC, G1> = PinGroup::new();
+//! g1.set_io2(context.PB13, PinType::Sample);
+//! g1.set_io3(context.PB14, PinType::Shield);
+//!
+//! let mut g2: PinGroup<embassy_stm32::peripherals::TSC, G2> = PinGroup::new();
+//! g2.set_io1(context.PB4, PinType::Sample);
+//! g2.set_io2(context.PB5, PinType::Channel);
+//!
+//! let mut g7: PinGroup<embassy_stm32::peripherals::TSC, G7> = PinGroup::new();
+//! g7.set_io2(context.PE3, PinType::Sample);
+//! g7.set_io3(context.PE4, PinType::Channel);
+//!
+//! let mut touch_controller = tsc::Tsc::new(
+//!     context.TSC,
+//!     Some(g1),
+//!     Some(g2),
+//!     None,
+//!     None,
+//!     None,
+//!     None,
+//!     Some(g7),
+//!     None,
+//!     config,
+//! );
+//!
+//! touch_controller.discharge_io(true);
+//! Timer::after_millis(1).await;
+//!
+//! touch_controller.start();
+//!
+//! ```
 
 #![macro_use]
 

From a91f68654473e8ca6030b97ccda98e7fd868716e Mon Sep 17 00:00:00 2001
From: Karun <karun@nautilusdefense.com>
Date: Fri, 3 May 2024 17:29:21 -0400
Subject: [PATCH 13/14] Check group configuration validity

---
 embassy-stm32/src/tsc/mod.rs | 250 ++++++++++++++++++++++++++++++++---
 1 file changed, 233 insertions(+), 17 deletions(-)

diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
index 6b9d8fcf5..17a455558 100644
--- a/embassy-stm32/src/tsc/mod.rs
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -215,10 +215,15 @@ impl Default for Config {
 #[allow(missing_docs)]
 pub struct TscPin<'d, T, C> {
     _pin: PeripheralRef<'d, AnyPin>,
-    _role: PinType,
+    role: PinType,
     phantom: PhantomData<(T, C)>,
 }
 
+enum GroupError {
+    NoSample,
+    ChannelShield,
+}
+
 /// Pin group definition
 /// Pins are organized into groups of four IOs, all groups with a
 /// sampling channel must also have a sampling capacitor channel.
@@ -241,6 +246,119 @@ impl<'d, T: Instance, C> PinGroup<'d, T, C> {
             d4: None,
         }
     }
+
+    fn contains_shield(&self) -> bool {
+        let mut shield_count = 0;
+
+        if let Some(pin) = &self.d1 {
+            if let PinType::Shield = pin.role {
+                shield_count += 1;
+            }
+        }
+
+        if let Some(pin) = &self.d2 {
+            if let PinType::Shield = pin.role {
+                shield_count += 1;
+            }
+        }
+
+        if let Some(pin) = &self.d3 {
+            if let PinType::Shield = pin.role {
+                shield_count += 1;
+            }
+        }
+
+        if let Some(pin) = &self.d4 {
+            if let PinType::Shield = pin.role {
+                shield_count += 1;
+            }
+        }
+
+        shield_count == 1
+    }
+
+    fn check_group(&self) -> Result<(), GroupError> {
+        let mut channel_count = 0;
+        let mut shield_count = 0;
+        let mut sample_count = 0;
+        if let Some(pin) = &self.d1 {
+            match pin.role {
+                PinType::Channel => {
+                    channel_count += 1;
+                }
+                PinType::Shield => {
+                    shield_count += 1;
+                }
+                PinType::Sample => {
+                    sample_count += 1;
+                }
+            }
+        }
+
+        if let Some(pin) = &self.d2 {
+            match pin.role {
+                PinType::Channel => {
+                    channel_count += 1;
+                }
+                PinType::Shield => {
+                    shield_count += 1;
+                }
+                PinType::Sample => {
+                    sample_count += 1;
+                }
+            }
+        }
+
+        if let Some(pin) = &self.d3 {
+            match pin.role {
+                PinType::Channel => {
+                    channel_count += 1;
+                }
+                PinType::Shield => {
+                    shield_count += 1;
+                }
+                PinType::Sample => {
+                    sample_count += 1;
+                }
+            }
+        }
+
+        if let Some(pin) = &self.d4 {
+            match pin.role {
+                PinType::Channel => {
+                    channel_count += 1;
+                }
+                PinType::Shield => {
+                    shield_count += 1;
+                }
+                PinType::Sample => {
+                    sample_count += 1;
+                }
+            }
+        }
+
+        // Every group requires one sampling capacitor
+        if sample_count != 1 {
+            return Err(GroupError::NoSample);
+        }
+
+        // Each group must have at least one shield or channel IO
+        if shield_count == 0 && channel_count == 0 {
+            return Err(GroupError::ChannelShield);
+        }
+
+        // Any group can either contain channel ios or a shield IO
+        if shield_count != 0 && channel_count != 0 {
+            return Err(GroupError::ChannelShield);
+        }
+
+        // No more than one shield IO is allow per group and amongst all groups
+        if shield_count > 1 {
+            return Err(GroupError::ChannelShield);
+        }
+
+        Ok(())
+    }
 }
 
 macro_rules! group_impl {
@@ -261,7 +379,7 @@ macro_rules! group_impl {
                     );
                     self.d1 = Some(TscPin {
                         _pin: pin.map_into(),
-                        _role: role,
+                        role: role,
                         phantom: PhantomData,
                     })
                 })
@@ -282,7 +400,7 @@ macro_rules! group_impl {
                     );
                     self.d2 = Some(TscPin {
                         _pin: pin.map_into(),
-                        _role: role,
+                        role: role,
                         phantom: PhantomData,
                     })
                 })
@@ -303,7 +421,7 @@ macro_rules! group_impl {
                     );
                     self.d3 = Some(TscPin {
                         _pin: pin.map_into(),
-                        _role: role,
+                        role: role,
                         phantom: PhantomData,
                     })
                 })
@@ -324,7 +442,7 @@ macro_rules! group_impl {
                     );
                     self.d4 = Some(TscPin {
                         _pin: pin.map_into(),
-                        _role: role,
+                        role: role,
                         phantom: PhantomData,
                     })
                 })
@@ -391,20 +509,118 @@ impl<'d, T: Instance> Tsc<'d, T> {
         config: Config,
     ) -> Self {
         // Need to check valid pin configuration input
-        Self::new_inner(
-            peri,
-            g1,
-            g2,
-            g3,
-            g4,
-            g5,
-            g6,
+        let g1 = g1.filter(|b| b.check_group().is_ok());
+        let g2 = g2.filter(|b| b.check_group().is_ok());
+        let g3 = g3.filter(|b| b.check_group().is_ok());
+        let g4 = g4.filter(|b| b.check_group().is_ok());
+        let g5 = g5.filter(|b| b.check_group().is_ok());
+        let g6 = g6.filter(|b| b.check_group().is_ok());
+        let g7 = g7.filter(|b| b.check_group().is_ok());
+        let g8 = g8.filter(|b| b.check_group().is_ok());
+
+        match Self::check_shields(
+            &g1,
+            &g2,
+            &g3,
+            &g4,
+            &g5,
+            &g6,
             #[cfg(any(tsc_v2, tsc_v3))]
-            g7,
+            &g7,
             #[cfg(tsc_v3)]
-            g8,
-            config,
-        )
+            &g8,
+        ) {
+            Ok(()) => Self::new_inner(
+                peri,
+                g1,
+                g2,
+                g3,
+                g4,
+                g5,
+                g6,
+                #[cfg(any(tsc_v2, tsc_v3))]
+                g7,
+                #[cfg(tsc_v3)]
+                g8,
+                config,
+            ),
+            Err(_) => Self::new_inner(
+                peri,
+                None,
+                None,
+                None,
+                None,
+                None,
+                None,
+                #[cfg(any(tsc_v2, tsc_v3))]
+                None,
+                #[cfg(tsc_v3)]
+                None,
+                config,
+            ),
+        }
+    }
+
+    fn check_shields(
+        g1: &Option<PinGroup<'d, T, G1>>,
+        g2: &Option<PinGroup<'d, T, G2>>,
+        g3: &Option<PinGroup<'d, T, G3>>,
+        g4: &Option<PinGroup<'d, T, G4>>,
+        g5: &Option<PinGroup<'d, T, G5>>,
+        g6: &Option<PinGroup<'d, T, G6>>,
+        #[cfg(any(tsc_v2, tsc_v3))] g7: &Option<PinGroup<'d, T, G7>>,
+        #[cfg(tsc_v3)] g8: &Option<PinGroup<'d, T, G8>>,
+    ) -> Result<(), GroupError> {
+        let mut shield_count = 0;
+
+        if let Some(pin_group) = g1 {
+            if pin_group.contains_shield() {
+                shield_count += 1;
+            }
+        };
+        if let Some(pin_group) = g2 {
+            if pin_group.contains_shield() {
+                shield_count += 1;
+            }
+        };
+        if let Some(pin_group) = g3 {
+            if pin_group.contains_shield() {
+                shield_count += 1;
+            }
+        };
+        if let Some(pin_group) = g4 {
+            if pin_group.contains_shield() {
+                shield_count += 1;
+            }
+        };
+        if let Some(pin_group) = g5 {
+            if pin_group.contains_shield() {
+                shield_count += 1;
+            }
+        };
+        if let Some(pin_group) = g6 {
+            if pin_group.contains_shield() {
+                shield_count += 1;
+            }
+        };
+        #[cfg(any(tsc_v2, tsc_v3))]
+        if let Some(pin_group) = g7 {
+            if pin_group.contains_shield() {
+                shield_count += 1;
+            }
+        };
+        #[cfg(tsc_v3)]
+        if let Some(pin_group) = g8 {
+            if pin_group.contains_shield() {
+                shield_count += 1;
+            }
+        };
+
+        if shield_count > 1 {
+            return Err(GroupError::ChannelShield);
+        }
+
+        Ok(())
     }
 
     fn extract_groups(io_mask: u32) -> u32 {

From 07c2f169f50bb6cf52cfd3b2a815cfb7c2d34aa8 Mon Sep 17 00:00:00 2001
From: Karun <karun@nautilusdefense.com>
Date: Fri, 3 May 2024 19:47:42 -0400
Subject: [PATCH 14/14] Add versioning for group checks

---
 embassy-stm32/src/tsc/mod.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
index 17a455558..bf583f04c 100644
--- a/embassy-stm32/src/tsc/mod.rs
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -515,7 +515,9 @@ impl<'d, T: Instance> Tsc<'d, T> {
         let g4 = g4.filter(|b| b.check_group().is_ok());
         let g5 = g5.filter(|b| b.check_group().is_ok());
         let g6 = g6.filter(|b| b.check_group().is_ok());
+        #[cfg(any(tsc_v2, tsc_v3))]
         let g7 = g7.filter(|b| b.check_group().is_ok());
+        #[cfg(tsc_v3)]
         let g8 = g8.filter(|b| b.check_group().is_ok());
 
         match Self::check_shields(