aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/stm32f3/src/bin/tsc_multipin.rs204
1 files changed, 204 insertions, 0 deletions
diff --git a/examples/stm32f3/src/bin/tsc_multipin.rs b/examples/stm32f3/src/bin/tsc_multipin.rs
new file mode 100644
index 000000000..c524c3760
--- /dev/null
+++ b/examples/stm32f3/src/bin/tsc_multipin.rs
@@ -0,0 +1,204 @@
1// Example of TSC (Touch Sensing Controller) using multiple pins from the same tsc-group.
2//
3// What is special about using multiple TSC pins as sensor channels from the same TSC group,
4// is that only one TSC pin for each TSC group can be acquired and read at the time.
5// To control which channel pins are acquired and read, we must write a mask before initiating an
6// acquisition. To help manage and abstract all this business away, we can organize our channel
7// pins into acquisition banks. Each acquisition bank can contain exactly one channel pin per TSC
8// group and it will contain the relevant mask.
9//
10// This example demonstrates how to:
11// 1. Configure multiple channel pins within a single TSC group
12// 2. Use the set_active_channels_bank method to switch between sets of different channels (acquisition banks)
13// 3. Read and interpret touch values from multiple channels in the same group
14//
15// Suggested physical setup on STM32F303ZE Nucleo board:
16// - Connect a 1000pF capacitor between pin PA10 and GND. This is the sampling capacitor for TSC
17// group 4.
18// - Connect one end of a 1K resistor to pin PA9 and leave the other end loose.
19// The loose end will act as a touch sensor.
20//
21// - Connect a 1000pF capacitor between pin PA7 and GND. This is the sampling capacitor for TSC
22// group 2.
23// - Connect one end of another 1K resistor to pin PA6 and leave the other end loose.
24// The loose end will act as a touch sensor.
25// - Connect one end of another 1K resistor to pin PA5 and leave the other end loose.
26// The loose end will act as a touch sensor.
27//
28// The example uses pins from two TSC groups.
29// - PA10 as sampling capacitor, TSC group 4 IO2
30// - PA9 as channel, TSC group 4 IO1
31// - PA7 as sampling capacitor, TSC group 2 IO4
32// - PA6 as channel, TSC group 2 IO3
33// - PA5 as channel, TSC group 2 IO2
34//
35// The pins have been chosen to make it easy to simply add capacitors directly onto the board and
36// connect one leg to GND, and to easily add resistors to the board with no special connectors,
37// breadboards, special wires or soldering required. All you need is the capacitors and resistors.
38//
39// The program reads the designated channel pins and adjusts the LED blinking
40// pattern based on which sensor(s) are touched:
41// - No touch: LED off
42// - one sensor touched: Slow blinking
43// - two sensors touched: Fast blinking
44// - three sensors touched: LED constantly on
45//
46// ## Troubleshooting:
47//
48// - If touch is not detected, try adjusting the SENSOR_THRESHOLD value (currently set to 20).
49// - Experiment with different values for ct_pulse_high_length, ct_pulse_low_length, pulse_generator_prescaler, max_count_value, and discharge_delay to optimize sensitivity.
50// - Be aware that for some boards there will be overlapping concerns between some pins, for
51// example UART connection for the programmer to the MCU and a TSC pin. No errors or warning will
52// be emitted if you try to use such a pin for TSC, but you will get strange sensor readings.
53//
54// Note: Configuration values and sampling capacitor values have been determined experimentally. Optimal values may vary based on your specific hardware setup. Refer to the official STM32 datasheet and user manuals for more information on pin configurations and TSC functionality.
55
56#![no_std]
57#![no_main]
58
59use defmt::*;
60use embassy_stm32::gpio::{Level, Output, Speed};
61use embassy_stm32::tsc::{self, *};
62use embassy_stm32::{mode, peripherals};
63use embassy_time::Timer;
64use {defmt_rtt as _, panic_probe as _};
65
66const SENSOR_THRESHOLD: u16 = 10;
67
68async fn acquire_sensors(
69 touch_controller: &mut Tsc<'static, peripherals::TSC, mode::Blocking>,
70 tsc_acquisition_bank: &AcquisitionBank,
71) {
72 touch_controller.set_active_channels_bank(tsc_acquisition_bank);
73 touch_controller.start();
74 touch_controller.poll_for_acquisition();
75 touch_controller.discharge_io(true);
76 let discharge_delay = 5; // ms
77 Timer::after_millis(discharge_delay).await;
78}
79
80#[embassy_executor::main]
81async fn main(_spawner: embassy_executor::Spawner) {
82 let device_config = embassy_stm32::Config::default();
83 let context = embassy_stm32::init(device_config);
84
85 // ---------- initial configuration of TSC ----------
86 //
87 let mut pin_group4: PinGroupWithRoles<peripherals::TSC, G4> = PinGroupWithRoles::default();
88 // D68 on the STM32F303ZE nucleo-board
89 pin_group4.set_io2::<tsc::pin_roles::Sample>(context.PA10);
90 // D69 on the STM32F303ZE nucleo-board
91 let tsc_sensor0 = pin_group4.set_io1(context.PA9);
92
93 let mut pin_group2: PinGroupWithRoles<peripherals::TSC, G2> = PinGroupWithRoles::default();
94 // D11 on the STM32F303ZE nucleo-board
95 pin_group2.set_io4::<tsc::pin_roles::Sample>(context.PA7);
96 // D12 on the STM32F303ZE nucleo-board
97 let tsc_sensor1 = pin_group2.set_io3(context.PA6);
98 // D13 on the STM32F303ZE nucleo-board
99 let tsc_sensor2 = pin_group2.set_io2(context.PA5);
100
101 let config = Config {
102 ct_pulse_high_length: ChargeTransferPulseCycle::_4,
103 ct_pulse_low_length: ChargeTransferPulseCycle::_4,
104 spread_spectrum: false,
105 spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
106 spread_spectrum_prescaler: false,
107 pulse_generator_prescaler: PGPrescalerDivider::_16,
108 max_count_value: MaxCount::_255,
109 io_default_mode: false,
110 synchro_pin_polarity: false,
111 acquisition_mode: false,
112 max_count_interrupt: false,
113 };
114
115 let pin_groups: PinGroups<peripherals::TSC> = PinGroups {
116 g4: Some(pin_group4.pin_group),
117 g2: Some(pin_group2.pin_group),
118 ..Default::default()
119 };
120
121 let mut touch_controller = tsc::Tsc::new_blocking(context.TSC, pin_groups, config).unwrap();
122
123 // ---------- setting up acquisition banks ----------
124 // sensor0 and sensor1 in this example belong to different TSC-groups,
125 // therefore we can acquire and read them both in one go.
126 let bank1 = touch_controller.create_acquisition_bank(AcquisitionBankPins {
127 g4_pin: Some(tsc_sensor0),
128 g2_pin: Some(tsc_sensor1),
129 ..Default::default()
130 });
131 // `sensor1` and `sensor2` belongs to the same TSC-group, therefore we must make sure to
132 // acquire them one at the time. Therefore, we organize them into different acquisition banks.
133 let bank2 = touch_controller.create_acquisition_bank(AcquisitionBankPins {
134 g2_pin: Some(tsc_sensor2),
135 ..Default::default()
136 });
137
138 // Check if TSC is ready
139 if touch_controller.get_state() != State::Ready {
140 crate::panic!("TSC not ready!");
141 }
142
143 info!("TSC initialized successfully");
144
145 // LED2 on the STM32F303ZE nucleo-board
146 let mut led = Output::new(context.PB7, Level::High, Speed::Low);
147
148 let mut led_state = false;
149
150 loop {
151 acquire_sensors(&mut touch_controller, &bank1).await;
152 let readings1 = touch_controller.get_acquisition_bank_values(&bank1);
153 acquire_sensors(&mut touch_controller, &bank2).await;
154 let readings2 = touch_controller.get_acquisition_bank_values(&bank2);
155
156 let mut touched_sensors_count = 0;
157 for reading in readings1.iter() {
158 info!("{}", reading);
159 if reading.sensor_value < SENSOR_THRESHOLD {
160 touched_sensors_count += 1;
161 }
162 }
163 for reading in readings2.iter() {
164 info!("{}", reading);
165 if reading.sensor_value < SENSOR_THRESHOLD {
166 touched_sensors_count += 1;
167 }
168 }
169
170 match touched_sensors_count {
171 0 => {
172 // No sensors touched, turn off the LED
173 led.set_low();
174 led_state = false;
175 }
176 1 => {
177 // One sensor touched, blink slowly
178 led_state = !led_state;
179 if led_state {
180 led.set_high();
181 } else {
182 led.set_low();
183 }
184 Timer::after_millis(200).await;
185 }
186 2 => {
187 // Two sensors touched, blink faster
188 led_state = !led_state;
189 if led_state {
190 led.set_high();
191 } else {
192 led.set_low();
193 }
194 Timer::after_millis(50).await;
195 }
196 3 => {
197 // All three sensors touched, LED constantly on
198 led.set_high();
199 led_state = true;
200 }
201 _ => crate::unreachable!(), // This case should never occur with 3 sensors
202 }
203 }
204}