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 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 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 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 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

+ '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

+ '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

+ 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);