1//! TSC Peripheral Interface
2//!
3//! This module provides an interface for the Touch Sensing Controller (TSC) peripheral.
4//! It supports both blocking and async modes of operation, as well as different TSC versions (v1, v2, v3).
5//!
6//! # Key Concepts
7//!
8//! - **Pin Groups**: TSC pins are organized into groups, each containing up to four IOs.
9//! - **Pin Roles**: Each pin in a group can have a role: Channel, Sample, or Shield.
10//! - **Acquisition Banks**: Used for efficient, repeated TSC acquisitions on specific sets of pins.
11//!
12//! # Example (stm32)
13//!
14//! ```rust
15//! let device_config = embassy_stm32::Config::default();
16//! let context = embassy_stm32::init(device_config);
17//!
18//! let config = tsc::Config {
19//! ct_pulse_high_length: ChargeTransferPulseCycle::_4,
20//! ct_pulse_low_length: ChargeTransferPulseCycle::_4,
21//! spread_spectrum: false,
22//! spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
23//! spread_spectrum_prescaler: false,
24//! pulse_generator_prescaler: PGPrescalerDivider::_16,
25//! max_count_value: MaxCount::_255,
26//! io_default_mode: false,
27//! synchro_pin_polarity: false,
28//! acquisition_mode: false,
29//! max_count_interrupt: false,
30//! };
31//!
32//! let mut g2: PinGroupWithRoles<embassy_stm32::peripherals::TSC, G2> = PinGroupWithRoles::new();
33//! g2.set_io1::<tsc_pin_roles::Sample>(context.PB4);
34//! let sensor_pin = g2.set_io2::<tsc_pin_roles::Channel>(context.PB5);
35//!
36//! let pin_groups = PinGroups {
37//! g2: Some(g2.pin_group),
38//! ..Default::default()
39//! };
40//!
41//! let mut touch_controller = tsc::Tsc::new_blocking(
42//! context.TSC,
43//! pin_groups,
44//! config,
45//! ).unwrap();
46//!
47//! let discharge_delay = 5; // ms
48//!
49//! loop {
50//! touch_controller.set_active_channels_mask(sensor_pin.pin.into());
51//! touch_controller.start();
52//! touch_controller.poll_for_acquisition();
53//! touch_controller.discharge_io(true);
54//! Timer::after_millis(discharge_delay).await;
55//!
56//! match touch_controller.group_get_status(sensor_pin.pin.group()) {
57//! GroupStatus::Complete => {
58//! let group_val = touch_controller.group_get_value(sensor_pin.pin.group());
59//! // Process the touch value
60//! // ...
61//! }
62//! GroupStatus::Ongoing => {
63//! // Handle ongoing acquisition
64//! // ...
65//! }
66//! }
67//! }
68//! ```
69//!
70//! # Async Usage
71//!
72//! For async operation, use `Tsc::new_async` and `pend_for_acquisition` instead of polling.
73
74#![macro_use]
75
76/// Configuration structures and enums for the TSC peripheral.
77pub mod config;
78
79/// Definitions and implementations for TSC pin groups.
80pub mod pin_groups;
81
82/// Definitions and implementations for individual TSC I/O pins.
83pub mod io_pin;
84
85/// Structures and implementations for TSC acquisition banks.
86pub mod acquisition_banks;
87
88/// Core implementation of the TSC (Touch Sensing Controller) driver.
89pub mod tsc;
90
91/// Type definitions used throughout the TSC module.
92pub mod types;
93
94/// Error types and definitions for the TSC module.
95pub mod errors;
96
97use core::marker::PhantomData;
98
99pub use acquisition_banks::*;
100pub use config::*;
101use embassy_sync::waitqueue::AtomicWaker;
102pub use errors::*;
103pub use io_pin::*;
104pub use pin_groups::*;
105pub use tsc::*;
106pub use types::*;
107
108use crate::rcc::RccPeripheral;
109use crate::{interrupt, peripherals, Peripheral};
110
111#[cfg(tsc_v1)]
112const TSC_NUM_GROUPS: usize = 6;
113#[cfg(tsc_v2)]
114const TSC_NUM_GROUPS: usize = 7;
115#[cfg(tsc_v3)]
116const TSC_NUM_GROUPS: usize = 8;
117
118/// Error type defined for TSC
119#[derive(Debug, Clone, Copy)]
120#[cfg_attr(feature = "defmt", derive(defmt::Format))]
121pub enum Error {
122 /// Test error for TSC
123 Test,
124}
125
126/// TSC interrupt handler.
127pub struct InterruptHandler<T: Instance> {
128 _phantom: PhantomData<T>,
129}
130
131impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
132 unsafe fn on_interrupt() {
133 T::regs().ier().write(|w: &mut Ier| w.set_eoaie(val:false));
134 T::waker().wake();
135 }
136}
137
138pub(crate) trait SealedInstance {
139 fn regs() -> crate::pac::tsc::Tsc;
140 fn waker() -> &'static AtomicWaker;
141}
142
143/// TSC instance trait
144#[allow(private_bounds)]
145pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {
146 /// Interrupt for this TSC instance
147 type Interrupt: interrupt::typelevel::Interrupt;
148}
149
150foreach_interrupt!(
151 ($inst:ident, tsc, TSC, GLOBAL, $irq:ident) => {
152 impl Instance for peripherals::$inst {
153 type Interrupt = crate::interrupt::typelevel::$irq;
154 }
155
156 impl SealedInstance for peripherals::$inst {
157 fn regs() -> crate::pac::tsc::Tsc {
158 crate::pac::$inst
159 }
160 fn waker() -> &'static AtomicWaker {
161 static WAKER: AtomicWaker = AtomicWaker::new();
162 &WAKER
163 }
164 }
165 };
166);
167