658 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			658 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| //! TSC Peripheral Interface
 | |
| 
 | |
| #![macro_use]
 | |
| 
 | |
| /// 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};
 | |
| 
 | |
| const TSC_NUM_GROUPS: u32 = 8;
 | |
| 
 | |
| /// Error type defined for TSC
 | |
| #[derive(Debug)]
 | |
| #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | |
| pub enum Error {
 | |
|     /// Test error for TSC
 | |
|     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,
 | |
|     Three,
 | |
|     Four,
 | |
|     Five,
 | |
|     Six,
 | |
|     #[cfg(any(tsc_v2, tsc_v3))]
 | |
|     Seven,
 | |
|     #[cfg(tsc_v3)]
 | |
|     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,
 | |
|             #[cfg(any(tsc_v2, tsc_v3))]
 | |
|             Group::Seven => 6,
 | |
|             #[cfg(tsc_v3)]
 | |
|             Group::Eight => 7,
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// 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: 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
 | |
|     pub pulse_generator_prescaler: PGPrescalerDivider,
 | |
|     /// 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,
 | |
|     /// 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 {
 | |
|     fn default() -> Self {
 | |
|         Self {
 | |
|             ct_pulse_high_length: ChargeTransferPulseCycle::_1,
 | |
|             ct_pulse_low_length: ChargeTransferPulseCycle::_1,
 | |
|             spread_spectrum: false,
 | |
|             spread_spectrum_deviation: SSDeviation::new(0).unwrap(),
 | |
|             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,
 | |
|             channel_ios: 0,
 | |
|             shield_ios: 0,
 | |
|             sampling_ios: 0,
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// 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,
 | |
| }
 | |
| 
 | |
| /// 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>>,
 | |
|     _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>>,
 | |
|     state: State,
 | |
|     config: Config,
 | |
| }
 | |
| 
 | |
| 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>,
 | |
|         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,
 | |
|             #[cfg(any(tsc_v2, tsc_v3))]
 | |
|             None,
 | |
|             #[cfg(tsc_v3)]
 | |
|             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;
 | |
|         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,
 | |
|         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>>,
 | |
|         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);
 | |
|             // 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_mcv(config.max_count_value.into());
 | |
|             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()
 | |
|             .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);
 | |
| 
 | |
|         // Set sampling IOs
 | |
|         T::REGS.ioscr().write(|w| w.0 = config.sampling_ios);
 | |
| 
 | |
|         // Set the groups to be acquired
 | |
|         T::REGS
 | |
|             .iogcsr()
 | |
|             .write(|w| w.0 = Self::extract_groups(config.channel_ios));
 | |
| 
 | |
|         // 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,
 | |
|             _g1: g1,
 | |
|             _g2: g2,
 | |
|             _g3: g3,
 | |
|             _g4: g4,
 | |
|             _g5: g5,
 | |
|             _g6: g6,
 | |
|             #[cfg(any(tsc_v2, tsc_v3))]
 | |
|             _g7: g7,
 | |
|             #[cfg(tsc_v3)]
 | |
|             _g8: g8,
 | |
|             state: State::Ready,
 | |
|             config,
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Start charge transfer acquisition
 | |
|     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);
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     /// Start charge transfer acquisition with interrupts enabled
 | |
|     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);
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     /// Stop charge transfer acquisition
 | |
|     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;
 | |
|     }
 | |
| 
 | |
|     /// Stop charge transfer acquisition and clear interrupts
 | |
|     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;
 | |
|     }
 | |
| 
 | |
|     /// 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() {
 | |
|                 if T::REGS.isr().read().mcef() {
 | |
|                     self.state = State::Error
 | |
|                 } else {
 | |
|                     self.state = State::Ready
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         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
 | |
|         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(),
 | |
|             #[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 {
 | |
|             true => GroupStatus::Complete,
 | |
|             false => GroupStatus::Ongoing,
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// 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| {
 | |
|             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);
 |