1use core::marker::PhantomData;
2use core::ops::BitOr;
3
4use embassy_hal_internal::{into_ref, PeripheralRef};
5
6use super::errors::GroupError;
7use super::io_pin::*;
8use super::Instance;
9use crate::gpio::{AfType, AnyPin, OutputType, Speed};
10use crate::Peripheral;
11
12/// Pin type definition to control IO parameters
13#[derive(PartialEq, Clone, Copy)]
14pub enum PinType {
15 /// Sensing channel pin connected to an electrode
16 Channel,
17 /// Sampling capacitor pin, one required for every pin group
18 Sample,
19 /// Shield pin connected to capacitive sensing shield
20 Shield,
21}
22
23/// Pin struct that maintains usage
24#[allow(missing_docs)]
25pub struct Pin<'d, T, Group> {
26 _pin: PeripheralRef<'d, AnyPin>,
27 role: PinType,
28 tsc_io_pin: IOPin,
29 phantom: PhantomData<(T, Group)>,
30}
31
32impl<'d, T, Group> Pin<'d, T, Group> {
33 /// Returns the role of this TSC pin.
34 ///
35 /// The role indicates whether this pin is configured as a channel,
36 /// sampling capacitor, or shield in the TSC group.
37 ///
38 /// # Returns
39 /// The `PinType` representing the role of this pin.
40 pub fn role(&self) -> PinType {
41 self.role
42 }
43
44 /// Returns the TSC IO pin associated with this pin.
45 ///
46 /// This method provides access to the specific TSC IO pin configuration,
47 /// which includes information about the pin's group and position within that group.
48 ///
49 /// # Returns
50 /// The `IOPin` representing this pin's TSC-specific configuration.
51 pub fn tsc_io_pin(&self) -> IOPin {
52 self.tsc_io_pin
53 }
54}
55
56/// Represents a group of TSC (Touch Sensing Controller) pins.
57///
58/// In the TSC peripheral, pins are organized into groups of four IOs. Each group
59/// must have exactly one sampling capacitor pin and can have multiple channel pins
60/// or a single shield pin. This structure encapsulates these pin configurations
61/// for a single TSC group.
62///
63/// # Pin Roles
64/// - Sampling Capacitor: One required per group, used for charge transfer.
65/// - Channel: Sensing pins connected to electrodes for touch detection.
66/// - Shield: Optional, used for active shielding to improve sensitivity.
67///
68/// # Constraints
69/// - Each group must have exactly one sampling capacitor pin.
70/// - A group can have either channel pins or a shield pin, but not both.
71/// - No more than one shield pin is allowed across all groups.
72#[allow(missing_docs)]
73pub struct PinGroup<'d, T, Group> {
74 pin1: Option<Pin<'d, T, Group>>,
75 pin2: Option<Pin<'d, T, Group>>,
76 pin3: Option<Pin<'d, T, Group>>,
77 pin4: Option<Pin<'d, T, Group>>,
78}
79
80impl<'d, T, G> Default for PinGroup<'d, T, G> {
81 fn default() -> Self {
82 Self {
83 pin1: None,
84 pin2: None,
85 pin3: None,
86 pin4: None,
87 }
88 }
89}
90
91/// Defines roles and traits for TSC (Touch Sensing Controller) pins.
92///
93/// This module contains marker types and traits that represent different roles
94/// a TSC pin can have, such as channel, sample, or shield.
95pub mod pin_roles {
96 use super::{OutputType, PinType};
97
98 /// Marker type for a TSC channel pin.
99 #[derive(PartialEq, Clone, Copy, Debug)]
100 pub struct Channel;
101
102 /// Marker type for a TSC sampling pin.
103 #[derive(PartialEq, Clone, Copy, Debug)]
104 pub struct Sample;
105
106 /// Marker type for a TSC shield pin.
107 #[derive(PartialEq, Clone, Copy, Debug)]
108 pub struct Shield;
109
110 /// Trait for TSC pin roles.
111 ///
112 /// This trait defines the behavior and properties of different TSC pin roles.
113 /// It is implemented by the marker types `Channel`, `Sample`, and `Shield`.
114 pub trait Role {
115 /// Returns the `PinType` associated with this role.
116 fn pin_type() -> PinType;
117
118 /// Returns the `OutputType` associated with this role.
119 fn output_type() -> OutputType;
120 }
121
122 impl Role for Channel {
123 fn pin_type() -> PinType {
124 PinType::Channel
125 }
126 fn output_type() -> OutputType {
127 OutputType::PushPull
128 }
129 }
130
131 impl Role for Sample {
132 fn pin_type() -> PinType {
133 PinType::Sample
134 }
135 fn output_type() -> OutputType {
136 OutputType::OpenDrain
137 }
138 }
139
140 impl Role for Shield {
141 fn pin_type() -> PinType {
142 PinType::Shield
143 }
144 fn output_type() -> OutputType {
145 OutputType::PushPull
146 }
147 }
148}
149
150/// Represents a group of TSC pins with their associated roles.
151///
152/// This struct allows for type-safe configuration of TSC pin groups,
153/// ensuring that pins are assigned appropriate roles within their group.
154/// This type is essentially just a wrapper type around a `PinGroup` value.
155///
156/// # Type Parameters
157/// - `'d`: Lifetime of the pin group.
158/// - `T`: The TSC instance type.
159/// - `G`: The group identifier.
160/// - `R1`, `R2`, `R3`, `R4`: Role types for each pin in the group, defaulting to `Channel`.
161pub struct PinGroupWithRoles<
162 'd,
163 T: Instance,
164 G,
165 R1 = pin_roles::Channel,
166 R2 = pin_roles::Channel,
167 R3 = pin_roles::Channel,
168 R4 = pin_roles::Channel,
169> {
170 /// The underlying pin group without role information.
171 pub pin_group: PinGroup<'d, T, G>,
172 _phantom: PhantomData<(R1, R2, R3, R4)>,
173}
174
175impl<'d, T: Instance, G, R1, R2, R3, R4> Default for PinGroupWithRoles<'d, T, G, R1, R2, R3, R4> {
176 fn default() -> Self {
177 Self {
178 pin_group: PinGroup::default(),
179 _phantom: PhantomData,
180 }
181 }
182}
183
184impl<'d, T: Instance, G> PinGroup<'d, T, G> {
185 fn contains_exactly_one_shield_pin(&self) -> bool {
186 let shield_count = self.shield_pins().count();
187 shield_count == 1
188 }
189
190 fn check_group(&self) -> Result<(), GroupError> {
191 let mut channel_count = 0;
192 let mut shield_count = 0;
193 let mut sample_count = 0;
194 for pin in self.pins().into_iter().flatten() {
195 match pin.role {
196 PinType::Channel => {
197 channel_count += 1;
198 }
199 PinType::Shield => {
200 shield_count += 1;
201 }
202 PinType::Sample => {
203 sample_count += 1;
204 }
205 }
206 }
207
208 // Every group requires exactly one sampling capacitor
209 if sample_count != 1 {
210 return Err(GroupError::NoSamplingCapacitor);
211 }
212
213 // Each group must have at least one shield or channel IO
214 if shield_count == 0 && channel_count == 0 {
215 return Err(GroupError::NoChannelOrShield);
216 }
217
218 // Any group can either contain channel ios or a shield IO.
219 // (An active shield requires its own sampling capacitor)
220 if shield_count != 0 && channel_count != 0 {
221 return Err(GroupError::MixedChannelAndShield);
222 }
223
224 // No more than one shield IO is allow per group and amongst all groups
225 if shield_count > 1 {
226 return Err(GroupError::MultipleShields);
227 }
228
229 Ok(())
230 }
231
232 /// Returns a reference to the first pin in the group, if configured.
233 pub fn pin1(&self) -> Option<&Pin<'d, T, G>> {
234 self.pin1.as_ref()
235 }
236
237 /// Returns a reference to the second pin in the group, if configured.
238 pub fn pin2(&self) -> Option<&Pin<'d, T, G>> {
239 self.pin2.as_ref()
240 }
241
242 /// Returns a reference to the third pin in the group, if configured.
243 pub fn pin3(&self) -> Option<&Pin<'d, T, G>> {
244 self.pin3.as_ref()
245 }
246
247 /// Returns a reference to the fourth pin in the group, if configured.
248 pub fn pin4(&self) -> Option<&Pin<'d, T, G>> {
249 self.pin4.as_ref()
250 }
251
252 fn sample_pins(&self) -> impl Iterator<Item = IOPin> + '_ {
253 self.pins_filtered(PinType::Sample)
254 }
255
256 fn shield_pins(&self) -> impl Iterator<Item = IOPin> + '_ {
257 self.pins_filtered(PinType::Shield)
258 }
259
260 fn channel_pins(&self) -> impl Iterator<Item = IOPin> + '_ {
261 self.pins_filtered(PinType::Channel)
262 }
263
264 fn pins_filtered(&self, pin_type: PinType) -> impl Iterator<Item = IOPin> + '_ {
265 self.pins().into_iter().filter_map(move |pin| {
266 pin.as_ref()
267 .and_then(|p| if p.role == pin_type { Some(p.tsc_io_pin) } else { None })
268 })
269 }
270
271 fn make_channel_ios_mask(&self) -> u32 {
272 self.channel_pins().fold(0, u32::bitor)
273 }
274
275 fn make_shield_ios_mask(&self) -> u32 {
276 self.shield_pins().fold(0, u32::bitor)
277 }
278
279 fn make_sample_ios_mask(&self) -> u32 {
280 self.sample_pins().fold(0, u32::bitor)
281 }
282
283 fn pins(&self) -> [&Option<Pin<'d, T, G>>; 4] {
284 [&self.pin1, &self.pin2, &self.pin3, &self.pin4]
285 }
286
287 fn pins_mut(&mut self) -> [&mut Option<Pin<'d, T, G>>; 4] {
288 [&mut self.pin1, &mut self.pin2, &mut self.pin3, &mut self.pin4]
289 }
290}
291
292#[cfg(any(tsc_v2, tsc_v3))]
293macro_rules! TSC_V2_V3_GUARD {
294 ($e:expr) => {{
295 #[cfg(any(tsc_v2, tsc_v3))]
296 {
297 $e
298 }
299 #[cfg(not(any(tsc_v2, tsc_v3)))]
300 {
301 compile_error!("Group 7 is not supported in this TSC version")
302 }
303 }};
304}
305
306#[cfg(tsc_v3)]
307macro_rules! TSC_V3_GUARD {
308 ($e:expr) => {{
309 #[cfg(tsc_v3)]
310 {
311 $e
312 }
313 #[cfg(not(tsc_v3))]
314 {
315 compile_error!("Group 8 is not supported in this TSC version")
316 }
317 }};
318}
319
320macro_rules! trait_to_io_pin {
321 (G1IO1Pin) => {
322 IOPin::Group1Io1
323 };
324 (G1IO2Pin) => {
325 IOPin::Group1Io2
326 };
327 (G1IO3Pin) => {
328 IOPin::Group1Io3
329 };
330 (G1IO4Pin) => {
331 IOPin::Group1Io4
332 };
333
334 (G2IO1Pin) => {
335 IOPin::Group2Io1
336 };
337 (G2IO2Pin) => {
338 IOPin::Group2Io2
339 };
340 (G2IO3Pin) => {
341 IOPin::Group2Io3
342 };
343 (G2IO4Pin) => {
344 IOPin::Group2Io4
345 };
346
347 (G3IO1Pin) => {
348 IOPin::Group3Io1
349 };
350 (G3IO2Pin) => {
351 IOPin::Group3Io2
352 };
353 (G3IO3Pin) => {
354 IOPin::Group3Io3
355 };
356 (G3IO4Pin) => {
357 IOPin::Group3Io4
358 };
359
360 (G4IO1Pin) => {
361 IOPin::Group4Io1
362 };
363 (G4IO2Pin) => {
364 IOPin::Group4Io2
365 };
366 (G4IO3Pin) => {
367 IOPin::Group4Io3
368 };
369 (G4IO4Pin) => {
370 IOPin::Group4Io4
371 };
372
373 (G5IO1Pin) => {
374 IOPin::Group5Io1
375 };
376 (G5IO2Pin) => {
377 IOPin::Group5Io2
378 };
379 (G5IO3Pin) => {
380 IOPin::Group5Io3
381 };
382 (G5IO4Pin) => {
383 IOPin::Group5Io4
384 };
385
386 (G6IO1Pin) => {
387 IOPin::Group6Io1
388 };
389 (G6IO2Pin) => {
390 IOPin::Group6Io2
391 };
392 (G6IO3Pin) => {
393 IOPin::Group6Io3
394 };
395 (G6IO4Pin) => {
396 IOPin::Group6Io4
397 };
398
399 (G7IO1Pin) => {
400 TSC_V2_V3_GUARD!(IOPin::Group7Io1)
401 };
402 (G7IO2Pin) => {
403 TSC_V2_V3_GUARD!(IOPin::Group7Io2)
404 };
405 (G7IO3Pin) => {
406 TSC_V2_V3_GUARD!(IOPin::Group7Io3)
407 };
408 (G7IO4Pin) => {
409 TSC_V2_V3_GUARD!(IOPin::Group7Io4)
410 };
411
412 (G8IO1Pin) => {
413 TSC_V3_GUARD!(IOPin::Group8Io1)
414 };
415 (G8IO2Pin) => {
416 TSC_V3_GUARD!(IOPin::Group8Io2)
417 };
418 (G8IO3Pin) => {
419 TSC_V3_GUARD!(IOPin::Group8Io3)
420 };
421 (G8IO4Pin) => {
422 TSC_V3_GUARD!(IOPin::Group8Io4)
423 };
424}
425
426macro_rules! impl_set_io {
427 ($method:ident, $group:ident, $trait:ident, $index:expr) => {
428 #[doc = concat!("Create a new pin1 for ", stringify!($group), " TSC group instance.")]
429 pub fn $method<Role: pin_roles::Role>(
430 &mut self,
431 pin: impl Peripheral<P = impl $trait<T>> + 'd,
432 ) -> IOPinWithRole<$group, Role> {
433 into_ref!(pin);
434 critical_section::with(|_| {
435 pin.set_low();
436 pin.set_as_af(pin.af_num(), AfType::output(Role::output_type(), Speed::VeryHigh));
437 let tsc_io_pin = trait_to_io_pin!($trait);
438 let new_pin = Pin {
439 _pin: pin.map_into(),
440 role: Role::pin_type(),
441 tsc_io_pin,
442 phantom: PhantomData,
443 };
444 *self.pin_group.pins_mut()[$index] = Some(new_pin);
445 IOPinWithRole {
446 pin: tsc_io_pin,
447 phantom: PhantomData,
448 }
449 })
450 }
451 };
452}
453
454macro_rules! group_impl {
455 ($group:ident, $trait1:ident, $trait2:ident, $trait3:ident, $trait4:ident) => {
456 impl<'d, T: Instance, R1: pin_roles::Role, R2: pin_roles::Role, R3: pin_roles::Role, R4: pin_roles::Role>
457 PinGroupWithRoles<'d, T, $group, R1, R2, R3, R4>
458 {
459 impl_set_io!(set_io1, $group, $trait1, 0);
460 impl_set_io!(set_io2, $group, $trait2, 1);
461 impl_set_io!(set_io3, $group, $trait3, 2);
462 impl_set_io!(set_io4, $group, $trait4, 3);
463 }
464 };
465}
466
467group_impl!(G1, G1IO1Pin, G1IO2Pin, G1IO3Pin, G1IO4Pin);
468group_impl!(G2, G2IO1Pin, G2IO2Pin, G2IO3Pin, G2IO4Pin);
469group_impl!(G3, G3IO1Pin, G3IO2Pin, G3IO3Pin, G3IO4Pin);
470group_impl!(G4, G4IO1Pin, G4IO2Pin, G4IO3Pin, G4IO4Pin);
471group_impl!(G5, G5IO1Pin, G5IO2Pin, G5IO3Pin, G5IO4Pin);
472group_impl!(G6, G6IO1Pin, G6IO2Pin, G6IO3Pin, G6IO4Pin);
473#[cfg(any(tsc_v2, tsc_v3))]
474group_impl!(G7, G7IO1Pin, G7IO2Pin, G7IO3Pin, G7IO4Pin);
475#[cfg(tsc_v3)]
476group_impl!(G8, G8IO1Pin, G8IO2Pin, G8IO3Pin, G8IO4Pin);
477
478/// Group 1 marker type.
479#[derive(Clone, Copy, Debug)]
480pub enum G1 {}
481/// Group 2 marker type.
482#[derive(Clone, Copy, Debug)]
483pub enum G2 {}
484/// Group 3 marker type.
485#[derive(Clone, Copy, Debug)]
486pub enum G3 {}
487/// Group 4 marker type.
488#[derive(Clone, Copy, Debug)]
489pub enum G4 {}
490/// Group 5 marker type.
491#[derive(Clone, Copy, Debug)]
492pub enum G5 {}
493/// Group 6 marker type.
494#[derive(Clone, Copy, Debug)]
495pub enum G6 {}
496/// Group 7 marker type.
497#[derive(Clone, Copy, Debug)]
498pub enum G7 {}
499/// Group 8 marker type.
500#[derive(Clone, Copy, Debug)]
501pub enum G8 {}
502
503/// Represents the collection of pin groups for the Touch Sensing Controller (TSC).
504///
505/// Each field corresponds to a specific group of TSC pins:
506#[allow(missing_docs)]
507pub struct PinGroups<'d, T: Instance> {
508 pub g1: Option<PinGroup<'d, T, G1>>,
509 pub g2: Option<PinGroup<'d, T, G2>>,
510 pub g3: Option<PinGroup<'d, T, G3>>,
511 pub g4: Option<PinGroup<'d, T, G4>>,
512 pub g5: Option<PinGroup<'d, T, G5>>,
513 pub g6: Option<PinGroup<'d, T, G6>>,
514 #[cfg(any(tsc_v2, tsc_v3))]
515 pub g7: Option<PinGroup<'d, T, G7>>,
516 #[cfg(tsc_v3)]
517 pub g8: Option<PinGroup<'d, T, G8>>,
518}
519
520impl<'d, T: Instance> PinGroups<'d, T> {
521 pub(super) fn check(&self) -> Result<(), GroupError> {
522 let mut shield_count = 0;
523
524 // Helper function to check a single group
525 fn check_group<C, T: Instance>(
526 group: &Option<PinGroup<'_, T, C>>,
527 shield_count: &mut u32,
528 ) -> Result<(), GroupError> {
529 if let Some(group) = group {
530 group.check_group()?;
531 if group.contains_exactly_one_shield_pin() {
532 *shield_count += 1;
533 if *shield_count > 1 {
534 return Err(GroupError::MultipleShields);
535 }
536 }
537 }
538 Ok(())
539 }
540
541 // Check each group
542 check_group(&self.g1, &mut shield_count)?;
543 check_group(&self.g2, &mut shield_count)?;
544 check_group(&self.g3, &mut shield_count)?;
545 check_group(&self.g4, &mut shield_count)?;
546 check_group(&self.g5, &mut shield_count)?;
547 check_group(&self.g6, &mut shield_count)?;
548 #[cfg(any(tsc_v2, tsc_v3))]
549 check_group(&self.g7, &mut shield_count)?;
550 #[cfg(tsc_v3)]
551 check_group(&self.g8, &mut shield_count)?;
552
553 Ok(())
554 }
555
556 pub(super) fn make_channel_ios_mask(&self) -> u32 {
557 #[allow(unused_mut)]
558 let mut mask = self.g1.as_ref().map_or(0, |g| g.make_channel_ios_mask())
559 | self.g2.as_ref().map_or(0, |g| g.make_channel_ios_mask())
560 | self.g3.as_ref().map_or(0, |g| g.make_channel_ios_mask())
561 | self.g4.as_ref().map_or(0, |g| g.make_channel_ios_mask())
562 | self.g5.as_ref().map_or(0, |g| g.make_channel_ios_mask())
563 | self.g6.as_ref().map_or(0, |g| g.make_channel_ios_mask());
564 #[cfg(any(tsc_v2, tsc_v3))]
565 {
566 mask |= self.g7.as_ref().map_or(0, |g| g.make_channel_ios_mask());
567 }
568 #[cfg(tsc_v3)]
569 {
570 mask |= self.g8.as_ref().map_or(0, |g| g.make_channel_ios_mask());
571 }
572 mask
573 }
574
575 pub(super) fn make_shield_ios_mask(&self) -> u32 {
576 #[allow(unused_mut)]
577 let mut mask = self.g1.as_ref().map_or(0, |g| g.make_shield_ios_mask())
578 | self.g2.as_ref().map_or(0, |g| g.make_shield_ios_mask())
579 | self.g3.as_ref().map_or(0, |g| g.make_shield_ios_mask())
580 | self.g4.as_ref().map_or(0, |g| g.make_shield_ios_mask())
581 | self.g5.as_ref().map_or(0, |g| g.make_shield_ios_mask())
582 | self.g6.as_ref().map_or(0, |g| g.make_shield_ios_mask());
583 #[cfg(any(tsc_v2, tsc_v3))]
584 {
585 mask |= self.g7.as_ref().map_or(0, |g| g.make_shield_ios_mask());
586 }
587 #[cfg(tsc_v3)]
588 {
589 mask |= self.g8.as_ref().map_or(0, |g| g.make_shield_ios_mask());
590 }
591 mask
592 }
593
594 pub(super) fn make_sample_ios_mask(&self) -> u32 {
595 #[allow(unused_mut)]
596 let mut mask = self.g1.as_ref().map_or(0, |g| g.make_sample_ios_mask())
597 | self.g2.as_ref().map_or(0, |g| g.make_sample_ios_mask())
598 | self.g3.as_ref().map_or(0, |g| g.make_sample_ios_mask())
599 | self.g4.as_ref().map_or(0, |g| g.make_sample_ios_mask())
600 | self.g5.as_ref().map_or(0, |g| g.make_sample_ios_mask())
601 | self.g6.as_ref().map_or(0, |g| g.make_sample_ios_mask());
602 #[cfg(any(tsc_v2, tsc_v3))]
603 {
604 mask |= self.g7.as_ref().map_or(0, |g| g.make_sample_ios_mask());
605 }
606 #[cfg(tsc_v3)]
607 {
608 mask |= self.g8.as_ref().map_or(0, |g| g.make_sample_ios_mask());
609 }
610 mask
611 }
612}
613
614impl<'d, T: Instance> Default for PinGroups<'d, T> {
615 fn default() -> Self {
616 Self {
617 g1: None,
618 g2: None,
619 g3: None,
620 g4: None,
621 g5: None,
622 g6: None,
623 #[cfg(any(tsc_v2, tsc_v3))]
624 g7: None,
625 #[cfg(tsc_v3)]
626 g8: None,
627 }
628 }
629}
630
631pin_trait!(G1IO1Pin, Instance);
632pin_trait!(G1IO2Pin, Instance);
633pin_trait!(G1IO3Pin, Instance);
634pin_trait!(G1IO4Pin, Instance);
635
636pin_trait!(G2IO1Pin, Instance);
637pin_trait!(G2IO2Pin, Instance);
638pin_trait!(G2IO3Pin, Instance);
639pin_trait!(G2IO4Pin, Instance);
640
641pin_trait!(G3IO1Pin, Instance);
642pin_trait!(G3IO2Pin, Instance);
643pin_trait!(G3IO3Pin, Instance);
644pin_trait!(G3IO4Pin, Instance);
645
646pin_trait!(G4IO1Pin, Instance);
647pin_trait!(G4IO2Pin, Instance);
648pin_trait!(G4IO3Pin, Instance);
649pin_trait!(G4IO4Pin, Instance);
650
651pin_trait!(G5IO1Pin, Instance);
652pin_trait!(G5IO2Pin, Instance);
653pin_trait!(G5IO3Pin, Instance);
654pin_trait!(G5IO4Pin, Instance);
655
656pin_trait!(G6IO1Pin, Instance);
657pin_trait!(G6IO2Pin, Instance);
658pin_trait!(G6IO3Pin, Instance);
659pin_trait!(G6IO4Pin, Instance);
660
661pin_trait!(G7IO1Pin, Instance);
662pin_trait!(G7IO2Pin, Instance);
663pin_trait!(G7IO3Pin, Instance);
664pin_trait!(G7IO4Pin, Instance);
665
666pin_trait!(G8IO1Pin, Instance);
667pin_trait!(G8IO2Pin, Instance);
668pin_trait!(G8IO3Pin, Instance);
669pin_trait!(G8IO4Pin, Instance);
670

Provided by KDAB

Privacy Policy