| 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. |
| 77 | pub mod config; |
| 78 | |
| 79 | /// Definitions and implementations for TSC pin groups. |
| 80 | pub mod pin_groups; |
| 81 | |
| 82 | /// Definitions and implementations for individual TSC I/O pins. |
| 83 | pub mod io_pin; |
| 84 | |
| 85 | /// Structures and implementations for TSC acquisition banks. |
| 86 | pub mod acquisition_banks; |
| 87 | |
| 88 | /// Core implementation of the TSC (Touch Sensing Controller) driver. |
| 89 | pub mod tsc; |
| 90 | |
| 91 | /// Type definitions used throughout the TSC module. |
| 92 | pub mod types; |
| 93 | |
| 94 | /// Error types and definitions for the TSC module. |
| 95 | pub mod errors; |
| 96 | |
| 97 | use core::marker::PhantomData; |
| 98 | |
| 99 | pub use acquisition_banks::*; |
| 100 | pub use config::*; |
| 101 | use embassy_sync::waitqueue::AtomicWaker; |
| 102 | pub use errors::*; |
| 103 | pub use io_pin::*; |
| 104 | pub use pin_groups::*; |
| 105 | pub use tsc::*; |
| 106 | pub use types::*; |
| 107 | |
| 108 | use crate::rcc::RccPeripheral; |
| 109 | use crate::{interrupt, peripherals, Peripheral}; |
| 110 | |
| 111 | #[cfg (tsc_v1)] |
| 112 | const TSC_NUM_GROUPS: usize = 6; |
| 113 | #[cfg (tsc_v2)] |
| 114 | const TSC_NUM_GROUPS: usize = 7; |
| 115 | #[cfg (tsc_v3)] |
| 116 | const 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))] |
| 121 | pub enum Error { |
| 122 | /// Test error for TSC |
| 123 | Test, |
| 124 | } |
| 125 | |
| 126 | /// TSC interrupt handler. |
| 127 | pub struct InterruptHandler<T: Instance> { |
| 128 | _phantom: PhantomData<T>, |
| 129 | } |
| 130 | |
| 131 | impl<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 | |
| 138 | pub(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)] |
| 145 | pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral { |
| 146 | /// Interrupt for this TSC instance |
| 147 | type Interrupt: interrupt::typelevel::Interrupt; |
| 148 | } |
| 149 | |
| 150 | foreach_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 | |