aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-05-21 20:55:41 +0000
committerGitHub <[email protected]>2024-05-21 20:55:41 +0000
commit2d8ec70f7160a3672e5f8fd9e9751814429bfd8e (patch)
tree78fb6094659b91a208e0a16495610ffb845b9757
parente85242af2c638b41772029a28be4a64bf43922dc (diff)
parent07c2f169f50bb6cf52cfd3b2a815cfb7c2d34aa8 (diff)
Merge pull request #2853 from nautd/kkoppul2/tsc
TSC implementation
-rw-r--r--embassy-stm32/build.rs32
-rw-r--r--embassy-stm32/src/lib.rs2
-rw-r--r--embassy-stm32/src/tsc/enums.rs238
-rw-r--r--embassy-stm32/src/tsc/mod.rs936
4 files changed, 1208 insertions, 0 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index e615c6307..4eed6fe7d 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -1091,6 +1091,38 @@ fn main() {
1091 (("octospi", "NCS"), quote!(crate::ospi::NSSPin)), 1091 (("octospi", "NCS"), quote!(crate::ospi::NSSPin)),
1092 (("octospi", "CLK"), quote!(crate::ospi::SckPin)), 1092 (("octospi", "CLK"), quote!(crate::ospi::SckPin)),
1093 (("octospi", "NCLK"), quote!(crate::ospi::NckPin)), 1093 (("octospi", "NCLK"), quote!(crate::ospi::NckPin)),
1094 (("tsc", "G1_IO1"), quote!(crate::tsc::G1IO1Pin)),
1095 (("tsc", "G1_IO2"), quote!(crate::tsc::G1IO2Pin)),
1096 (("tsc", "G1_IO3"), quote!(crate::tsc::G1IO3Pin)),
1097 (("tsc", "G1_IO4"), quote!(crate::tsc::G1IO4Pin)),
1098 (("tsc", "G2_IO1"), quote!(crate::tsc::G2IO1Pin)),
1099 (("tsc", "G2_IO2"), quote!(crate::tsc::G2IO2Pin)),
1100 (("tsc", "G2_IO3"), quote!(crate::tsc::G2IO3Pin)),
1101 (("tsc", "G2_IO4"), quote!(crate::tsc::G2IO4Pin)),
1102 (("tsc", "G3_IO1"), quote!(crate::tsc::G3IO1Pin)),
1103 (("tsc", "G3_IO2"), quote!(crate::tsc::G3IO2Pin)),
1104 (("tsc", "G3_IO3"), quote!(crate::tsc::G3IO3Pin)),
1105 (("tsc", "G3_IO4"), quote!(crate::tsc::G3IO4Pin)),
1106 (("tsc", "G4_IO1"), quote!(crate::tsc::G4IO1Pin)),
1107 (("tsc", "G4_IO2"), quote!(crate::tsc::G4IO2Pin)),
1108 (("tsc", "G4_IO3"), quote!(crate::tsc::G4IO3Pin)),
1109 (("tsc", "G4_IO4"), quote!(crate::tsc::G4IO4Pin)),
1110 (("tsc", "G5_IO1"), quote!(crate::tsc::G5IO1Pin)),
1111 (("tsc", "G5_IO2"), quote!(crate::tsc::G5IO2Pin)),
1112 (("tsc", "G5_IO3"), quote!(crate::tsc::G5IO3Pin)),
1113 (("tsc", "G5_IO4"), quote!(crate::tsc::G5IO4Pin)),
1114 (("tsc", "G6_IO1"), quote!(crate::tsc::G6IO1Pin)),
1115 (("tsc", "G6_IO2"), quote!(crate::tsc::G6IO2Pin)),
1116 (("tsc", "G6_IO3"), quote!(crate::tsc::G6IO3Pin)),
1117 (("tsc", "G6_IO4"), quote!(crate::tsc::G6IO4Pin)),
1118 (("tsc", "G7_IO1"), quote!(crate::tsc::G7IO1Pin)),
1119 (("tsc", "G7_IO2"), quote!(crate::tsc::G7IO2Pin)),
1120 (("tsc", "G7_IO3"), quote!(crate::tsc::G7IO3Pin)),
1121 (("tsc", "G7_IO4"), quote!(crate::tsc::G7IO4Pin)),
1122 (("tsc", "G8_IO1"), quote!(crate::tsc::G8IO1Pin)),
1123 (("tsc", "G8_IO2"), quote!(crate::tsc::G8IO2Pin)),
1124 (("tsc", "G8_IO3"), quote!(crate::tsc::G8IO3Pin)),
1125 (("tsc", "G8_IO4"), quote!(crate::tsc::G8IO4Pin)),
1094 ].into(); 1126 ].into();
1095 1127
1096 for p in METADATA.peripherals { 1128 for p in METADATA.peripherals {
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 029e01480..b4b9d5d12 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -105,6 +105,8 @@ pub mod sai;
105pub mod sdmmc; 105pub mod sdmmc;
106#[cfg(spi)] 106#[cfg(spi)]
107pub mod spi; 107pub mod spi;
108#[cfg(tsc)]
109pub mod tsc;
108#[cfg(ucpd)] 110#[cfg(ucpd)]
109pub mod ucpd; 111pub mod ucpd;
110#[cfg(uid)] 112#[cfg(uid)]
diff --git a/embassy-stm32/src/tsc/enums.rs b/embassy-stm32/src/tsc/enums.rs
new file mode 100644
index 000000000..0d34a43ec
--- /dev/null
+++ b/embassy-stm32/src/tsc/enums.rs
@@ -0,0 +1,238 @@
1use core::ops::BitOr;
2
3/// Pin defines
4#[allow(missing_docs)]
5pub enum TscIOPin {
6 Group1Io1,
7 Group1Io2,
8 Group1Io3,
9 Group1Io4,
10 Group2Io1,
11 Group2Io2,
12 Group2Io3,
13 Group2Io4,
14 Group3Io1,
15 Group3Io2,
16 Group3Io3,
17 Group3Io4,
18 Group4Io1,
19 Group4Io2,
20 Group4Io3,
21 Group4Io4,
22 Group5Io1,
23 Group5Io2,
24 Group5Io3,
25 Group5Io4,
26 Group6Io1,
27 Group6Io2,
28 Group6Io3,
29 Group6Io4,
30 #[cfg(any(tsc_v2, tsc_v3))]
31 Group7Io1,
32 #[cfg(any(tsc_v2, tsc_v3))]
33 Group7Io2,
34 #[cfg(any(tsc_v2, tsc_v3))]
35 Group7Io3,
36 #[cfg(any(tsc_v2, tsc_v3))]
37 Group7Io4,
38 #[cfg(tsc_v3)]
39 Group8Io1,
40 #[cfg(tsc_v3)]
41 Group8Io2,
42 #[cfg(tsc_v3)]
43 Group8Io3,
44 #[cfg(tsc_v3)]
45 Group8Io4,
46}
47
48impl BitOr<TscIOPin> for u32 {
49 type Output = u32;
50 fn bitor(self, rhs: TscIOPin) -> Self::Output {
51 let rhs: u32 = rhs.into();
52 self | rhs
53 }
54}
55
56impl BitOr<u32> for TscIOPin {
57 type Output = u32;
58 fn bitor(self, rhs: u32) -> Self::Output {
59 let val: u32 = self.into();
60 val | rhs
61 }
62}
63
64impl BitOr for TscIOPin {
65 type Output = u32;
66 fn bitor(self, rhs: Self) -> Self::Output {
67 let val: u32 = self.into();
68 let rhs: u32 = rhs.into();
69 val | rhs
70 }
71}
72
73impl Into<u32> for TscIOPin {
74 fn into(self) -> u32 {
75 match self {
76 TscIOPin::Group1Io1 => 0x00000001,
77 TscIOPin::Group1Io2 => 0x00000002,
78 TscIOPin::Group1Io3 => 0x00000004,
79 TscIOPin::Group1Io4 => 0x00000008,
80 TscIOPin::Group2Io1 => 0x00000010,
81 TscIOPin::Group2Io2 => 0x00000020,
82 TscIOPin::Group2Io3 => 0x00000040,
83 TscIOPin::Group2Io4 => 0x00000080,
84 TscIOPin::Group3Io1 => 0x00000100,
85 TscIOPin::Group3Io2 => 0x00000200,
86 TscIOPin::Group3Io3 => 0x00000400,
87 TscIOPin::Group3Io4 => 0x00000800,
88 TscIOPin::Group4Io1 => 0x00001000,
89 TscIOPin::Group4Io2 => 0x00002000,
90 TscIOPin::Group4Io3 => 0x00004000,
91 TscIOPin::Group4Io4 => 0x00008000,
92 TscIOPin::Group5Io1 => 0x00010000,
93 TscIOPin::Group5Io2 => 0x00020000,
94 TscIOPin::Group5Io3 => 0x00040000,
95 TscIOPin::Group5Io4 => 0x00080000,
96 TscIOPin::Group6Io1 => 0x00100000,
97 TscIOPin::Group6Io2 => 0x00200000,
98 TscIOPin::Group6Io3 => 0x00400000,
99 TscIOPin::Group6Io4 => 0x00800000,
100 #[cfg(any(tsc_v2, tsc_v3))]
101 TscIOPin::Group7Io1 => 0x01000000,
102 #[cfg(any(tsc_v2, tsc_v3))]
103 TscIOPin::Group7Io2 => 0x02000000,
104 #[cfg(any(tsc_v2, tsc_v3))]
105 TscIOPin::Group7Io3 => 0x04000000,
106 #[cfg(any(tsc_v2, tsc_v3))]
107 TscIOPin::Group7Io4 => 0x08000000,
108 #[cfg(tsc_v3)]
109 TscIOPin::Group8Io1 => 0x10000000,
110 #[cfg(tsc_v3)]
111 TscIOPin::Group8Io2 => 0x20000000,
112 #[cfg(tsc_v3)]
113 TscIOPin::Group8Io3 => 0x40000000,
114 #[cfg(tsc_v3)]
115 TscIOPin::Group8Io4 => 0x80000000,
116 }
117 }
118}
119
120/// Spread Spectrum Deviation
121#[derive(Copy, Clone)]
122pub struct SSDeviation(u8);
123impl SSDeviation {
124 /// Create new deviation value, acceptable inputs are 1-128
125 pub fn new(val: u8) -> Result<Self, ()> {
126 if val == 0 || val > 128 {
127 return Err(());
128 }
129 Ok(Self(val - 1))
130 }
131}
132
133impl Into<u8> for SSDeviation {
134 fn into(self) -> u8 {
135 self.0
136 }
137}
138
139/// Charge transfer pulse cycles
140#[allow(missing_docs)]
141#[derive(Copy, Clone, PartialEq)]
142pub enum ChargeTransferPulseCycle {
143 _1,
144 _2,
145 _3,
146 _4,
147 _5,
148 _6,
149 _7,
150 _8,
151 _9,
152 _10,
153 _11,
154 _12,
155 _13,
156 _14,
157 _15,
158 _16,
159}
160
161impl Into<u8> for ChargeTransferPulseCycle {
162 fn into(self) -> u8 {
163 match self {
164 ChargeTransferPulseCycle::_1 => 0,
165 ChargeTransferPulseCycle::_2 => 1,
166 ChargeTransferPulseCycle::_3 => 2,
167 ChargeTransferPulseCycle::_4 => 3,
168 ChargeTransferPulseCycle::_5 => 4,
169 ChargeTransferPulseCycle::_6 => 5,
170 ChargeTransferPulseCycle::_7 => 6,
171 ChargeTransferPulseCycle::_8 => 7,
172 ChargeTransferPulseCycle::_9 => 8,
173 ChargeTransferPulseCycle::_10 => 9,
174 ChargeTransferPulseCycle::_11 => 10,
175 ChargeTransferPulseCycle::_12 => 11,
176 ChargeTransferPulseCycle::_13 => 12,
177 ChargeTransferPulseCycle::_14 => 13,
178 ChargeTransferPulseCycle::_15 => 14,
179 ChargeTransferPulseCycle::_16 => 15,
180 }
181 }
182}
183
184/// Prescaler divider
185#[allow(missing_docs)]
186#[derive(Copy, Clone, PartialEq)]
187pub enum PGPrescalerDivider {
188 _1,
189 _2,
190 _4,
191 _8,
192 _16,
193 _32,
194 _64,
195 _128,
196}
197
198impl Into<u8> for PGPrescalerDivider {
199 fn into(self) -> u8 {
200 match self {
201 PGPrescalerDivider::_1 => 0,
202 PGPrescalerDivider::_2 => 1,
203 PGPrescalerDivider::_4 => 2,
204 PGPrescalerDivider::_8 => 3,
205 PGPrescalerDivider::_16 => 4,
206 PGPrescalerDivider::_32 => 5,
207 PGPrescalerDivider::_64 => 6,
208 PGPrescalerDivider::_128 => 7,
209 }
210 }
211}
212
213/// Max count
214#[allow(missing_docs)]
215#[derive(Copy, Clone)]
216pub enum MaxCount {
217 _255,
218 _511,
219 _1023,
220 _2047,
221 _4095,
222 _8191,
223 _16383,
224}
225
226impl Into<u8> for MaxCount {
227 fn into(self) -> u8 {
228 match self {
229 MaxCount::_255 => 0,
230 MaxCount::_511 => 1,
231 MaxCount::_1023 => 2,
232 MaxCount::_2047 => 3,
233 MaxCount::_4095 => 4,
234 MaxCount::_8191 => 5,
235 MaxCount::_16383 => 6,
236 }
237 }
238}
diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
new file mode 100644
index 000000000..bf583f04c
--- /dev/null
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -0,0 +1,936 @@
1//! TSC Peripheral Interface
2//!
3//!
4//! # Example (stm32)
5//! ``` rust, ignore
6//!
7//! let mut device_config = embassy_stm32::Config::default();
8//! {
9//! device_config.rcc.mux = ClockSrc::MSI(Msirange::RANGE_4MHZ);
10//! }
11//!
12//! let context = embassy_stm32::init(device_config);
13//!
14//! let config = tsc::Config {
15//! ct_pulse_high_length: ChargeTransferPulseCycle::_2,
16//! ct_pulse_low_length: ChargeTransferPulseCycle::_2,
17//! spread_spectrum: false,
18//! spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
19//! spread_spectrum_prescaler: false,
20//! pulse_generator_prescaler: PGPrescalerDivider::_4,
21//! max_count_value: MaxCount::_8191,
22//! io_default_mode: false,
23//! synchro_pin_polarity: false,
24//! acquisition_mode: false,
25//! max_count_interrupt: false,
26//! channel_ios: TscIOPin::Group2Io2 | TscIOPin::Group7Io3,
27//! shield_ios: TscIOPin::Group1Io3.into(),
28//! sampling_ios: TscIOPin::Group1Io2 | TscIOPin::Group2Io1 | TscIOPin::Group7Io2,
29//! };
30//!
31//! let mut g1: PinGroup<embassy_stm32::peripherals::TSC, G1> = PinGroup::new();
32//! g1.set_io2(context.PB13, PinType::Sample);
33//! g1.set_io3(context.PB14, PinType::Shield);
34//!
35//! let mut g2: PinGroup<embassy_stm32::peripherals::TSC, G2> = PinGroup::new();
36//! g2.set_io1(context.PB4, PinType::Sample);
37//! g2.set_io2(context.PB5, PinType::Channel);
38//!
39//! let mut g7: PinGroup<embassy_stm32::peripherals::TSC, G7> = PinGroup::new();
40//! g7.set_io2(context.PE3, PinType::Sample);
41//! g7.set_io3(context.PE4, PinType::Channel);
42//!
43//! let mut touch_controller = tsc::Tsc::new(
44//! context.TSC,
45//! Some(g1),
46//! Some(g2),
47//! None,
48//! None,
49//! None,
50//! None,
51//! Some(g7),
52//! None,
53//! config,
54//! );
55//!
56//! touch_controller.discharge_io(true);
57//! Timer::after_millis(1).await;
58//!
59//! touch_controller.start();
60//!
61//! ```
62
63#![macro_use]
64
65/// Enums defined for peripheral parameters
66pub mod enums;
67
68use core::marker::PhantomData;
69
70use embassy_hal_internal::{into_ref, PeripheralRef};
71pub use enums::*;
72
73use crate::gpio::{AFType, AnyPin};
74use crate::pac::tsc::Tsc as Regs;
75use crate::rcc::RccPeripheral;
76use crate::{peripherals, Peripheral};
77
78#[cfg(tsc_v1)]
79const TSC_NUM_GROUPS: u32 = 6;
80#[cfg(tsc_v2)]
81const TSC_NUM_GROUPS: u32 = 7;
82#[cfg(tsc_v3)]
83const TSC_NUM_GROUPS: u32 = 8;
84
85/// Error type defined for TSC
86#[derive(Debug)]
87#[cfg_attr(feature = "defmt", derive(defmt::Format))]
88pub enum Error {
89 /// Test error for TSC
90 Test,
91}
92
93/// Pin type definition to control IO parameters
94pub enum PinType {
95 /// Sensing channel pin connected to an electrode
96 Channel,
97 /// Sampling capacitor pin, one required for every pin group
98 Sample,
99 /// Shield pin connected to capacitive sensing shield
100 Shield,
101}
102
103/// Peripheral state
104#[derive(PartialEq, Clone, Copy)]
105pub enum State {
106 /// Peripheral is being setup or reconfigured
107 Reset,
108 /// Ready to start acquisition
109 Ready,
110 /// In process of sensor acquisition
111 Busy,
112 /// Error occured during acquisition
113 Error,
114}
115
116/// Individual group status checked after acquisition reported as complete
117/// For groups with multiple channel pins, may take longer because acquisitions
118/// are done sequentially. Check this status before pulling count for each
119/// sampled channel
120#[derive(PartialEq)]
121pub enum GroupStatus {
122 /// Acquisition for channel still in progress
123 Ongoing,
124 /// Acquisition either not started or complete
125 Complete,
126}
127
128/// Group identifier used to interrogate status
129#[allow(missing_docs)]
130pub enum Group {
131 One,
132 Two,
133 Three,
134 Four,
135 Five,
136 Six,
137 #[cfg(any(tsc_v2, tsc_v3))]
138 Seven,
139 #[cfg(tsc_v3)]
140 Eight,
141}
142
143impl Into<usize> for Group {
144 fn into(self) -> usize {
145 match self {
146 Group::One => 0,
147 Group::Two => 1,
148 Group::Three => 2,
149 Group::Four => 3,
150 Group::Five => 4,
151 Group::Six => 5,
152 #[cfg(any(tsc_v2, tsc_v3))]
153 Group::Seven => 6,
154 #[cfg(tsc_v3)]
155 Group::Eight => 7,
156 }
157 }
158}
159
160/// Peripheral configuration
161#[derive(Clone, Copy)]
162pub struct Config {
163 /// Duration of high state of the charge transfer pulse
164 pub ct_pulse_high_length: ChargeTransferPulseCycle,
165 /// Duration of the low state of the charge transfer pulse
166 pub ct_pulse_low_length: ChargeTransferPulseCycle,
167 /// Enable/disable of spread spectrum feature
168 pub spread_spectrum: bool,
169 /// Adds variable number of periods of the SS clk to pulse high state
170 pub spread_spectrum_deviation: SSDeviation,
171 /// Selects AHB clock divider used to generate SS clk
172 pub spread_spectrum_prescaler: bool,
173 /// Selects AHB clock divider used to generate pulse generator clk
174 pub pulse_generator_prescaler: PGPrescalerDivider,
175 /// Maximum number of charge tranfer pulses that can be generated before error
176 pub max_count_value: MaxCount,
177 /// Defines config of all IOs when no ongoing acquisition
178 pub io_default_mode: bool,
179 /// Polarity of sync input pin
180 pub synchro_pin_polarity: bool,
181 /// Acquisition starts when start bit is set or with sync pin input
182 pub acquisition_mode: bool,
183 /// Enable max count interrupt
184 pub max_count_interrupt: bool,
185 /// Channel IO mask
186 pub channel_ios: u32,
187 /// Shield IO mask
188 pub shield_ios: u32,
189 /// Sampling IO mask
190 pub sampling_ios: u32,
191}
192
193impl Default for Config {
194 fn default() -> Self {
195 Self {
196 ct_pulse_high_length: ChargeTransferPulseCycle::_1,
197 ct_pulse_low_length: ChargeTransferPulseCycle::_1,
198 spread_spectrum: false,
199 spread_spectrum_deviation: SSDeviation::new(1).unwrap(),
200 spread_spectrum_prescaler: false,
201 pulse_generator_prescaler: PGPrescalerDivider::_1,
202 max_count_value: MaxCount::_255,
203 io_default_mode: false,
204 synchro_pin_polarity: false,
205 acquisition_mode: false,
206 max_count_interrupt: false,
207 channel_ios: 0,
208 shield_ios: 0,
209 sampling_ios: 0,
210 }
211 }
212}
213
214/// Pin struct that maintains usage
215#[allow(missing_docs)]
216pub struct TscPin<'d, T, C> {
217 _pin: PeripheralRef<'d, AnyPin>,
218 role: PinType,
219 phantom: PhantomData<(T, C)>,
220}
221
222enum GroupError {
223 NoSample,
224 ChannelShield,
225}
226
227/// Pin group definition
228/// Pins are organized into groups of four IOs, all groups with a
229/// sampling channel must also have a sampling capacitor channel.
230#[allow(missing_docs)]
231#[derive(Default)]
232pub struct PinGroup<'d, T, C> {
233 d1: Option<TscPin<'d, T, C>>,
234 d2: Option<TscPin<'d, T, C>>,
235 d3: Option<TscPin<'d, T, C>>,
236 d4: Option<TscPin<'d, T, C>>,
237}
238
239impl<'d, T: Instance, C> PinGroup<'d, T, C> {
240 /// Create new sensing group
241 pub fn new() -> Self {
242 Self {
243 d1: None,
244 d2: None,
245 d3: None,
246 d4: None,
247 }
248 }
249
250 fn contains_shield(&self) -> bool {
251 let mut shield_count = 0;
252
253 if let Some(pin) = &self.d1 {
254 if let PinType::Shield = pin.role {
255 shield_count += 1;
256 }
257 }
258
259 if let Some(pin) = &self.d2 {
260 if let PinType::Shield = pin.role {
261 shield_count += 1;
262 }
263 }
264
265 if let Some(pin) = &self.d3 {
266 if let PinType::Shield = pin.role {
267 shield_count += 1;
268 }
269 }
270
271 if let Some(pin) = &self.d4 {
272 if let PinType::Shield = pin.role {
273 shield_count += 1;
274 }
275 }
276
277 shield_count == 1
278 }
279
280 fn check_group(&self) -> Result<(), GroupError> {
281 let mut channel_count = 0;
282 let mut shield_count = 0;
283 let mut sample_count = 0;
284 if let Some(pin) = &self.d1 {
285 match pin.role {
286 PinType::Channel => {
287 channel_count += 1;
288 }
289 PinType::Shield => {
290 shield_count += 1;
291 }
292 PinType::Sample => {
293 sample_count += 1;
294 }
295 }
296 }
297
298 if let Some(pin) = &self.d2 {
299 match pin.role {
300 PinType::Channel => {
301 channel_count += 1;
302 }
303 PinType::Shield => {
304 shield_count += 1;
305 }
306 PinType::Sample => {
307 sample_count += 1;
308 }
309 }
310 }
311
312 if let Some(pin) = &self.d3 {
313 match pin.role {
314 PinType::Channel => {
315 channel_count += 1;
316 }
317 PinType::Shield => {
318 shield_count += 1;
319 }
320 PinType::Sample => {
321 sample_count += 1;
322 }
323 }
324 }
325
326 if let Some(pin) = &self.d4 {
327 match pin.role {
328 PinType::Channel => {
329 channel_count += 1;
330 }
331 PinType::Shield => {
332 shield_count += 1;
333 }
334 PinType::Sample => {
335 sample_count += 1;
336 }
337 }
338 }
339
340 // Every group requires one sampling capacitor
341 if sample_count != 1 {
342 return Err(GroupError::NoSample);
343 }
344
345 // Each group must have at least one shield or channel IO
346 if shield_count == 0 && channel_count == 0 {
347 return Err(GroupError::ChannelShield);
348 }
349
350 // Any group can either contain channel ios or a shield IO
351 if shield_count != 0 && channel_count != 0 {
352 return Err(GroupError::ChannelShield);
353 }
354
355 // No more than one shield IO is allow per group and amongst all groups
356 if shield_count > 1 {
357 return Err(GroupError::ChannelShield);
358 }
359
360 Ok(())
361 }
362}
363
364macro_rules! group_impl {
365 ($group:ident, $trait1:ident, $trait2:ident, $trait3:ident, $trait4:ident) => {
366 impl<'d, T: Instance> PinGroup<'d, T, $group> {
367 #[doc = concat!("Create a new pin1 for ", stringify!($group), " TSC group instance.")]
368 pub fn set_io1(&mut self, pin: impl Peripheral<P = impl $trait1<T>> + 'd, role: PinType) {
369 into_ref!(pin);
370 critical_section::with(|_| {
371 pin.set_low();
372 pin.set_as_af(
373 pin.af_num(),
374 match role {
375 PinType::Channel => AFType::OutputPushPull,
376 PinType::Sample => AFType::OutputOpenDrain,
377 PinType::Shield => AFType::OutputPushPull,
378 },
379 );
380 self.d1 = Some(TscPin {
381 _pin: pin.map_into(),
382 role: role,
383 phantom: PhantomData,
384 })
385 })
386 }
387
388 #[doc = concat!("Create a new pin2 for ", stringify!($group), " TSC group instance.")]
389 pub fn set_io2(&mut self, pin: impl Peripheral<P = impl $trait2<T>> + 'd, role: PinType) {
390 into_ref!(pin);
391 critical_section::with(|_| {
392 pin.set_low();
393 pin.set_as_af(
394 pin.af_num(),
395 match role {
396 PinType::Channel => AFType::OutputPushPull,
397 PinType::Sample => AFType::OutputOpenDrain,
398 PinType::Shield => AFType::OutputPushPull,
399 },
400 );
401 self.d2 = Some(TscPin {
402 _pin: pin.map_into(),
403 role: role,
404 phantom: PhantomData,
405 })
406 })
407 }
408
409 #[doc = concat!("Create a new pin3 for ", stringify!($group), " TSC group instance.")]
410 pub fn set_io3(&mut self, pin: impl Peripheral<P = impl $trait3<T>> + 'd, role: PinType) {
411 into_ref!(pin);
412 critical_section::with(|_| {
413 pin.set_low();
414 pin.set_as_af(
415 pin.af_num(),
416 match role {
417 PinType::Channel => AFType::OutputPushPull,
418 PinType::Sample => AFType::OutputOpenDrain,
419 PinType::Shield => AFType::OutputPushPull,
420 },
421 );
422 self.d3 = Some(TscPin {
423 _pin: pin.map_into(),
424 role: role,
425 phantom: PhantomData,
426 })
427 })
428 }
429
430 #[doc = concat!("Create a new pin4 for ", stringify!($group), " TSC group instance.")]
431 pub fn set_io4(&mut self, pin: impl Peripheral<P = impl $trait4<T>> + 'd, role: PinType) {
432 into_ref!(pin);
433 critical_section::with(|_| {
434 pin.set_low();
435 pin.set_as_af(
436 pin.af_num(),
437 match role {
438 PinType::Channel => AFType::OutputPushPull,
439 PinType::Sample => AFType::OutputOpenDrain,
440 PinType::Shield => AFType::OutputPushPull,
441 },
442 );
443 self.d4 = Some(TscPin {
444 _pin: pin.map_into(),
445 role: role,
446 phantom: PhantomData,
447 })
448 })
449 }
450 }
451 };
452}
453
454group_impl!(G1, G1IO1Pin, G1IO2Pin, G1IO3Pin, G1IO4Pin);
455group_impl!(G2, G2IO1Pin, G2IO2Pin, G2IO3Pin, G2IO4Pin);
456group_impl!(G3, G3IO1Pin, G3IO2Pin, G3IO3Pin, G3IO4Pin);
457group_impl!(G4, G4IO1Pin, G4IO2Pin, G4IO3Pin, G4IO4Pin);
458group_impl!(G5, G5IO1Pin, G5IO2Pin, G5IO3Pin, G5IO4Pin);
459group_impl!(G6, G6IO1Pin, G6IO2Pin, G6IO3Pin, G6IO4Pin);
460group_impl!(G7, G7IO1Pin, G7IO2Pin, G7IO3Pin, G7IO4Pin);
461group_impl!(G8, G8IO1Pin, G8IO2Pin, G8IO3Pin, G8IO4Pin);
462
463/// Group 1 marker type.
464pub enum G1 {}
465/// Group 2 marker type.
466pub enum G2 {}
467/// Group 3 marker type.
468pub enum G3 {}
469/// Group 4 marker type.
470pub enum G4 {}
471/// Group 5 marker type.
472pub enum G5 {}
473/// Group 6 marker type.
474pub enum G6 {}
475/// Group 7 marker type.
476pub enum G7 {}
477/// Group 8 marker type.
478pub enum G8 {}
479
480/// TSC driver
481pub struct Tsc<'d, T: Instance> {
482 _peri: PeripheralRef<'d, T>,
483 _g1: Option<PinGroup<'d, T, G1>>,
484 _g2: Option<PinGroup<'d, T, G2>>,
485 _g3: Option<PinGroup<'d, T, G3>>,
486 _g4: Option<PinGroup<'d, T, G4>>,
487 _g5: Option<PinGroup<'d, T, G5>>,
488 _g6: Option<PinGroup<'d, T, G6>>,
489 #[cfg(any(tsc_v2, tsc_v3))]
490 _g7: Option<PinGroup<'d, T, G7>>,
491 #[cfg(tsc_v3)]
492 _g8: Option<PinGroup<'d, T, G8>>,
493 state: State,
494 config: Config,
495}
496
497impl<'d, T: Instance> Tsc<'d, T> {
498 /// Create new TSC driver
499 pub fn new(
500 peri: impl Peripheral<P = T> + 'd,
501 g1: Option<PinGroup<'d, T, G1>>,
502 g2: Option<PinGroup<'d, T, G2>>,
503 g3: Option<PinGroup<'d, T, G3>>,
504 g4: Option<PinGroup<'d, T, G4>>,
505 g5: Option<PinGroup<'d, T, G5>>,
506 g6: Option<PinGroup<'d, T, G6>>,
507 #[cfg(any(tsc_v2, tsc_v3))] g7: Option<PinGroup<'d, T, G7>>,
508 #[cfg(tsc_v3)] g8: Option<PinGroup<'d, T, G8>>,
509 config: Config,
510 ) -> Self {
511 // Need to check valid pin configuration input
512 let g1 = g1.filter(|b| b.check_group().is_ok());
513 let g2 = g2.filter(|b| b.check_group().is_ok());
514 let g3 = g3.filter(|b| b.check_group().is_ok());
515 let g4 = g4.filter(|b| b.check_group().is_ok());
516 let g5 = g5.filter(|b| b.check_group().is_ok());
517 let g6 = g6.filter(|b| b.check_group().is_ok());
518 #[cfg(any(tsc_v2, tsc_v3))]
519 let g7 = g7.filter(|b| b.check_group().is_ok());
520 #[cfg(tsc_v3)]
521 let g8 = g8.filter(|b| b.check_group().is_ok());
522
523 match Self::check_shields(
524 &g1,
525 &g2,
526 &g3,
527 &g4,
528 &g5,
529 &g6,
530 #[cfg(any(tsc_v2, tsc_v3))]
531 &g7,
532 #[cfg(tsc_v3)]
533 &g8,
534 ) {
535 Ok(()) => Self::new_inner(
536 peri,
537 g1,
538 g2,
539 g3,
540 g4,
541 g5,
542 g6,
543 #[cfg(any(tsc_v2, tsc_v3))]
544 g7,
545 #[cfg(tsc_v3)]
546 g8,
547 config,
548 ),
549 Err(_) => Self::new_inner(
550 peri,
551 None,
552 None,
553 None,
554 None,
555 None,
556 None,
557 #[cfg(any(tsc_v2, tsc_v3))]
558 None,
559 #[cfg(tsc_v3)]
560 None,
561 config,
562 ),
563 }
564 }
565
566 fn check_shields(
567 g1: &Option<PinGroup<'d, T, G1>>,
568 g2: &Option<PinGroup<'d, T, G2>>,
569 g3: &Option<PinGroup<'d, T, G3>>,
570 g4: &Option<PinGroup<'d, T, G4>>,
571 g5: &Option<PinGroup<'d, T, G5>>,
572 g6: &Option<PinGroup<'d, T, G6>>,
573 #[cfg(any(tsc_v2, tsc_v3))] g7: &Option<PinGroup<'d, T, G7>>,
574 #[cfg(tsc_v3)] g8: &Option<PinGroup<'d, T, G8>>,
575 ) -> Result<(), GroupError> {
576 let mut shield_count = 0;
577
578 if let Some(pin_group) = g1 {
579 if pin_group.contains_shield() {
580 shield_count += 1;
581 }
582 };
583 if let Some(pin_group) = g2 {
584 if pin_group.contains_shield() {
585 shield_count += 1;
586 }
587 };
588 if let Some(pin_group) = g3 {
589 if pin_group.contains_shield() {
590 shield_count += 1;
591 }
592 };
593 if let Some(pin_group) = g4 {
594 if pin_group.contains_shield() {
595 shield_count += 1;
596 }
597 };
598 if let Some(pin_group) = g5 {
599 if pin_group.contains_shield() {
600 shield_count += 1;
601 }
602 };
603 if let Some(pin_group) = g6 {
604 if pin_group.contains_shield() {
605 shield_count += 1;
606 }
607 };
608 #[cfg(any(tsc_v2, tsc_v3))]
609 if let Some(pin_group) = g7 {
610 if pin_group.contains_shield() {
611 shield_count += 1;
612 }
613 };
614 #[cfg(tsc_v3)]
615 if let Some(pin_group) = g8 {
616 if pin_group.contains_shield() {
617 shield_count += 1;
618 }
619 };
620
621 if shield_count > 1 {
622 return Err(GroupError::ChannelShield);
623 }
624
625 Ok(())
626 }
627
628 fn extract_groups(io_mask: u32) -> u32 {
629 let mut groups: u32 = 0;
630 for idx in 0..TSC_NUM_GROUPS {
631 if io_mask & (0x0F << idx * 4) != 0 {
632 groups |= 1 << idx
633 }
634 }
635 groups
636 }
637
638 fn new_inner(
639 peri: impl Peripheral<P = T> + 'd,
640 g1: Option<PinGroup<'d, T, G1>>,
641 g2: Option<PinGroup<'d, T, G2>>,
642 g3: Option<PinGroup<'d, T, G3>>,
643 g4: Option<PinGroup<'d, T, G4>>,
644 g5: Option<PinGroup<'d, T, G5>>,
645 g6: Option<PinGroup<'d, T, G6>>,
646 #[cfg(any(tsc_v2, tsc_v3))] g7: Option<PinGroup<'d, T, G7>>,
647 #[cfg(tsc_v3)] g8: Option<PinGroup<'d, T, G8>>,
648 config: Config,
649 ) -> Self {
650 into_ref!(peri);
651
652 T::enable_and_reset();
653
654 T::REGS.cr().modify(|w| {
655 w.set_tsce(true);
656 w.set_ctph(config.ct_pulse_high_length.into());
657 w.set_ctpl(config.ct_pulse_low_length.into());
658 w.set_sse(config.spread_spectrum);
659 // Prevent invalid configuration for pulse generator prescaler
660 if config.ct_pulse_low_length == ChargeTransferPulseCycle::_1
661 && (config.pulse_generator_prescaler == PGPrescalerDivider::_1
662 || config.pulse_generator_prescaler == PGPrescalerDivider::_2)
663 {
664 w.set_pgpsc(PGPrescalerDivider::_4.into());
665 } else if config.ct_pulse_low_length == ChargeTransferPulseCycle::_2
666 && config.pulse_generator_prescaler == PGPrescalerDivider::_1
667 {
668 w.set_pgpsc(PGPrescalerDivider::_2.into());
669 } else {
670 w.set_pgpsc(config.pulse_generator_prescaler.into());
671 }
672 w.set_ssd(config.spread_spectrum_deviation.into());
673 w.set_sspsc(config.spread_spectrum_prescaler);
674
675 w.set_mcv(config.max_count_value.into());
676 w.set_syncpol(config.synchro_pin_polarity);
677 w.set_am(config.acquisition_mode);
678 });
679
680 // Set IO configuration
681 // Disable Schmitt trigger hysteresis on all used TSC IOs
682 T::REGS
683 .iohcr()
684 .write(|w| w.0 = !(config.channel_ios | config.shield_ios | config.sampling_ios));
685
686 // Set channel and shield IOs
687 T::REGS.ioccr().write(|w| w.0 = config.channel_ios | config.shield_ios);
688
689 // Set sampling IOs
690 T::REGS.ioscr().write(|w| w.0 = config.sampling_ios);
691
692 // Set the groups to be acquired
693 T::REGS
694 .iogcsr()
695 .write(|w| w.0 = Self::extract_groups(config.channel_ios));
696
697 // Disable interrupts
698 T::REGS.ier().modify(|w| {
699 w.set_eoaie(false);
700 w.set_mceie(false);
701 });
702
703 // Clear flags
704 T::REGS.icr().modify(|w| {
705 w.set_eoaic(true);
706 w.set_mceic(true);
707 });
708
709 Self {
710 _peri: peri,
711 _g1: g1,
712 _g2: g2,
713 _g3: g3,
714 _g4: g4,
715 _g5: g5,
716 _g6: g6,
717 #[cfg(any(tsc_v2, tsc_v3))]
718 _g7: g7,
719 #[cfg(tsc_v3)]
720 _g8: g8,
721 state: State::Ready,
722 config,
723 }
724 }
725
726 /// Start charge transfer acquisition
727 pub fn start(&mut self) {
728 self.state = State::Busy;
729
730 // Disable interrupts
731 T::REGS.ier().modify(|w| {
732 w.set_eoaie(false);
733 w.set_mceie(false);
734 });
735
736 // Clear flags
737 T::REGS.icr().modify(|w| {
738 w.set_eoaic(true);
739 w.set_mceic(true);
740 });
741
742 // Set the touch sensing IOs not acquired to the default mode
743 T::REGS.cr().modify(|w| {
744 w.set_iodef(self.config.io_default_mode);
745 });
746
747 // Start the acquisition
748 T::REGS.cr().modify(|w| {
749 w.set_start(true);
750 });
751 }
752
753 /// Start charge transfer acquisition with interrupts enabled
754 pub fn start_it(&mut self) {
755 self.state = State::Busy;
756
757 // Enable interrupts
758 T::REGS.ier().modify(|w| {
759 w.set_eoaie(true);
760 w.set_mceie(self.config.max_count_interrupt);
761 });
762
763 // Clear flags
764 T::REGS.icr().modify(|w| {
765 w.set_eoaic(true);
766 w.set_mceic(true);
767 });
768
769 // Set the touch sensing IOs not acquired to the default mode
770 T::REGS.cr().modify(|w| {
771 w.set_iodef(self.config.io_default_mode);
772 });
773
774 // Start the acquisition
775 T::REGS.cr().modify(|w| {
776 w.set_start(true);
777 });
778 }
779
780 /// Stop charge transfer acquisition
781 pub fn stop(&mut self) {
782 T::REGS.cr().modify(|w| {
783 w.set_start(false);
784 });
785
786 // Set the touch sensing IOs in low power mode
787 T::REGS.cr().modify(|w| {
788 w.set_iodef(false);
789 });
790
791 // Clear flags
792 T::REGS.icr().modify(|w| {
793 w.set_eoaic(true);
794 w.set_mceic(true);
795 });
796
797 self.state = State::Ready;
798 }
799
800 /// Stop charge transfer acquisition and clear interrupts
801 pub fn stop_it(&mut self) {
802 T::REGS.cr().modify(|w| {
803 w.set_start(false);
804 });
805
806 // Set the touch sensing IOs in low power mode
807 T::REGS.cr().modify(|w| {
808 w.set_iodef(false);
809 });
810
811 // Disable interrupts
812 T::REGS.ier().modify(|w| {
813 w.set_eoaie(false);
814 w.set_mceie(false);
815 });
816
817 // Clear flags
818 T::REGS.icr().modify(|w| {
819 w.set_eoaic(true);
820 w.set_mceic(true);
821 });
822
823 self.state = State::Ready;
824 }
825
826 /// Wait for end of acquisition
827 pub fn poll_for_acquisition(&mut self) {
828 while self.get_state() == State::Busy {}
829 }
830
831 /// Get current state of acquisition
832 pub fn get_state(&mut self) -> State {
833 if self.state == State::Busy {
834 if T::REGS.isr().read().eoaf() {
835 if T::REGS.isr().read().mcef() {
836 self.state = State::Error
837 } else {
838 self.state = State::Ready
839 }
840 }
841 }
842 self.state
843 }
844
845 /// Get the individual group status to check acquisition complete
846 pub fn group_get_status(&mut self, index: Group) -> GroupStatus {
847 // Status bits are set by hardware when the acquisition on the corresponding
848 // enabled analog IO group is complete, cleared when new acquisition is started
849 let status = match index {
850 Group::One => T::REGS.iogcsr().read().g1s(),
851 Group::Two => T::REGS.iogcsr().read().g2s(),
852 Group::Three => T::REGS.iogcsr().read().g3s(),
853 Group::Four => T::REGS.iogcsr().read().g4s(),
854 Group::Five => T::REGS.iogcsr().read().g5s(),
855 Group::Six => T::REGS.iogcsr().read().g6s(),
856 #[cfg(any(tsc_v2, tsc_v3))]
857 Group::Seven => T::REGS.iogcsr().read().g7s(),
858 #[cfg(tsc_v3)]
859 Group::Eight => T::REGS.iogcsr().read().g8s(),
860 };
861 match status {
862 true => GroupStatus::Complete,
863 false => GroupStatus::Ongoing,
864 }
865 }
866
867 /// Get the count for the acquisiton, valid once group status is set
868 pub fn group_get_value(&mut self, index: Group) -> u16 {
869 T::REGS.iogcr(index.into()).read().cnt()
870 }
871
872 /// Discharge the IOs for subsequent acquisition
873 pub fn discharge_io(&mut self, status: bool) {
874 // Set the touch sensing IOs in low power mode
875 T::REGS.cr().modify(|w| {
876 w.set_iodef(!status);
877 });
878 }
879}
880
881impl<'d, T: Instance> Drop for Tsc<'d, T> {
882 fn drop(&mut self) {
883 T::disable();
884 }
885}
886
887pub(crate) trait SealedInstance {
888 const REGS: Regs;
889}
890
891/// TSC instance trait
892#[allow(private_bounds)]
893pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {}
894
895foreach_peripheral!(
896 (tsc, $inst:ident) => {
897 impl SealedInstance for peripherals::$inst {
898 const REGS: Regs = crate::pac::$inst;
899 }
900
901 impl Instance for peripherals::$inst {}
902 };
903);
904
905pin_trait!(G1IO1Pin, Instance);
906pin_trait!(G1IO2Pin, Instance);
907pin_trait!(G1IO3Pin, Instance);
908pin_trait!(G1IO4Pin, Instance);
909pin_trait!(G2IO1Pin, Instance);
910pin_trait!(G2IO2Pin, Instance);
911pin_trait!(G2IO3Pin, Instance);
912pin_trait!(G2IO4Pin, Instance);
913pin_trait!(G3IO1Pin, Instance);
914pin_trait!(G3IO2Pin, Instance);
915pin_trait!(G3IO3Pin, Instance);
916pin_trait!(G3IO4Pin, Instance);
917pin_trait!(G4IO1Pin, Instance);
918pin_trait!(G4IO2Pin, Instance);
919pin_trait!(G4IO3Pin, Instance);
920pin_trait!(G4IO4Pin, Instance);
921pin_trait!(G5IO1Pin, Instance);
922pin_trait!(G5IO2Pin, Instance);
923pin_trait!(G5IO3Pin, Instance);
924pin_trait!(G5IO4Pin, Instance);
925pin_trait!(G6IO1Pin, Instance);
926pin_trait!(G6IO2Pin, Instance);
927pin_trait!(G6IO3Pin, Instance);
928pin_trait!(G6IO4Pin, Instance);
929pin_trait!(G7IO1Pin, Instance);
930pin_trait!(G7IO2Pin, Instance);
931pin_trait!(G7IO3Pin, Instance);
932pin_trait!(G7IO4Pin, Instance);
933pin_trait!(G8IO1Pin, Instance);
934pin_trait!(G8IO2Pin, Instance);
935pin_trait!(G8IO3Pin, Instance);
936pin_trait!(G8IO4Pin, Instance);