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(