diff options
| author | michel <[email protected]> | 2024-08-07 21:58:49 +0200 |
|---|---|---|
| committer | michel <[email protected]> | 2024-11-29 17:58:33 +0100 |
| commit | 721c6820d4a6e3bbf2546997205a32975e6bad8b (patch) | |
| tree | f725e1f66b0b7f40a3b663f355c2b1d5d389af06 /examples/stm32f3/src | |
| parent | 1a1d5c4689a8b6c57ebb74e99fdea8df39adb037 (diff) | |
STM32-TSC: enable discriminating between pins within same TSC group and improve TSC library in general
Diffstat (limited to 'examples/stm32f3/src')
| -rw-r--r-- | examples/stm32f3/src/bin/blocking-tsc.rs | 98 | ||||
| -rw-r--r-- | examples/stm32f3/src/bin/tsc_blocking.rs | 138 |
2 files changed, 138 insertions, 98 deletions
diff --git a/examples/stm32f3/src/bin/blocking-tsc.rs b/examples/stm32f3/src/bin/blocking-tsc.rs deleted file mode 100644 index 5c8dac94f..000000000 --- a/examples/stm32f3/src/bin/blocking-tsc.rs +++ /dev/null | |||
| @@ -1,98 +0,0 @@ | |||
| 1 | // Example of polling TSC (Touch Sensing Controller) that lights an LED when touch is detected. | ||
| 2 | // | ||
| 3 | // Suggested physical setup on STM32F303ZE Nucleo board: | ||
| 4 | // - Connect a 1000pF capacitor between pin A0 and GND. This is your sampling capacitor. | ||
| 5 | // - Connect one end of a 1K resistor to pin A1 and leave the other end loose. | ||
| 6 | // The loose end will act as touch sensor which will register your touch. | ||
| 7 | // | ||
| 8 | // Troubleshooting the setup: | ||
| 9 | // - If no touch seems to be registered, then try to disconnect the sampling capacitor from GND momentarily, | ||
| 10 | // now the led should light up. Next try using a different value for the sampling capacitor. | ||
| 11 | // Also experiment with increasing the values for `ct_pulse_high_length`, `ct_pulse_low_length`, `pulse_generator_prescaler`, `max_count_value` and `discharge_delay`. | ||
| 12 | // | ||
| 13 | // All configuration values and sampling capacitor value have been determined experimentally. | ||
| 14 | // Suitable configuration and discharge delay values are highly dependent on the value of the sample capacitor. For example, a shorter discharge delay can be used with smaller capacitor values. | ||
| 15 | // | ||
| 16 | #![no_std] | ||
| 17 | #![no_main] | ||
| 18 | |||
| 19 | use defmt::*; | ||
| 20 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 21 | use embassy_stm32::tsc::{self, *}; | ||
| 22 | use embassy_time::Timer; | ||
| 23 | use {defmt_rtt as _, panic_probe as _}; | ||
| 24 | |||
| 25 | /// This example is written for the nucleo-stm32f303ze, with a stm32f303ze chip. | ||
| 26 | /// | ||
| 27 | /// Make sure you check/update the following (whether you use the F303ZE or another board): | ||
| 28 | /// | ||
| 29 | /// * [ ] Update .cargo/config.toml with the correct `probe-rs run --chip STM32F303ZETx`chip name. | ||
| 30 | /// * [ ] Update Cargo.toml to have the correct `embassy-stm32` feature, for F303ZE it should be `stm32f303ze`. | ||
| 31 | /// * [ ] If your board has a special clock or power configuration, make sure that it is | ||
| 32 | /// set up appropriately. | ||
| 33 | /// * [ ] If your board has different pin mapping, update any pin numbers or peripherals | ||
| 34 | /// to match your schematic | ||
| 35 | /// | ||
| 36 | /// If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: | ||
| 37 | /// | ||
| 38 | /// * Which example you are trying to run | ||
| 39 | /// * Which chip and board you are using | ||
| 40 | /// | ||
| 41 | /// Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org | ||
| 42 | #[embassy_executor::main] | ||
| 43 | async fn main(_spawner: embassy_executor::Spawner) { | ||
| 44 | let device_config = embassy_stm32::Config::default(); | ||
| 45 | let context = embassy_stm32::init(device_config); | ||
| 46 | |||
| 47 | let tsc_conf = Config { | ||
| 48 | ct_pulse_high_length: ChargeTransferPulseCycle::_8, | ||
| 49 | ct_pulse_low_length: ChargeTransferPulseCycle::_8, | ||
| 50 | spread_spectrum: false, | ||
| 51 | spread_spectrum_deviation: SSDeviation::new(2).unwrap(), | ||
| 52 | spread_spectrum_prescaler: false, | ||
| 53 | pulse_generator_prescaler: PGPrescalerDivider::_32, | ||
| 54 | max_count_value: MaxCount::_255, | ||
| 55 | io_default_mode: false, | ||
| 56 | synchro_pin_polarity: false, | ||
| 57 | acquisition_mode: false, | ||
| 58 | max_count_interrupt: false, | ||
| 59 | channel_ios: TscIOPin::Group1Io1.into(), | ||
| 60 | shield_ios: 0, // no shield | ||
| 61 | sampling_ios: TscIOPin::Group1Io2.into(), | ||
| 62 | }; | ||
| 63 | |||
| 64 | let mut g1: PinGroup<embassy_stm32::peripherals::TSC, G1> = PinGroup::new(); | ||
| 65 | g1.set_io1(context.PA0, PinType::Sample); | ||
| 66 | g1.set_io2(context.PA1, PinType::Channel); | ||
| 67 | |||
| 68 | let mut touch_controller = tsc::Tsc::new_blocking(context.TSC, Some(g1), None, None, None, None, None, tsc_conf); | ||
| 69 | |||
| 70 | // LED2 on the STM32F303ZE nucleo-board | ||
| 71 | let mut led = Output::new(context.PB7, Level::High, Speed::Low); | ||
| 72 | |||
| 73 | // smaller sample capacitor discharge faster and can be used with shorter delay. | ||
| 74 | let discharge_delay = 5; // ms | ||
| 75 | |||
| 76 | // the interval at which the loop polls for new touch sensor values | ||
| 77 | let polling_interval = 100; // ms | ||
| 78 | |||
| 79 | info!("polling for touch"); | ||
| 80 | loop { | ||
| 81 | touch_controller.start(); | ||
| 82 | touch_controller.poll_for_acquisition(); | ||
| 83 | touch_controller.discharge_io(true); | ||
| 84 | Timer::after_millis(discharge_delay).await; | ||
| 85 | |||
| 86 | let grp1_status = touch_controller.group_get_status(Group::One); | ||
| 87 | match grp1_status { | ||
| 88 | GroupStatus::Complete => { | ||
| 89 | let group_one_val = touch_controller.group_get_value(Group::One); | ||
| 90 | info!("{}", group_one_val); | ||
| 91 | led.set_high(); | ||
| 92 | } | ||
| 93 | GroupStatus::Ongoing => led.set_low(), | ||
| 94 | } | ||
| 95 | |||
| 96 | Timer::after_millis(polling_interval).await; | ||
| 97 | } | ||
| 98 | } | ||
diff --git a/examples/stm32f3/src/bin/tsc_blocking.rs b/examples/stm32f3/src/bin/tsc_blocking.rs new file mode 100644 index 000000000..fa7f718e6 --- /dev/null +++ b/examples/stm32f3/src/bin/tsc_blocking.rs | |||
| @@ -0,0 +1,138 @@ | |||
| 1 | // Example of blocking TSC (Touch Sensing Controller) that lights an LED when touch is detected. | ||
| 2 | // | ||
| 3 | // This example demonstrates: | ||
| 4 | // 1. Configuring a single TSC channel pin | ||
| 5 | // 2. Using the blocking TSC interface with polling | ||
| 6 | // 3. Waiting for acquisition completion using `poll_for_acquisition` | ||
| 7 | // 4. Reading touch values and controlling an LED based on the results | ||
| 8 | // | ||
| 9 | // Suggested physical setup on STM32F303ZE Nucleo board: | ||
| 10 | // - Connect a 1000pF capacitor between pin PA10 and GND. This is your sampling capacitor. | ||
| 11 | // - Connect one end of a 1K resistor to pin PA9 and leave the other end loose. | ||
| 12 | // The loose end will act as the touch sensor which will register your touch. | ||
| 13 | // | ||
| 14 | // The example uses two pins from Group 4 of the TSC: | ||
| 15 | // - PA10 as the sampling capacitor, TSC group 4 IO2 (D68 on the STM32F303ZE nucleo-board) | ||
| 16 | // - PA9 as the channel pin, TSC group 4 IO1 (D69 on the STM32F303ZE nucleo-board) | ||
| 17 | // | ||
| 18 | // The program continuously reads the touch sensor value: | ||
| 19 | // - It starts acquisition, waits for completion using `poll_for_acquisition`, and reads the value. | ||
| 20 | // - The LED is turned on when touch is detected (sensor value < 40). | ||
| 21 | // - Touch values are logged to the console. | ||
| 22 | // | ||
| 23 | // Troubleshooting: | ||
| 24 | // - If touch is not detected, try adjusting the SENSOR_THRESHOLD value. | ||
| 25 | // - Experiment with different values for ct_pulse_high_length, ct_pulse_low_length, | ||
| 26 | // pulse_generator_prescaler, max_count_value, and discharge_delay to optimize sensitivity. | ||
| 27 | // | ||
| 28 | // Note: Configuration values and sampling capacitor value have been determined experimentally. | ||
| 29 | // Optimal values may vary based on your specific hardware setup. | ||
| 30 | // Pins have been chosen for their convenient locations on the STM32F303ZE board. Refer to the | ||
| 31 | // official relevant STM32 datasheets and user nucleo-board user manuals to find suitable | ||
| 32 | // alternative pins. | ||
| 33 | |||
| 34 | #![no_std] | ||
| 35 | #![no_main] | ||
| 36 | |||
| 37 | use defmt::*; | ||
| 38 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 39 | use embassy_stm32::tsc::{self, *}; | ||
| 40 | use embassy_stm32::{mode, peripherals}; | ||
| 41 | use embassy_time::Timer; | ||
| 42 | use {defmt_rtt as _, panic_probe as _}; | ||
| 43 | |||
| 44 | const SENSOR_THRESHOLD: u16 = 25; // Adjust this value based on your setup | ||
| 45 | |||
| 46 | #[embassy_executor::main] | ||
| 47 | async fn main(_spawner: embassy_executor::Spawner) { | ||
| 48 | let device_config = embassy_stm32::Config::default(); | ||
| 49 | let context = embassy_stm32::init(device_config); | ||
| 50 | |||
| 51 | let tsc_conf = Config { | ||
| 52 | ct_pulse_high_length: ChargeTransferPulseCycle::_4, | ||
| 53 | ct_pulse_low_length: ChargeTransferPulseCycle::_4, | ||
| 54 | spread_spectrum: false, | ||
| 55 | spread_spectrum_deviation: SSDeviation::new(2).unwrap(), | ||
| 56 | spread_spectrum_prescaler: false, | ||
| 57 | pulse_generator_prescaler: PGPrescalerDivider::_16, | ||
| 58 | max_count_value: MaxCount::_255, | ||
| 59 | io_default_mode: false, | ||
| 60 | synchro_pin_polarity: false, | ||
| 61 | acquisition_mode: false, | ||
| 62 | max_count_interrupt: false, | ||
| 63 | }; | ||
| 64 | |||
| 65 | let mut g: PinGroupWithRoles<peripherals::TSC, G4> = PinGroupWithRoles::default(); | ||
| 66 | // D68 on the STM32F303ZE nucleo-board | ||
| 67 | g.set_io2::<tsc_pin_roles::Sample>(context.PA10); | ||
| 68 | // D69 on the STM32F303ZE nucleo-board | ||
| 69 | let tsc_sensor = g.set_io1::<tsc_pin_roles::Channel>(context.PA9); | ||
| 70 | |||
| 71 | let pin_groups: PinGroups<peripherals::TSC> = PinGroups { | ||
| 72 | g4: Some(g.pin_group), | ||
| 73 | ..Default::default() | ||
| 74 | }; | ||
| 75 | |||
| 76 | let mut touch_controller = tsc::Tsc::new_blocking(context.TSC, pin_groups, tsc_conf).unwrap(); | ||
| 77 | |||
| 78 | // Check if TSC is ready | ||
| 79 | if touch_controller.get_state() != State::Ready { | ||
| 80 | crate::panic!("TSC not ready!"); | ||
| 81 | } | ||
| 82 | info!("TSC initialized successfully"); | ||
| 83 | |||
| 84 | // LED2 on the STM32F303ZE nucleo-board | ||
| 85 | let mut led = Output::new(context.PB7, Level::High, Speed::Low); | ||
| 86 | |||
| 87 | // smaller sample capacitor discharge faster and can be used with shorter delay. | ||
| 88 | let discharge_delay = 5; // ms | ||
| 89 | |||
| 90 | // the interval at which the loop polls for new touch sensor values | ||
| 91 | let polling_interval = 100; // ms | ||
| 92 | |||
| 93 | info!("polling for touch"); | ||
| 94 | loop { | ||
| 95 | touch_controller.set_active_channels_mask(tsc_sensor.pin.into()); | ||
| 96 | touch_controller.start(); | ||
| 97 | touch_controller.poll_for_acquisition(); | ||
| 98 | touch_controller.discharge_io(true); | ||
| 99 | Timer::after_millis(discharge_delay).await; | ||
| 100 | |||
| 101 | match read_touch_value(&mut touch_controller, tsc_sensor.pin).await { | ||
| 102 | Some(v) => { | ||
| 103 | info!("sensor value {}", v); | ||
| 104 | if v < SENSOR_THRESHOLD { | ||
| 105 | led.set_high(); | ||
| 106 | } else { | ||
| 107 | led.set_low(); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | None => led.set_low(), | ||
| 111 | } | ||
| 112 | |||
| 113 | Timer::after_millis(polling_interval).await; | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | const MAX_GROUP_STATUS_READ_ATTEMPTS: usize = 10; | ||
| 118 | |||
| 119 | // attempt to read group status and delay when still ongoing | ||
| 120 | async fn read_touch_value( | ||
| 121 | touch_controller: &mut tsc::Tsc<'_, peripherals::TSC, mode::Blocking>, | ||
| 122 | sensor_pin: TscIOPin, | ||
| 123 | ) -> Option<u16> { | ||
| 124 | for _ in 0..MAX_GROUP_STATUS_READ_ATTEMPTS { | ||
| 125 | match touch_controller.group_get_status(sensor_pin.group()) { | ||
| 126 | GroupStatus::Complete => { | ||
| 127 | return Some(touch_controller.group_get_value(sensor_pin.group())); | ||
| 128 | } | ||
| 129 | GroupStatus::Ongoing => { | ||
| 130 | // if you end up here a lot, then you prob need to increase discharge_delay | ||
| 131 | // or consider changing the code to adjust the discharge_delay dynamically | ||
| 132 | info!("Acquisition still ongoing"); | ||
| 133 | Timer::after_millis(1).await; | ||
| 134 | } | ||
| 135 | } | ||
| 136 | } | ||
| 137 | None | ||
| 138 | } | ||
