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 | |
| parent | 1a1d5c4689a8b6c57ebb74e99fdea8df39adb037 (diff) | |
STM32-TSC: enable discriminating between pins within same TSC group and improve TSC library in general
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/stm32f3/README.md | 24 | ||||
| -rw-r--r-- | examples/stm32f3/src/bin/blocking-tsc.rs | 98 | ||||
| -rw-r--r-- | examples/stm32f3/src/bin/tsc_blocking.rs | 138 | ||||
| -rw-r--r-- | examples/stm32l0/.cargo/config.toml | 2 | ||||
| -rw-r--r-- | examples/stm32l0/Cargo.toml | 2 | ||||
| -rw-r--r-- | examples/stm32l0/README.md | 24 | ||||
| -rw-r--r-- | examples/stm32l0/src/bin/async-tsc.rs | 122 | ||||
| -rw-r--r-- | examples/stm32l0/src/bin/blocking-tsc.rs | 116 | ||||
| -rw-r--r-- | examples/stm32l0/src/bin/tsc_async.rs | 116 | ||||
| -rw-r--r-- | examples/stm32l0/src/bin/tsc_blocking.rs | 142 | ||||
| -rw-r--r-- | examples/stm32l0/src/bin/tsc_multipin.rs | 233 | ||||
| -rw-r--r-- | examples/stm32l4/.cargo/config.toml | 3 | ||||
| -rw-r--r-- | examples/stm32l4/Cargo.toml | 2 | ||||
| -rw-r--r-- | examples/stm32l4/README.md | 24 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/tsc_async.rs | 108 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/tsc_blocking.rs | 147 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/tsc_multipin.rs | 222 | ||||
| -rw-r--r-- | examples/stm32u5/src/bin/tsc.rs | 75 |
18 files changed, 1215 insertions, 383 deletions
diff --git a/examples/stm32f3/README.md b/examples/stm32f3/README.md new file mode 100644 index 000000000..0a85c4858 --- /dev/null +++ b/examples/stm32f3/README.md | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | # Examples for STM32F3 family | ||
| 2 | Run individual examples with | ||
| 3 | ``` | ||
| 4 | cargo run --bin <module-name> | ||
| 5 | ``` | ||
| 6 | for example | ||
| 7 | ``` | ||
| 8 | cargo run --bin blinky | ||
| 9 | ``` | ||
| 10 | |||
| 11 | ## Checklist before running examples | ||
| 12 | You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using. | ||
| 13 | |||
| 14 | * [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for F303ZE it should be `probe-rs run --chip STM32F303ZETx`. (use `probe-rs chip list` to find your chip) | ||
| 15 | * [ ] Update Cargo.toml to have the correct `embassy-stm32` feature. For example for F303ZE it should be `stm32f303ze`. Look in the `Cargo.toml` file of the `embassy-stm32` project to find the correct feature flag for your chip. | ||
| 16 | * [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. | ||
| 17 | * [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic | ||
| 18 | |||
| 19 | If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: | ||
| 20 | |||
| 21 | * Which example you are trying to run | ||
| 22 | * Which chip and board you are using | ||
| 23 | |||
| 24 | Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org | ||
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 | } | ||
diff --git a/examples/stm32l0/.cargo/config.toml b/examples/stm32l0/.cargo/config.toml index b050334b2..fed9cf9ce 100644 --- a/examples/stm32l0/.cargo/config.toml +++ b/examples/stm32l0/.cargo/config.toml | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] |
| 2 | # replace your chip as listed in `probe-rs chip list` | 2 | # replace your chip as listed in `probe-rs chip list` |
| 3 | runner = "probe-rs run --chip STM32L053R8Tx" | 3 | runner = "probe-rs run --chip STM32L073RZTx" |
| 4 | 4 | ||
| 5 | [build] | 5 | [build] |
| 6 | target = "thumbv6m-none-eabi" | 6 | target = "thumbv6m-none-eabi" |
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 95e215b6f..9d234804a 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml | |||
| @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | # Change stm32l072cz to your chip name, if necessary. | 8 | # Change stm32l072cz to your chip name, if necessary. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l073rz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
diff --git a/examples/stm32l0/README.md b/examples/stm32l0/README.md new file mode 100644 index 000000000..82d222027 --- /dev/null +++ b/examples/stm32l0/README.md | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | # Examples for STM32L0 family | ||
| 2 | Run individual examples with | ||
| 3 | ``` | ||
| 4 | cargo run --bin <module-name> | ||
| 5 | ``` | ||
| 6 | for example | ||
| 7 | ``` | ||
| 8 | cargo run --bin blinky | ||
| 9 | ``` | ||
| 10 | |||
| 11 | ## Checklist before running examples | ||
| 12 | You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using. | ||
| 13 | |||
| 14 | * [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for L073RZ it should be `probe-rs run --chip STM32L073RZTx`. (use `probe-rs chip list` to find your chip) | ||
| 15 | * [ ] Update Cargo.toml to have the correct `embassy-stm32` feature. For example for L073RZ it should be `stm32l073rz`. Look in the `Cargo.toml` file of the `embassy-stm32` project to find the correct feature flag for your chip. | ||
| 16 | * [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. | ||
| 17 | * [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic | ||
| 18 | |||
| 19 | If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: | ||
| 20 | |||
| 21 | * Which example you are trying to run | ||
| 22 | * Which chip and board you are using | ||
| 23 | |||
| 24 | Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org | ||
diff --git a/examples/stm32l0/src/bin/async-tsc.rs b/examples/stm32l0/src/bin/async-tsc.rs deleted file mode 100644 index c40b86af9..000000000 --- a/examples/stm32l0/src/bin/async-tsc.rs +++ /dev/null | |||
| @@ -1,122 +0,0 @@ | |||
| 1 | // Example of async TSC (Touch Sensing Controller) that lights an LED when touch is detected. | ||
| 2 | // | ||
| 3 | // Suggested physical setup on STM32L073RZ 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::bind_interrupts; | ||
| 21 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 22 | use embassy_stm32::tsc::{self, *}; | ||
| 23 | use embassy_time::Timer; | ||
| 24 | use {defmt_rtt as _, panic_probe as _}; | ||
| 25 | |||
| 26 | bind_interrupts!(struct Irqs { | ||
| 27 | TSC => InterruptHandler<embassy_stm32::peripherals::TSC>; | ||
| 28 | }); | ||
| 29 | |||
| 30 | #[cortex_m_rt::exception] | ||
| 31 | unsafe fn HardFault(_: &cortex_m_rt::ExceptionFrame) -> ! { | ||
| 32 | cortex_m::peripheral::SCB::sys_reset(); | ||
| 33 | } | ||
| 34 | |||
| 35 | /// This example is written for the nucleo-stm32l073rz, with a stm32l073rz chip. | ||
| 36 | /// | ||
| 37 | /// Make sure you check/update the following (whether you use the L073RZ or another board): | ||
| 38 | /// | ||
| 39 | /// * [ ] Update .cargo/config.toml with the correct `probe-rs run --chip STM32L073RZTx`chip name. | ||
| 40 | /// * [ ] Update Cargo.toml to have the correct `embassy-stm32` feature, for L073RZ it should be `stm32l073rz`. | ||
| 41 | /// * [ ] If your board has a special clock or power configuration, make sure that it is | ||
| 42 | /// set up appropriately. | ||
| 43 | /// * [ ] If your board has different pin mapping, update any pin numbers or peripherals | ||
| 44 | /// to match your schematic | ||
| 45 | /// | ||
| 46 | /// If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: | ||
| 47 | /// | ||
| 48 | /// * Which example you are trying to run | ||
| 49 | /// * Which chip and board you are using | ||
| 50 | /// | ||
| 51 | /// Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org | ||
| 52 | #[embassy_executor::main] | ||
| 53 | async fn main(_spawner: embassy_executor::Spawner) { | ||
| 54 | let device_config = embassy_stm32::Config::default(); | ||
| 55 | let context = embassy_stm32::init(device_config); | ||
| 56 | |||
| 57 | let config = tsc::Config { | ||
| 58 | ct_pulse_high_length: ChargeTransferPulseCycle::_4, | ||
| 59 | ct_pulse_low_length: ChargeTransferPulseCycle::_4, | ||
| 60 | spread_spectrum: false, | ||
| 61 | spread_spectrum_deviation: SSDeviation::new(2).unwrap(), | ||
| 62 | spread_spectrum_prescaler: false, | ||
| 63 | pulse_generator_prescaler: PGPrescalerDivider::_16, | ||
| 64 | max_count_value: MaxCount::_255, | ||
| 65 | io_default_mode: false, | ||
| 66 | synchro_pin_polarity: false, | ||
| 67 | acquisition_mode: false, | ||
| 68 | max_count_interrupt: false, | ||
| 69 | channel_ios: TscIOPin::Group1Io1.into(), | ||
| 70 | shield_ios: 0, // no shield | ||
| 71 | sampling_ios: TscIOPin::Group1Io2.into(), | ||
| 72 | }; | ||
| 73 | |||
| 74 | let mut g1: PinGroup<embassy_stm32::peripherals::TSC, G1> = PinGroup::new(); | ||
| 75 | g1.set_io1(context.PA0, PinType::Sample); | ||
| 76 | g1.set_io2(context.PA1, PinType::Channel); | ||
| 77 | |||
| 78 | let mut touch_controller = tsc::Tsc::new_async( | ||
| 79 | context.TSC, | ||
| 80 | Some(g1), | ||
| 81 | None, | ||
| 82 | None, | ||
| 83 | None, | ||
| 84 | None, | ||
| 85 | None, | ||
| 86 | None, | ||
| 87 | None, | ||
| 88 | config, | ||
| 89 | Irqs, | ||
| 90 | ); | ||
| 91 | |||
| 92 | // Check if TSC is ready | ||
| 93 | if touch_controller.get_state() != State::Ready { | ||
| 94 | info!("TSC not ready!"); | ||
| 95 | loop {} // Halt execution | ||
| 96 | } | ||
| 97 | info!("TSC initialized successfully"); | ||
| 98 | |||
| 99 | // LED2 on the STM32L073RZ nucleo-board (PA5) | ||
| 100 | let mut led = Output::new(context.PA5, Level::High, Speed::Low); | ||
| 101 | |||
| 102 | // smaller sample capacitor discharge faster and can be used with shorter delay. | ||
| 103 | let discharge_delay = 5; // ms | ||
| 104 | |||
| 105 | info!("Starting touch_controller interface"); | ||
| 106 | loop { | ||
| 107 | touch_controller.start(); | ||
| 108 | touch_controller.pend_for_acquisition().await; | ||
| 109 | touch_controller.discharge_io(true); | ||
| 110 | Timer::after_millis(discharge_delay).await; | ||
| 111 | |||
| 112 | let grp1_status = touch_controller.group_get_status(Group::One); | ||
| 113 | match grp1_status { | ||
| 114 | GroupStatus::Complete => { | ||
| 115 | let group_one_val = touch_controller.group_get_value(Group::One); | ||
| 116 | info!("{}", group_one_val); | ||
| 117 | led.set_high(); | ||
| 118 | } | ||
| 119 | GroupStatus::Ongoing => led.set_low(), | ||
| 120 | } | ||
| 121 | } | ||
| 122 | } | ||
diff --git a/examples/stm32l0/src/bin/blocking-tsc.rs b/examples/stm32l0/src/bin/blocking-tsc.rs deleted file mode 100644 index 7e4f40946..000000000 --- a/examples/stm32l0/src/bin/blocking-tsc.rs +++ /dev/null | |||
| @@ -1,116 +0,0 @@ | |||
| 1 | // Example of polling TSC (Touch Sensing Controller) that lights an LED when touch is detected. | ||
| 2 | // | ||
| 3 | // Suggested physical setup on STM32L073RZ 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-stm32l073rz, with a stm32l073rz chip. | ||
| 26 | /// | ||
| 27 | /// Make sure you check/update the following (whether you use the L073RZ or another board): | ||
| 28 | /// | ||
| 29 | /// * [ ] Update .cargo/config.toml with the correct `probe-rs run --chip STM32L073RZTx`chip name. | ||
| 30 | /// * [ ] Update Cargo.toml to have the correct `embassy-stm32` feature, for L073RZ it should be `stm32l073rz`. | ||
| 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::_4, | ||
| 49 | ct_pulse_low_length: ChargeTransferPulseCycle::_4, | ||
| 50 | spread_spectrum: false, | ||
| 51 | spread_spectrum_deviation: SSDeviation::new(2).unwrap(), | ||
| 52 | spread_spectrum_prescaler: false, | ||
| 53 | pulse_generator_prescaler: PGPrescalerDivider::_16, | ||
| 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( | ||
| 69 | context.TSC, | ||
| 70 | Some(g1), | ||
| 71 | None, | ||
| 72 | None, | ||
| 73 | None, | ||
| 74 | None, | ||
| 75 | None, | ||
| 76 | None, | ||
| 77 | None, | ||
| 78 | tsc_conf, | ||
| 79 | ); | ||
| 80 | |||
| 81 | // Check if TSC is ready | ||
| 82 | if touch_controller.get_state() != State::Ready { | ||
| 83 | info!("TSC not ready!"); | ||
| 84 | loop {} // Halt execution | ||
| 85 | } | ||
| 86 | info!("TSC initialized successfully"); | ||
| 87 | |||
| 88 | // LED2 on the STM32L073RZ nucleo-board (PA5) | ||
| 89 | let mut led = Output::new(context.PA5, Level::High, Speed::Low); | ||
| 90 | |||
| 91 | // smaller sample capacitor discharge faster and can be used with shorter delay. | ||
| 92 | let discharge_delay = 5; // ms | ||
| 93 | |||
| 94 | // the interval at which the loop polls for new touch sensor values | ||
| 95 | let polling_interval = 100; // ms | ||
| 96 | |||
| 97 | info!("polling for touch"); | ||
| 98 | loop { | ||
| 99 | touch_controller.start(); | ||
| 100 | touch_controller.poll_for_acquisition(); | ||
| 101 | touch_controller.discharge_io(true); | ||
| 102 | Timer::after_millis(discharge_delay).await; | ||
| 103 | |||
| 104 | let grp1_status = touch_controller.group_get_status(Group::One); | ||
| 105 | match grp1_status { | ||
| 106 | GroupStatus::Complete => { | ||
| 107 | let group_one_val = touch_controller.group_get_value(Group::One); | ||
| 108 | info!("{}", group_one_val); | ||
| 109 | led.set_high(); | ||
| 110 | } | ||
| 111 | GroupStatus::Ongoing => led.set_low(), | ||
| 112 | } | ||
| 113 | |||
| 114 | Timer::after_millis(polling_interval).await; | ||
| 115 | } | ||
| 116 | } | ||
diff --git a/examples/stm32l0/src/bin/tsc_async.rs b/examples/stm32l0/src/bin/tsc_async.rs new file mode 100644 index 000000000..cebe9712f --- /dev/null +++ b/examples/stm32l0/src/bin/tsc_async.rs | |||
| @@ -0,0 +1,116 @@ | |||
| 1 | // Example of async 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 STM32L073RZ Nucleo board: | ||
| 10 | // - Connect a 1000pF capacitor between pin PA0 and GND. This is your sampling capacitor. | ||
| 11 | // - Connect one end of a 1K resistor to pin PA1 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 1 of the TSC on the STM32L073RZ Nucleo board: | ||
| 15 | // - PA0 as the sampling capacitor, TSC group 1 IO1 (label A0) | ||
| 16 | // - PA1 as the channel pin, TSC group 1 IO2 (label A1) | ||
| 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 < 25). | ||
| 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 STM32L073RZ board. Refer to the | ||
| 31 | // official relevant STM32 datasheets and nucleo-board user manuals to find suitable | ||
| 32 | // alternative pins. | ||
| 33 | // | ||
| 34 | // Beware for STM32L073RZ nucleo-board, that PA2 and PA3 is used for the uart connection to | ||
| 35 | // the programmer chip. If you try to use these two pins for TSC, you will get strange | ||
| 36 | // readings, unless you somehow reconfigure/re-wire your nucleo-board. | ||
| 37 | // No errors or warnings will be emitted, they will just silently not work as expected. | ||
| 38 | // (see nucleo user manual UM1724, Rev 14, page 25) | ||
| 39 | |||
| 40 | #![no_std] | ||
| 41 | #![no_main] | ||
| 42 | |||
| 43 | use defmt::*; | ||
| 44 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 45 | use embassy_stm32::tsc::{self, *}; | ||
| 46 | use embassy_stm32::{bind_interrupts, peripherals}; | ||
| 47 | use embassy_time::Timer; | ||
| 48 | use {defmt_rtt as _, panic_probe as _}; | ||
| 49 | |||
| 50 | bind_interrupts!(struct Irqs { | ||
| 51 | TSC => InterruptHandler<embassy_stm32::peripherals::TSC>; | ||
| 52 | }); | ||
| 53 | const SENSOR_THRESHOLD: u16 = 25; // Adjust this value based on your setup | ||
| 54 | |||
| 55 | #[embassy_executor::main] | ||
| 56 | async fn main(_spawner: embassy_executor::Spawner) { | ||
| 57 | let device_config = embassy_stm32::Config::default(); | ||
| 58 | let context = embassy_stm32::init(device_config); | ||
| 59 | |||
| 60 | let mut pin_group: PinGroupWithRoles<peripherals::TSC, G1> = PinGroupWithRoles::default(); | ||
| 61 | pin_group.set_io1::<tsc_pin_roles::Sample>(context.PA0); | ||
| 62 | let sensor = pin_group.set_io2::<tsc_pin_roles::Channel>(context.PA1); | ||
| 63 | |||
| 64 | let tsc_conf = Config { | ||
| 65 | ct_pulse_high_length: ChargeTransferPulseCycle::_4, | ||
| 66 | ct_pulse_low_length: ChargeTransferPulseCycle::_4, | ||
| 67 | spread_spectrum: false, | ||
| 68 | spread_spectrum_deviation: SSDeviation::new(2).unwrap(), | ||
| 69 | spread_spectrum_prescaler: false, | ||
| 70 | pulse_generator_prescaler: PGPrescalerDivider::_16, | ||
| 71 | max_count_value: MaxCount::_255, | ||
| 72 | io_default_mode: false, | ||
| 73 | synchro_pin_polarity: false, | ||
| 74 | acquisition_mode: false, | ||
| 75 | max_count_interrupt: false, | ||
| 76 | }; | ||
| 77 | |||
| 78 | let pin_groups: PinGroups<peripherals::TSC> = PinGroups { | ||
| 79 | g1: Some(pin_group.pin_group), | ||
| 80 | ..Default::default() | ||
| 81 | }; | ||
| 82 | |||
| 83 | let mut touch_controller = tsc::Tsc::new_async(context.TSC, pin_groups, tsc_conf, Irqs).unwrap(); | ||
| 84 | |||
| 85 | // Check if TSC is ready | ||
| 86 | if touch_controller.get_state() != State::Ready { | ||
| 87 | info!("TSC not ready!"); | ||
| 88 | return; | ||
| 89 | } | ||
| 90 | info!("TSC initialized successfully"); | ||
| 91 | |||
| 92 | // LED2 on the STM32L073RZ nucleo-board (PA5) | ||
| 93 | let mut led = Output::new(context.PA5, Level::Low, Speed::Low); | ||
| 94 | |||
| 95 | let discharge_delay = 5; // ms | ||
| 96 | |||
| 97 | info!("Starting touch_controller interface"); | ||
| 98 | loop { | ||
| 99 | touch_controller.set_active_channels_mask(sensor.pin.into()); | ||
| 100 | touch_controller.start(); | ||
| 101 | touch_controller.pend_for_acquisition().await; | ||
| 102 | touch_controller.discharge_io(true); | ||
| 103 | Timer::after_millis(discharge_delay).await; | ||
| 104 | |||
| 105 | let group_val = touch_controller.group_get_value(sensor.pin.group()); | ||
| 106 | info!("Touch value: {}", group_val); | ||
| 107 | |||
| 108 | if group_val < SENSOR_THRESHOLD { | ||
| 109 | led.set_high(); | ||
| 110 | } else { | ||
| 111 | led.set_low(); | ||
| 112 | } | ||
| 113 | |||
| 114 | Timer::after_millis(100).await; | ||
| 115 | } | ||
| 116 | } | ||
diff --git a/examples/stm32l0/src/bin/tsc_blocking.rs b/examples/stm32l0/src/bin/tsc_blocking.rs new file mode 100644 index 000000000..65203925c --- /dev/null +++ b/examples/stm32l0/src/bin/tsc_blocking.rs | |||
| @@ -0,0 +1,142 @@ | |||
| 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 STM32L073RZ Nucleo board: | ||
| 10 | // - Connect a 1000pF capacitor between pin PA0 and GND. This is your sampling capacitor. | ||
| 11 | // - Connect one end of a 1K resistor to pin PA1 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 1 of the TSC on the STM32L073RZ Nucleo board: | ||
| 15 | // - PA0 as the sampling capacitor, TSC group 1 IO1 (label A0) | ||
| 16 | // - PA1 as the channel pin, TSC group 1 IO2 (label A1) | ||
| 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 < 25). | ||
| 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 STM32L073RZ board. Refer to the | ||
| 31 | // official relevant STM32 datasheets and nucleo-board user manuals to find suitable | ||
| 32 | // alternative pins. | ||
| 33 | // | ||
| 34 | // Beware for STM32L073RZ nucleo-board, that PA2 and PA3 is used for the uart connection to | ||
| 35 | // the programmer chip. If you try to use these two pins for TSC, you will get strange | ||
| 36 | // readings, unless you somehow reconfigure/re-wire your nucleo-board. | ||
| 37 | // No errors or warnings will be emitted, they will just silently not work as expected. | ||
| 38 | // (see nucleo user manual UM1724, Rev 14, page 25) | ||
| 39 | |||
| 40 | #![no_std] | ||
| 41 | #![no_main] | ||
| 42 | |||
| 43 | use defmt::*; | ||
| 44 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 45 | use embassy_stm32::tsc::{self, *}; | ||
| 46 | use embassy_stm32::{mode, peripherals}; | ||
| 47 | use embassy_time::Timer; | ||
| 48 | use {defmt_rtt as _, panic_probe as _}; | ||
| 49 | |||
| 50 | const SENSOR_THRESHOLD: u16 = 25; // Adjust this value based on your setup | ||
| 51 | |||
| 52 | #[embassy_executor::main] | ||
| 53 | async fn main(_spawner: embassy_executor::Spawner) { | ||
| 54 | let device_config = embassy_stm32::Config::default(); | ||
| 55 | let context = embassy_stm32::init(device_config); | ||
| 56 | |||
| 57 | let tsc_conf = Config { | ||
| 58 | ct_pulse_high_length: ChargeTransferPulseCycle::_4, | ||
| 59 | ct_pulse_low_length: ChargeTransferPulseCycle::_4, | ||
| 60 | spread_spectrum: false, | ||
| 61 | spread_spectrum_deviation: SSDeviation::new(2).unwrap(), | ||
| 62 | spread_spectrum_prescaler: false, | ||
| 63 | pulse_generator_prescaler: PGPrescalerDivider::_16, | ||
| 64 | max_count_value: MaxCount::_255, | ||
| 65 | io_default_mode: false, | ||
| 66 | synchro_pin_polarity: false, | ||
| 67 | acquisition_mode: false, | ||
| 68 | max_count_interrupt: false, | ||
| 69 | }; | ||
| 70 | |||
| 71 | let mut g1: PinGroupWithRoles<peripherals::TSC, G1> = PinGroupWithRoles::default(); | ||
| 72 | g1.set_io1::<tsc_pin_roles::Sample>(context.PA0); | ||
| 73 | let tsc_sensor = g1.set_io2::<tsc_pin_roles::Channel>(context.PA1); | ||
| 74 | |||
| 75 | let pin_groups: PinGroups<peripherals::TSC> = PinGroups { | ||
| 76 | g1: Some(g1.pin_group), | ||
| 77 | ..Default::default() | ||
| 78 | }; | ||
| 79 | |||
| 80 | let mut touch_controller = tsc::Tsc::new_blocking(context.TSC, pin_groups, tsc_conf).unwrap(); | ||
| 81 | |||
| 82 | // Check if TSC is ready | ||
| 83 | if touch_controller.get_state() != State::Ready { | ||
| 84 | crate::panic!("TSC not ready!"); | ||
| 85 | } | ||
| 86 | info!("TSC initialized successfully"); | ||
| 87 | |||
| 88 | // LED2 on the STM32L073RZ nucleo-board (PA5) | ||
| 89 | let mut led = Output::new(context.PA5, Level::High, Speed::Low); | ||
| 90 | |||
| 91 | // smaller sample capacitor discharge faster and can be used with shorter delay. | ||
| 92 | let discharge_delay = 5; // ms | ||
| 93 | |||
| 94 | // the interval at which the loop polls for new touch sensor values | ||
| 95 | let polling_interval = 100; // ms | ||
| 96 | |||
| 97 | info!("polling for touch"); | ||
| 98 | loop { | ||
| 99 | touch_controller.set_active_channels_mask(tsc_sensor.pin.into()); | ||
| 100 | touch_controller.start(); | ||
| 101 | touch_controller.poll_for_acquisition(); | ||
| 102 | touch_controller.discharge_io(true); | ||
| 103 | Timer::after_millis(discharge_delay).await; | ||
| 104 | |||
| 105 | match read_touch_value(&mut touch_controller, tsc_sensor.pin).await { | ||
| 106 | Some(v) => { | ||
| 107 | info!("sensor value {}", v); | ||
| 108 | if v < SENSOR_THRESHOLD { | ||
| 109 | led.set_high(); | ||
| 110 | } else { | ||
| 111 | led.set_low(); | ||
| 112 | } | ||
| 113 | } | ||
| 114 | None => led.set_low(), | ||
| 115 | } | ||
| 116 | |||
| 117 | Timer::after_millis(polling_interval).await; | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | const MAX_GROUP_STATUS_READ_ATTEMPTS: usize = 10; | ||
| 122 | |||
| 123 | // attempt to read group status and delay when still ongoing | ||
| 124 | async fn read_touch_value( | ||
| 125 | touch_controller: &mut tsc::Tsc<'_, peripherals::TSC, mode::Blocking>, | ||
| 126 | sensor_pin: TscIOPin, | ||
| 127 | ) -> Option<u16> { | ||
| 128 | for _ in 0..MAX_GROUP_STATUS_READ_ATTEMPTS { | ||
| 129 | match touch_controller.group_get_status(sensor_pin.group()) { | ||
| 130 | GroupStatus::Complete => { | ||
| 131 | return Some(touch_controller.group_get_value(sensor_pin.group())); | ||
| 132 | } | ||
| 133 | GroupStatus::Ongoing => { | ||
| 134 | // if you end up here a lot, then you prob need to increase discharge_delay | ||
| 135 | // or consider changing the code to adjust the discharge_delay dynamically | ||
| 136 | info!("Acquisition still ongoing"); | ||
| 137 | Timer::after_millis(1).await; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | } | ||
| 141 | None | ||
| 142 | } | ||
diff --git a/examples/stm32l0/src/bin/tsc_multipin.rs b/examples/stm32l0/src/bin/tsc_multipin.rs new file mode 100644 index 000000000..6170d0799 --- /dev/null +++ b/examples/stm32l0/src/bin/tsc_multipin.rs | |||
| @@ -0,0 +1,233 @@ | |||
| 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 method to switch between different channels | ||
| 13 | // 3. Read and interpret touch values from multiple channels in the same group | ||
| 14 | // | ||
| 15 | // Suggested physical setup on STM32L073RZ Nucleo board: | ||
| 16 | // - Connect a 1000pF capacitor between pin PA0 (label A0) and GND. This is the sampling capacitor for TSC | ||
| 17 | // group 1. | ||
| 18 | // - Connect one end of a 1K resistor to pin PA1 (label A1) and leave the other end loose. | ||
| 19 | // The loose end will act as a touch sensor. | ||
| 20 | // | ||
| 21 | // - Connect a 1000pF capacitor between pin PB3 (label D3) and GND. This is the sampling capacitor for TSC | ||
| 22 | // group 5. | ||
| 23 | // - Connect one end of another 1K resistor to pin PB4 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 PB6 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 | // - PA0 as sampling capacitor, TSC group 1 IO1 (label A0) | ||
| 30 | // - PA1 as channel, TSC group 1 IO2 (label A1) | ||
| 31 | // - PB3 as sampling capacitor, TSC group 5 IO1 (label D3) | ||
| 32 | // - PB4 as channel, TSC group 5 IO2 (label D3) | ||
| 33 | // - PB6 as channel, TSC group 5 IO3 (label D5) | ||
| 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 | // - If touch is not detected, try adjusting the SENSOR_THRESHOLD value. | ||
| 48 | // - Experiment with different values for ct_pulse_high_length, ct_pulse_low_length, | ||
| 49 | // pulse_generator_prescaler, max_count_value, and discharge_delay to optimize sensitivity. | ||
| 50 | // | ||
| 51 | // Note: Configuration values and sampling capacitor value have been determined experimentally. | ||
| 52 | // Optimal values may vary based on your specific hardware setup. | ||
| 53 | // Pins have been chosen for their convenient locations on the STM32L073RZ board. Refer to the | ||
| 54 | // official relevant STM32 datasheets and nucleo-board user manuals to find suitable | ||
| 55 | // alternative pins. | ||
| 56 | // | ||
| 57 | // Beware for STM32L073RZ nucleo-board, that PA2 and PA3 is used for the uart connection to | ||
| 58 | // the programmer chip. If you try to use these two pins for TSC, you will get strange | ||
| 59 | // readings, unless you somehow reconfigure/re-wire your nucleo-board. | ||
| 60 | // No errors or warnings will be emitted, they will just silently not work as expected. | ||
| 61 | // (see nucleo user manual UM1724, Rev 14, page 25) | ||
| 62 | |||
| 63 | #![no_std] | ||
| 64 | #![no_main] | ||
| 65 | |||
| 66 | use defmt::*; | ||
| 67 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 68 | use embassy_stm32::tsc::{self, *}; | ||
| 69 | use embassy_stm32::{bind_interrupts, mode, peripherals}; | ||
| 70 | use embassy_time::Timer; | ||
| 71 | use {defmt_rtt as _, panic_probe as _}; | ||
| 72 | |||
| 73 | bind_interrupts!(struct Irqs { | ||
| 74 | TSC => InterruptHandler<embassy_stm32::peripherals::TSC>; | ||
| 75 | }); | ||
| 76 | |||
| 77 | const MAX_GROUP_STATUS_READ_ATTEMPTS: usize = 10; | ||
| 78 | |||
| 79 | async fn read_touch_values( | ||
| 80 | touch_controller: &mut tsc::Tsc<'_, peripherals::TSC, mode::Async>, | ||
| 81 | tsc_acquisition_bank: &TscAcquisitionBank, | ||
| 82 | ) -> Option<TscAcquisitionBankReadings> { | ||
| 83 | for _ in 0..MAX_GROUP_STATUS_READ_ATTEMPTS { | ||
| 84 | let status = touch_controller.get_acquisition_bank_status(tsc_acquisition_bank); | ||
| 85 | if status.all_complete() { | ||
| 86 | let r = touch_controller.get_acquisition_bank_values(tsc_acquisition_bank); | ||
| 87 | return Some(r); | ||
| 88 | } else { | ||
| 89 | info!("Acquisition still ongoing"); | ||
| 90 | Timer::after_millis(1).await; | ||
| 91 | } | ||
| 92 | } | ||
| 93 | info!("Acquisition failed after {} attempts", MAX_GROUP_STATUS_READ_ATTEMPTS); | ||
| 94 | None | ||
| 95 | } | ||
| 96 | |||
| 97 | const SENSOR_THRESHOLD: u16 = 35; | ||
| 98 | |||
| 99 | async fn acquire_sensors( | ||
| 100 | touch_controller: &mut Tsc<'static, peripherals::TSC, mode::Async>, | ||
| 101 | tsc_acquisition_bank: &TscAcquisitionBank, | ||
| 102 | ) { | ||
| 103 | touch_controller.set_active_channels_mask(tsc_acquisition_bank.mask()); | ||
| 104 | touch_controller.start(); | ||
| 105 | touch_controller.pend_for_acquisition().await; | ||
| 106 | touch_controller.discharge_io(true); | ||
| 107 | let discharge_delay = 5; // ms | ||
| 108 | Timer::after_millis(discharge_delay).await; | ||
| 109 | } | ||
| 110 | |||
| 111 | #[embassy_executor::main] | ||
| 112 | async fn main(_spawner: embassy_executor::Spawner) { | ||
| 113 | let device_config = embassy_stm32::Config::default(); | ||
| 114 | let context = embassy_stm32::init(device_config); | ||
| 115 | |||
| 116 | // ---------- initial configuration of TSC ---------- | ||
| 117 | let mut pin_group1: PinGroupWithRoles<peripherals::TSC, G1> = PinGroupWithRoles::default(); | ||
| 118 | pin_group1.set_io1::<tsc_pin_roles::Sample>(context.PA0); | ||
| 119 | let tsc_sensor0 = pin_group1.set_io2(context.PA1); | ||
| 120 | |||
| 121 | let mut pin_group5: PinGroupWithRoles<peripherals::TSC, G5> = PinGroupWithRoles::default(); | ||
| 122 | pin_group5.set_io1::<tsc_pin_roles::Sample>(context.PB3); | ||
| 123 | let tsc_sensor1 = pin_group5.set_io2(context.PB4); | ||
| 124 | let tsc_sensor2 = pin_group5.set_io3(context.PB6); | ||
| 125 | |||
| 126 | let config = tsc::Config { | ||
| 127 | ct_pulse_high_length: ChargeTransferPulseCycle::_16, | ||
| 128 | ct_pulse_low_length: ChargeTransferPulseCycle::_16, | ||
| 129 | spread_spectrum: false, | ||
| 130 | spread_spectrum_deviation: SSDeviation::new(2).unwrap(), | ||
| 131 | spread_spectrum_prescaler: false, | ||
| 132 | pulse_generator_prescaler: PGPrescalerDivider::_16, | ||
| 133 | max_count_value: MaxCount::_255, | ||
| 134 | io_default_mode: false, | ||
| 135 | synchro_pin_polarity: false, | ||
| 136 | acquisition_mode: false, | ||
| 137 | max_count_interrupt: false, | ||
| 138 | }; | ||
| 139 | |||
| 140 | let pin_groups: PinGroups<peripherals::TSC> = PinGroups { | ||
| 141 | g1: Some(pin_group1.pin_group), | ||
| 142 | g5: Some(pin_group5.pin_group), | ||
| 143 | ..Default::default() | ||
| 144 | }; | ||
| 145 | |||
| 146 | let mut touch_controller = tsc::Tsc::new_async(context.TSC, pin_groups, config, Irqs).unwrap(); | ||
| 147 | |||
| 148 | // ---------- setting up acquisition banks ---------- | ||
| 149 | // sensor0 and sensor1 in this example belong to different TSC-groups, | ||
| 150 | // therefore we can acquire and read them both in one go. | ||
| 151 | let bank1 = touch_controller.create_acquisition_bank(TscAcquisitionBankPins { | ||
| 152 | g1_pin: Some(tsc_sensor0), | ||
| 153 | g5_pin: Some(tsc_sensor1), | ||
| 154 | ..Default::default() | ||
| 155 | }); | ||
| 156 | // `sensor1` and `sensor2` belongs to the same TSC-group, therefore we must make sure to | ||
| 157 | // acquire them one at the time. Therefore, we organize them into different acquisition banks. | ||
| 158 | let bank2 = touch_controller.create_acquisition_bank(TscAcquisitionBankPins { | ||
| 159 | g5_pin: Some(tsc_sensor2), | ||
| 160 | ..Default::default() | ||
| 161 | }); | ||
| 162 | |||
| 163 | // Check if TSC is ready | ||
| 164 | if touch_controller.get_state() != State::Ready { | ||
| 165 | crate::panic!("TSC not ready!"); | ||
| 166 | } | ||
| 167 | |||
| 168 | info!("TSC initialized successfully"); | ||
| 169 | |||
| 170 | // LED2 on the STM32L073RZ nucleo-board (PA5) | ||
| 171 | let mut led = Output::new(context.PA5, Level::High, Speed::Low); | ||
| 172 | |||
| 173 | let mut led_state = false; | ||
| 174 | |||
| 175 | loop { | ||
| 176 | acquire_sensors(&mut touch_controller, &bank1).await; | ||
| 177 | let readings1: TscAcquisitionBankReadings = read_touch_values(&mut touch_controller, &bank1) | ||
| 178 | .await | ||
| 179 | .expect("should be able to read values for bank 1"); | ||
| 180 | acquire_sensors(&mut touch_controller, &bank2).await; | ||
| 181 | let readings2: TscAcquisitionBankReadings = read_touch_values(&mut touch_controller, &bank2) | ||
| 182 | .await | ||
| 183 | .expect("should be able to read values for bank 2"); | ||
| 184 | |||
| 185 | let mut touched_sensors_count = 0; | ||
| 186 | for reading in readings1.iter() { | ||
| 187 | info!("{}", reading); | ||
| 188 | if reading.sensor_value < SENSOR_THRESHOLD { | ||
| 189 | touched_sensors_count += 1; | ||
| 190 | } | ||
| 191 | } | ||
| 192 | for reading in readings2.iter() { | ||
| 193 | info!("{}", reading); | ||
| 194 | if reading.sensor_value < SENSOR_THRESHOLD { | ||
| 195 | touched_sensors_count += 1; | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | match touched_sensors_count { | ||
| 200 | 0 => { | ||
| 201 | // No sensors touched, turn off the LED | ||
| 202 | led.set_low(); | ||
| 203 | led_state = false; | ||
| 204 | } | ||
| 205 | 1 => { | ||
| 206 | // One sensor touched, blink slowly | ||
| 207 | led_state = !led_state; | ||
| 208 | if led_state { | ||
| 209 | led.set_high(); | ||
| 210 | } else { | ||
| 211 | led.set_low(); | ||
| 212 | } | ||
| 213 | Timer::after_millis(200).await; | ||
| 214 | } | ||
| 215 | 2 => { | ||
| 216 | // Two sensors touched, blink faster | ||
| 217 | led_state = !led_state; | ||
| 218 | if led_state { | ||
| 219 | led.set_high(); | ||
| 220 | } else { | ||
| 221 | led.set_low(); | ||
| 222 | } | ||
| 223 | Timer::after_millis(50).await; | ||
| 224 | } | ||
| 225 | 3 => { | ||
| 226 | // All three sensors touched, LED constantly on | ||
| 227 | led.set_high(); | ||
| 228 | led_state = true; | ||
| 229 | } | ||
| 230 | _ => crate::unreachable!(), // This case should never occur with 3 sensors | ||
| 231 | } | ||
| 232 | } | ||
| 233 | } | ||
diff --git a/examples/stm32l4/.cargo/config.toml b/examples/stm32l4/.cargo/config.toml index 83fc6d6f8..d71fb1517 100644 --- a/examples/stm32l4/.cargo/config.toml +++ b/examples/stm32l4/.cargo/config.toml | |||
| @@ -2,7 +2,8 @@ | |||
| 2 | # replace STM32F429ZITx with your chip as listed in `probe-rs chip list` | 2 | # replace STM32F429ZITx with your chip as listed in `probe-rs chip list` |
| 3 | #runner = "probe-rs run --chip STM32L475VGT6" | 3 | #runner = "probe-rs run --chip STM32L475VGT6" |
| 4 | #runner = "probe-rs run --chip STM32L475VG" | 4 | #runner = "probe-rs run --chip STM32L475VG" |
| 5 | runner = "probe-rs run --chip STM32L4S5QI" | 5 | #runner = "probe-rs run --chip STM32L4S5QI" |
| 6 | runner = "probe-rs run --chip STM32L4R5ZITxP" | ||
| 6 | 7 | ||
| 7 | [build] | 8 | [build] |
| 8 | target = "thumbv7em-none-eabi" | 9 | target = "thumbv7em-none-eabi" |
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index b172878c1..512bb8064 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml | |||
| @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | # Change stm32l4s5vi to your chip name, if necessary. | 8 | # Change stm32l4s5vi to your chip name, if necessary. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4r5zi", "memory-x", "time-driver-any", "exti", "chrono"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } |
diff --git a/examples/stm32l4/README.md b/examples/stm32l4/README.md new file mode 100644 index 000000000..e463c18a0 --- /dev/null +++ b/examples/stm32l4/README.md | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | # Examples for STM32L4 family | ||
| 2 | Run individual examples with | ||
| 3 | ``` | ||
| 4 | cargo run --bin <module-name> | ||
| 5 | ``` | ||
| 6 | for example | ||
| 7 | ``` | ||
| 8 | cargo run --bin blinky | ||
| 9 | ``` | ||
| 10 | |||
| 11 | ## Checklist before running examples | ||
| 12 | You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using. | ||
| 13 | |||
| 14 | * [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for L4R5ZI-P it should be `probe-rs run --chip STM32L4R5ZITxP`. (use `probe-rs chip list` to find your chip) | ||
| 15 | * [ ] Update Cargo.toml to have the correct `embassy-stm32` feature. For example for L4R5ZI-P it should be `stm32l4r5zi`. Look in the `Cargo.toml` file of the `embassy-stm32` project to find the correct feature flag for your chip. | ||
| 16 | * [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. | ||
| 17 | * [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic | ||
| 18 | |||
| 19 | If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: | ||
| 20 | |||
| 21 | * Which example you are trying to run | ||
| 22 | * Which chip and board you are using | ||
| 23 | |||
| 24 | Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org | ||
diff --git a/examples/stm32l4/src/bin/tsc_async.rs b/examples/stm32l4/src/bin/tsc_async.rs new file mode 100644 index 000000000..ada2c468f --- /dev/null +++ b/examples/stm32l4/src/bin/tsc_async.rs | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | // Example of async 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 async TSC interface | ||
| 6 | // 3. Waiting for acquisition completion using `pend_for_acquisition` | ||
| 7 | // 4. Reading touch values and controlling an LED based on the results | ||
| 8 | // | ||
| 9 | // Suggested physical setup on STM32L4R5ZI-P board: | ||
| 10 | // - Connect a 1000pF capacitor between pin PB4 (D25) and GND. This is your sampling capacitor. | ||
| 11 | // - Connect one end of a 1K resistor to pin PB5 (D21) 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 2 of the TSC: | ||
| 15 | // - PB4 (D25) as the sampling capacitor, TSC group 2 IO1 | ||
| 16 | // - PB5 (D21) as the channel pin, TSC group 2 IO2 | ||
| 17 | // | ||
| 18 | // The program continuously reads the touch sensor value: | ||
| 19 | // - It starts acquisition, waits for completion using `pend_for_acquisition`, and reads the value. | ||
| 20 | // - The LED (connected to PB14) is turned on when touch is detected (sensor value < SENSOR_THRESHOLD). | ||
| 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 | |||
| 31 | #![no_std] | ||
| 32 | #![no_main] | ||
| 33 | |||
| 34 | use defmt::*; | ||
| 35 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 36 | use embassy_stm32::tsc::{self, *}; | ||
| 37 | use embassy_stm32::{bind_interrupts, peripherals}; | ||
| 38 | use embassy_time::Timer; | ||
| 39 | use {defmt_rtt as _, panic_probe as _}; | ||
| 40 | |||
| 41 | bind_interrupts!(struct Irqs { | ||
| 42 | TSC => InterruptHandler<embassy_stm32::peripherals::TSC>; | ||
| 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 mut pin_group: PinGroupWithRoles<peripherals::TSC, G2> = PinGroupWithRoles::default(); | ||
| 52 | // D25 | ||
| 53 | pin_group.set_io1::<tsc_pin_roles::Sample>(context.PB4); | ||
| 54 | // D21 | ||
| 55 | let tsc_sensor = pin_group.set_io2::<tsc_pin_roles::Channel>(context.PB5); | ||
| 56 | |||
| 57 | let pin_groups: PinGroups<peripherals::TSC> = PinGroups { | ||
| 58 | g2: Some(pin_group.pin_group), | ||
| 59 | ..Default::default() | ||
| 60 | }; | ||
| 61 | |||
| 62 | let tsc_conf = Config { | ||
| 63 | ct_pulse_high_length: ChargeTransferPulseCycle::_4, | ||
| 64 | ct_pulse_low_length: ChargeTransferPulseCycle::_4, | ||
| 65 | spread_spectrum: false, | ||
| 66 | spread_spectrum_deviation: SSDeviation::new(2).unwrap(), | ||
| 67 | spread_spectrum_prescaler: false, | ||
| 68 | pulse_generator_prescaler: PGPrescalerDivider::_16, | ||
| 69 | max_count_value: MaxCount::_255, | ||
| 70 | io_default_mode: false, | ||
| 71 | synchro_pin_polarity: false, | ||
| 72 | acquisition_mode: false, | ||
| 73 | max_count_interrupt: false, | ||
| 74 | }; | ||
| 75 | |||
| 76 | let mut touch_controller = tsc::Tsc::new_async(context.TSC, pin_groups, tsc_conf, Irqs).unwrap(); | ||
| 77 | |||
| 78 | // Check if TSC is ready | ||
| 79 | if touch_controller.get_state() != State::Ready { | ||
| 80 | info!("TSC not ready!"); | ||
| 81 | return; | ||
| 82 | } | ||
| 83 | info!("TSC initialized successfully"); | ||
| 84 | |||
| 85 | let mut led = Output::new(context.PB14, Level::High, Speed::Low); | ||
| 86 | |||
| 87 | let discharge_delay = 1; // ms | ||
| 88 | |||
| 89 | info!("Starting touch_controller interface"); | ||
| 90 | loop { | ||
| 91 | touch_controller.set_active_channels_mask(tsc_sensor.pin.into()); | ||
| 92 | touch_controller.start(); | ||
| 93 | touch_controller.pend_for_acquisition().await; | ||
| 94 | touch_controller.discharge_io(true); | ||
| 95 | Timer::after_millis(discharge_delay).await; | ||
| 96 | |||
| 97 | let group_val = touch_controller.group_get_value(tsc_sensor.pin.group()); | ||
| 98 | info!("Touch value: {}", group_val); | ||
| 99 | |||
| 100 | if group_val < SENSOR_THRESHOLD { | ||
| 101 | led.set_high(); | ||
| 102 | } else { | ||
| 103 | led.set_low(); | ||
| 104 | } | ||
| 105 | |||
| 106 | Timer::after_millis(100).await; | ||
| 107 | } | ||
| 108 | } | ||
diff --git a/examples/stm32l4/src/bin/tsc_blocking.rs b/examples/stm32l4/src/bin/tsc_blocking.rs new file mode 100644 index 000000000..76aba55ba --- /dev/null +++ b/examples/stm32l4/src/bin/tsc_blocking.rs | |||
| @@ -0,0 +1,147 @@ | |||
| 1 | // # Example of blocking TSC (Touch Sensing Controller) that lights an LED when touch is detected | ||
| 2 | // | ||
| 3 | // This example demonstrates how to use the Touch Sensing Controller (TSC) in blocking mode on an STM32L4R5ZI-P board. | ||
| 4 | // | ||
| 5 | // ## This example demonstrates: | ||
| 6 | // | ||
| 7 | // 1. Configuring a single TSC channel pin | ||
| 8 | // 2. Using the blocking TSC interface with polling | ||
| 9 | // 3. Waiting for acquisition completion using `poll_for_acquisition` | ||
| 10 | // 4. Reading touch values and controlling an LED based on the results | ||
| 11 | // | ||
| 12 | // ## Suggested physical setup on STM32L4R5ZI-P board: | ||
| 13 | // | ||
| 14 | // - Connect a 1000pF capacitor between pin PB4 (D25) and GND. This is your sampling capacitor. | ||
| 15 | // - Connect one end of a 1K resistor to pin PB5 (D21) and leave the other end loose. | ||
| 16 | // The loose end will act as the touch sensor which will register your touch. | ||
| 17 | // | ||
| 18 | // ## Pin Configuration: | ||
| 19 | // | ||
| 20 | // The example uses two pins from Group 2 of the TSC: | ||
| 21 | // - PB4 (D25) as the sampling capacitor, TSC group 2 IO1 | ||
| 22 | // - PB5 (D21) as the channel pin, TSC group 2 IO2 | ||
| 23 | // | ||
| 24 | // ## Program Behavior: | ||
| 25 | // | ||
| 26 | // The program continuously reads the touch sensor value: | ||
| 27 | // - It starts acquisition, waits for completion using `poll_for_acquisition`, and reads the value. | ||
| 28 | // - The LED (connected to PB14) is turned on when touch is detected (sensor value < SENSOR_THRESHOLD). | ||
| 29 | // - Touch values are logged to the console. | ||
| 30 | // | ||
| 31 | // ## Troubleshooting: | ||
| 32 | // | ||
| 33 | // - If touch is not detected, try adjusting the SENSOR_THRESHOLD value (currently set to 25). | ||
| 34 | // - Experiment with different values for ct_pulse_high_length, ct_pulse_low_length, | ||
| 35 | // pulse_generator_prescaler, max_count_value, and discharge_delay to optimize sensitivity. | ||
| 36 | // - Be aware that for some boards, there might be overlapping concerns between some pins, | ||
| 37 | // such as UART connections for the programmer. No errors or warnings will be emitted if you | ||
| 38 | // try to use such a pin for TSC, but you may get strange sensor readings. | ||
| 39 | // | ||
| 40 | // Note: Configuration values and sampling capacitor value have been determined experimentally. | ||
| 41 | // Optimal values may vary based on your specific hardware setup. Refer to the official | ||
| 42 | // STM32L4R5ZI-P datasheet and user manuals for more information on pin configurations and TSC functionality. | ||
| 43 | |||
| 44 | #![no_std] | ||
| 45 | #![no_main] | ||
| 46 | |||
| 47 | use defmt::*; | ||
| 48 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 49 | use embassy_stm32::tsc::{self, *}; | ||
| 50 | use embassy_stm32::{mode, peripherals}; | ||
| 51 | use embassy_time::Timer; | ||
| 52 | use {defmt_rtt as _, panic_probe as _}; | ||
| 53 | |||
| 54 | const SENSOR_THRESHOLD: u16 = 25; // Adjust this value based on your setup | ||
| 55 | |||
| 56 | #[embassy_executor::main] | ||
| 57 | async fn main(_spawner: embassy_executor::Spawner) { | ||
| 58 | let device_config = embassy_stm32::Config::default(); | ||
| 59 | let context = embassy_stm32::init(device_config); | ||
| 60 | |||
| 61 | let tsc_conf = Config { | ||
| 62 | ct_pulse_high_length: ChargeTransferPulseCycle::_4, | ||
| 63 | ct_pulse_low_length: ChargeTransferPulseCycle::_4, | ||
| 64 | spread_spectrum: false, | ||
| 65 | spread_spectrum_deviation: SSDeviation::new(2).unwrap(), | ||
| 66 | spread_spectrum_prescaler: false, | ||
| 67 | pulse_generator_prescaler: PGPrescalerDivider::_16, | ||
| 68 | max_count_value: MaxCount::_255, | ||
| 69 | io_default_mode: false, | ||
| 70 | synchro_pin_polarity: false, | ||
| 71 | acquisition_mode: false, | ||
| 72 | max_count_interrupt: false, | ||
| 73 | }; | ||
| 74 | |||
| 75 | let mut g2: PinGroupWithRoles<peripherals::TSC, G2> = PinGroupWithRoles::default(); | ||
| 76 | // D25 | ||
| 77 | g2.set_io1::<tsc_pin_roles::Sample>(context.PB4); | ||
| 78 | // D21 | ||
| 79 | let tsc_sensor = g2.set_io2::<tsc_pin_roles::Channel>(context.PB5); | ||
| 80 | |||
| 81 | let pin_groups: PinGroups<peripherals::TSC> = PinGroups { | ||
| 82 | g2: Some(g2.pin_group), | ||
| 83 | ..Default::default() | ||
| 84 | }; | ||
| 85 | |||
| 86 | let mut touch_controller = tsc::Tsc::new_blocking(context.TSC, pin_groups, tsc_conf).unwrap(); | ||
| 87 | |||
| 88 | // Check if TSC is ready | ||
| 89 | if touch_controller.get_state() != State::Ready { | ||
| 90 | crate::panic!("TSC not ready!"); | ||
| 91 | } | ||
| 92 | info!("TSC initialized successfully"); | ||
| 93 | |||
| 94 | let mut led = Output::new(context.PB14, Level::High, Speed::Low); | ||
| 95 | |||
| 96 | // smaller sample capacitor discharge faster and can be used with shorter delay. | ||
| 97 | let discharge_delay = 5; // ms | ||
| 98 | |||
| 99 | // the interval at which the loop polls for new touch sensor values | ||
| 100 | let polling_interval = 100; // ms | ||
| 101 | |||
| 102 | info!("polling for touch"); | ||
| 103 | loop { | ||
| 104 | touch_controller.set_active_channels_mask(tsc_sensor.pin.into()); | ||
| 105 | touch_controller.start(); | ||
| 106 | touch_controller.poll_for_acquisition(); | ||
| 107 | touch_controller.discharge_io(true); | ||
| 108 | Timer::after_millis(discharge_delay).await; | ||
| 109 | |||
| 110 | match read_touch_value(&mut touch_controller, tsc_sensor.pin).await { | ||
| 111 | Some(v) => { | ||
| 112 | info!("sensor value {}", v); | ||
| 113 | if v < SENSOR_THRESHOLD { | ||
| 114 | led.set_high(); | ||
| 115 | } else { | ||
| 116 | led.set_low(); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | None => led.set_low(), | ||
| 120 | } | ||
| 121 | |||
| 122 | Timer::after_millis(polling_interval).await; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | const MAX_GROUP_STATUS_READ_ATTEMPTS: usize = 10; | ||
| 127 | |||
| 128 | // attempt to read group status and delay when still ongoing | ||
| 129 | async fn read_touch_value( | ||
| 130 | touch_controller: &mut tsc::Tsc<'_, peripherals::TSC, mode::Blocking>, | ||
| 131 | sensor_pin: TscIOPin, | ||
| 132 | ) -> Option<u16> { | ||
| 133 | for _ in 0..MAX_GROUP_STATUS_READ_ATTEMPTS { | ||
| 134 | match touch_controller.group_get_status(sensor_pin.group()) { | ||
| 135 | GroupStatus::Complete => { | ||
| 136 | return Some(touch_controller.group_get_value(sensor_pin.group())); | ||
| 137 | } | ||
| 138 | GroupStatus::Ongoing => { | ||
| 139 | // if you end up here a lot, then you prob need to increase discharge_delay | ||
| 140 | // or consider changing the code to adjust the discharge_delay dynamically | ||
| 141 | info!("Acquisition still ongoing"); | ||
| 142 | Timer::after_millis(1).await; | ||
| 143 | } | ||
| 144 | } | ||
| 145 | } | ||
| 146 | None | ||
| 147 | } | ||
diff --git a/examples/stm32l4/src/bin/tsc_multipin.rs b/examples/stm32l4/src/bin/tsc_multipin.rs new file mode 100644 index 000000000..20a559514 --- /dev/null +++ b/examples/stm32l4/src/bin/tsc_multipin.rs | |||
| @@ -0,0 +1,222 @@ | |||
| 1 | // # Example of TSC (Touch Sensing Controller) using multiple pins from the same TSC group | ||
| 2 | // | ||
| 3 | // This example demonstrates how to use the Touch Sensing Controller (TSC) with multiple pins, including pins from the same TSC group, on an STM32L4R5ZI-P board. | ||
| 4 | // | ||
| 5 | // ## Key Concepts | ||
| 6 | // | ||
| 7 | // - Only one TSC pin for each TSC group can be acquired and read at a time. | ||
| 8 | // - To control which channel pins are acquired and read, we must write a mask before initiating an acquisition. | ||
| 9 | // - We organize channel pins into acquisition banks to manage this process efficiently. | ||
| 10 | // - Each acquisition bank can contain exactly one channel pin per TSC group and will contain the relevant mask. | ||
| 11 | // | ||
| 12 | // ## This example demonstrates how to: | ||
| 13 | // | ||
| 14 | // 1. Configure multiple channel pins within a single TSC group | ||
| 15 | // 2. Use the set_active_channels method to switch between different channels | ||
| 16 | // 3. Read and interpret touch values from multiple channels in the same group | ||
| 17 | // | ||
| 18 | // ## Suggested physical setup on STM32L4R5ZI-P board: | ||
| 19 | // | ||
| 20 | // - Connect a 1000pF capacitor between pin PB12 (D19) and GND. This is the sampling capacitor for TSC group 1. | ||
| 21 | // - Connect one end of a 1K resistor to pin PB13 (D18) and leave the other end loose. This will act as a touch sensor. | ||
| 22 | // - Connect a 1000pF capacitor between pin PB4 (D25) and GND. This is the sampling capacitor for TSC group 2. | ||
| 23 | // - Connect one end of a 1K resistor to pin PB5 (D22) and leave the other end loose. This will act as a touch sensor. | ||
| 24 | // - Connect one end of another 1K resistor to pin PB6 (D71) and leave the other end loose. This will act as a touch sensor. | ||
| 25 | // | ||
| 26 | // ## Pin Configuration: | ||
| 27 | // | ||
| 28 | // The example uses pins from two TSC groups: | ||
| 29 | // | ||
| 30 | // - Group 1: | ||
| 31 | // - PB12 (D19) as sampling capacitor (TSC group 1 IO1) | ||
| 32 | // - PB13 (D18) as channel (TSC group 1 IO2) | ||
| 33 | // - Group 2: | ||
| 34 | // - PB4 (D25) as sampling capacitor (TSC group 2 IO1) | ||
| 35 | // - PB5 (D22) as channel (TSC group 2 IO2) | ||
| 36 | // - PB6 (D71) as channel (TSC group 2 IO3) | ||
| 37 | // | ||
| 38 | // The pins have been chosen for their convenient locations on the STM32L4R5ZI-P board, making it easy to add capacitors and resistors directly to the board without special connectors, breadboards, or soldering. | ||
| 39 | // | ||
| 40 | // ## Program Behavior: | ||
| 41 | // | ||
| 42 | // The program reads the designated channel pins and adjusts the LED (connected to PB14) blinking pattern based on which sensor(s) are touched: | ||
| 43 | // | ||
| 44 | // - No touch: LED off | ||
| 45 | // - One sensor touched: Slow blinking | ||
| 46 | // - Two sensors touched: Fast blinking | ||
| 47 | // - Three sensors touched: LED constantly on | ||
| 48 | // | ||
| 49 | // ## Troubleshooting: | ||
| 50 | // | ||
| 51 | // - If touch is not detected, try adjusting the SENSOR_THRESHOLD value (currently set to 20). | ||
| 52 | // - 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. | ||
| 53 | // - Be aware that for some boards there will be overlapping concerns between some pins, for | ||
| 54 | // example UART connection for the programmer to the MCU and a TSC pin. No errors or warning will | ||
| 55 | // be emitted if you try to use such a pin for TSC, but you will get strange sensor readings. | ||
| 56 | // | ||
| 57 | // 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 STM32L4R5ZI-P datasheet and user manuals for more information on pin configurations and TSC functionality. | ||
| 58 | |||
| 59 | #![no_std] | ||
| 60 | #![no_main] | ||
| 61 | |||
| 62 | use defmt::*; | ||
| 63 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 64 | use embassy_stm32::tsc::{self, *}; | ||
| 65 | use embassy_stm32::{bind_interrupts, mode, peripherals}; | ||
| 66 | use embassy_time::Timer; | ||
| 67 | use {defmt_rtt as _, panic_probe as _}; | ||
| 68 | |||
| 69 | bind_interrupts!(struct Irqs { | ||
| 70 | TSC => InterruptHandler<embassy_stm32::peripherals::TSC>; | ||
| 71 | }); | ||
| 72 | |||
| 73 | const MAX_GROUP_STATUS_READ_ATTEMPTS: usize = 10; | ||
| 74 | |||
| 75 | async fn read_touch_values( | ||
| 76 | touch_controller: &mut tsc::Tsc<'_, peripherals::TSC, mode::Async>, | ||
| 77 | tsc_acquisition_bank: &TscAcquisitionBank, | ||
| 78 | ) -> Option<TscAcquisitionBankReadings> { | ||
| 79 | for _ in 0..MAX_GROUP_STATUS_READ_ATTEMPTS { | ||
| 80 | let status = touch_controller.get_acquisition_bank_status(tsc_acquisition_bank); | ||
| 81 | if status.all_complete() { | ||
| 82 | let r = touch_controller.get_acquisition_bank_values(tsc_acquisition_bank); | ||
| 83 | return Some(r); | ||
| 84 | } else { | ||
| 85 | info!("Acquisition still ongoing"); | ||
| 86 | Timer::after_millis(1).await; | ||
| 87 | } | ||
| 88 | } | ||
| 89 | info!("Acquisition failed after {} attempts", MAX_GROUP_STATUS_READ_ATTEMPTS); | ||
| 90 | None | ||
| 91 | } | ||
| 92 | |||
| 93 | const SENSOR_THRESHOLD: u16 = 20; | ||
| 94 | |||
| 95 | async fn acquire_sensors( | ||
| 96 | touch_controller: &mut Tsc<'static, peripherals::TSC, mode::Async>, | ||
| 97 | tsc_acquisition_bank: &TscAcquisitionBank, | ||
| 98 | ) { | ||
| 99 | touch_controller.set_active_channels_mask(tsc_acquisition_bank.mask()); | ||
| 100 | touch_controller.start(); | ||
| 101 | touch_controller.pend_for_acquisition().await; | ||
| 102 | touch_controller.discharge_io(true); | ||
| 103 | let discharge_delay = 1; // ms | ||
| 104 | Timer::after_millis(discharge_delay).await; | ||
| 105 | } | ||
| 106 | |||
| 107 | #[embassy_executor::main] | ||
| 108 | async fn main(_spawner: embassy_executor::Spawner) { | ||
| 109 | let device_config = embassy_stm32::Config::default(); | ||
| 110 | let context = embassy_stm32::init(device_config); | ||
| 111 | |||
| 112 | // ---------- initial configuration of TSC ---------- | ||
| 113 | let mut g1: PinGroupWithRoles<peripherals::TSC, G1> = PinGroupWithRoles::default(); | ||
| 114 | g1.set_io1::<tsc_pin_roles::Sample>(context.PB12); | ||
| 115 | let sensor0 = g1.set_io2::<tsc_pin_roles::Channel>(context.PB13); | ||
| 116 | |||
| 117 | let mut g2: PinGroupWithRoles<peripherals::TSC, G2> = PinGroupWithRoles::default(); | ||
| 118 | g2.set_io1::<tsc_pin_roles::Sample>(context.PB4); | ||
| 119 | let sensor1 = g2.set_io2(context.PB5); | ||
| 120 | let sensor2 = g2.set_io3(context.PB6); | ||
| 121 | |||
| 122 | let config = tsc::Config { | ||
| 123 | ct_pulse_high_length: ChargeTransferPulseCycle::_16, | ||
| 124 | ct_pulse_low_length: ChargeTransferPulseCycle::_16, | ||
| 125 | spread_spectrum: false, | ||
| 126 | spread_spectrum_deviation: SSDeviation::new(2).unwrap(), | ||
| 127 | spread_spectrum_prescaler: false, | ||
| 128 | pulse_generator_prescaler: PGPrescalerDivider::_16, | ||
| 129 | max_count_value: MaxCount::_255, | ||
| 130 | io_default_mode: false, | ||
| 131 | synchro_pin_polarity: false, | ||
| 132 | acquisition_mode: false, | ||
| 133 | max_count_interrupt: false, | ||
| 134 | }; | ||
| 135 | |||
| 136 | let pin_groups: PinGroups<peripherals::TSC> = PinGroups { | ||
| 137 | g1: Some(g1.pin_group), | ||
| 138 | g2: Some(g2.pin_group), | ||
| 139 | ..Default::default() | ||
| 140 | }; | ||
| 141 | |||
| 142 | let mut touch_controller = tsc::Tsc::new_async(context.TSC, pin_groups, config, Irqs).unwrap(); | ||
| 143 | |||
| 144 | // ---------- setting up acquisition banks ---------- | ||
| 145 | // sensor0 and sensor1 belong to different TSC-groups, therefore we can acquire and | ||
| 146 | // read them both in one go. | ||
| 147 | let bank1 = touch_controller.create_acquisition_bank(TscAcquisitionBankPins { | ||
| 148 | g1_pin: Some(sensor0), | ||
| 149 | g2_pin: Some(sensor1), | ||
| 150 | ..Default::default() | ||
| 151 | }); | ||
| 152 | // `sensor1` and `sensor2` belongs to the same TSC-group, therefore we must make sure to | ||
| 153 | // acquire them one at the time. We do this by organizing them into different acquisition banks. | ||
| 154 | let bank2 = touch_controller.create_acquisition_bank(TscAcquisitionBankPins { | ||
| 155 | g2_pin: Some(sensor2), | ||
| 156 | ..Default::default() | ||
| 157 | }); | ||
| 158 | |||
| 159 | // Check if TSC is ready | ||
| 160 | if touch_controller.get_state() != State::Ready { | ||
| 161 | crate::panic!("TSC not ready!"); | ||
| 162 | } | ||
| 163 | |||
| 164 | info!("TSC initialized successfully"); | ||
| 165 | |||
| 166 | let mut led = Output::new(context.PB14, Level::High, Speed::Low); | ||
| 167 | |||
| 168 | let mut led_state = false; | ||
| 169 | |||
| 170 | loop { | ||
| 171 | acquire_sensors(&mut touch_controller, &bank1).await; | ||
| 172 | let readings1: TscAcquisitionBankReadings = read_touch_values(&mut touch_controller, &bank1) | ||
| 173 | .await | ||
| 174 | .expect("should be able to read values for bank 1"); | ||
| 175 | acquire_sensors(&mut touch_controller, &bank2).await; | ||
| 176 | let readings2: TscAcquisitionBankReadings = read_touch_values(&mut touch_controller, &bank2) | ||
| 177 | .await | ||
| 178 | .expect("should be able to read values for bank 2"); | ||
| 179 | |||
| 180 | let mut touched_sensors_count = 0; | ||
| 181 | for reading in readings1.iter().chain(readings2.iter()) { | ||
| 182 | info!("{}", reading); | ||
| 183 | if reading.sensor_value < SENSOR_THRESHOLD { | ||
| 184 | touched_sensors_count += 1; | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | match touched_sensors_count { | ||
| 189 | 0 => { | ||
| 190 | // No sensors touched, turn off the LED | ||
| 191 | led.set_low(); | ||
| 192 | led_state = false; | ||
| 193 | } | ||
| 194 | 1 => { | ||
| 195 | // One sensor touched, blink slowly | ||
| 196 | led_state = !led_state; | ||
| 197 | if led_state { | ||
| 198 | led.set_high(); | ||
| 199 | } else { | ||
| 200 | led.set_low(); | ||
| 201 | } | ||
| 202 | Timer::after_millis(200).await; | ||
| 203 | } | ||
| 204 | 2 => { | ||
| 205 | // Two sensors touched, blink faster | ||
| 206 | led_state = !led_state; | ||
| 207 | if led_state { | ||
| 208 | led.set_high(); | ||
| 209 | } else { | ||
| 210 | led.set_low(); | ||
| 211 | } | ||
| 212 | Timer::after_millis(50).await; | ||
| 213 | } | ||
| 214 | 3 => { | ||
| 215 | // All three sensors touched, LED constantly on | ||
| 216 | led.set_high(); | ||
| 217 | led_state = true; | ||
| 218 | } | ||
| 219 | _ => crate::unreachable!(), // This case should never occur with 3 sensors | ||
| 220 | } | ||
| 221 | } | ||
| 222 | } | ||
diff --git a/examples/stm32u5/src/bin/tsc.rs b/examples/stm32u5/src/bin/tsc.rs index eb15d275a..800486665 100644 --- a/examples/stm32u5/src/bin/tsc.rs +++ b/examples/stm32u5/src/bin/tsc.rs | |||
| @@ -2,8 +2,8 @@ | |||
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_stm32::bind_interrupts; | ||
| 6 | use embassy_stm32::tsc::{self, *}; | 5 | use embassy_stm32::tsc::{self, *}; |
| 6 | use embassy_stm32::{bind_interrupts, peripherals}; | ||
| 7 | use embassy_time::Timer; | 7 | use embassy_time::Timer; |
| 8 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 9 | ||
| @@ -33,63 +33,52 @@ async fn main(_spawner: embassy_executor::Spawner) { | |||
| 33 | synchro_pin_polarity: false, | 33 | synchro_pin_polarity: false, |
| 34 | acquisition_mode: false, | 34 | acquisition_mode: false, |
| 35 | max_count_interrupt: false, | 35 | max_count_interrupt: false, |
| 36 | channel_ios: TscIOPin::Group2Io2 | TscIOPin::Group7Io3, | ||
| 37 | shield_ios: TscIOPin::Group1Io3.into(), | ||
| 38 | sampling_ios: TscIOPin::Group1Io2 | TscIOPin::Group2Io1 | TscIOPin::Group7Io2, | ||
| 39 | }; | 36 | }; |
| 40 | 37 | ||
| 41 | let mut g1: PinGroup<embassy_stm32::peripherals::TSC, G1> = PinGroup::new(); | 38 | let mut g1: PinGroupWithRoles<peripherals::TSC, G1> = PinGroupWithRoles::default(); |
| 42 | g1.set_io2(context.PB13, PinType::Sample); | 39 | g1.set_io2::<tsc_pin_roles::Sample>(context.PB13); |
| 43 | g1.set_io3(context.PB14, PinType::Shield); | 40 | g1.set_io3::<tsc_pin_roles::Shield>(context.PB14); |
| 44 | 41 | ||
| 45 | let mut g2: PinGroup<embassy_stm32::peripherals::TSC, G2> = PinGroup::new(); | 42 | let mut g2: PinGroupWithRoles<peripherals::TSC, G2> = PinGroupWithRoles::default(); |
| 46 | g2.set_io1(context.PB4, PinType::Sample); | 43 | g2.set_io1::<tsc_pin_roles::Sample>(context.PB4); |
| 47 | g2.set_io2(context.PB5, PinType::Channel); | 44 | let sensor0 = g2.set_io2(context.PB5); |
| 48 | 45 | ||
| 49 | let mut g7: PinGroup<embassy_stm32::peripherals::TSC, G7> = PinGroup::new(); | 46 | let mut g7: PinGroupWithRoles<peripherals::TSC, G7> = PinGroupWithRoles::default(); |
| 50 | g7.set_io2(context.PE3, PinType::Sample); | 47 | g7.set_io2::<tsc_pin_roles::Sample>(context.PE3); |
| 51 | g7.set_io3(context.PE4, PinType::Channel); | 48 | let sensor1 = g7.set_io3(context.PE4); |
| 52 | 49 | ||
| 53 | let mut touch_controller = tsc::Tsc::new_async( | 50 | let pin_groups: PinGroups<peripherals::TSC> = PinGroups { |
| 54 | context.TSC, | 51 | g1: Some(g1.pin_group), |
| 55 | Some(g1), | 52 | g2: Some(g2.pin_group), |
| 56 | Some(g2), | 53 | g7: Some(g7.pin_group), |
| 57 | None, | 54 | ..Default::default() |
| 58 | None, | 55 | }; |
| 59 | None, | 56 | |
| 60 | None, | 57 | let mut touch_controller = tsc::Tsc::new_async(context.TSC, pin_groups, config, Irqs).unwrap(); |
| 61 | Some(g7), | ||
| 62 | None, | ||
| 63 | config, | ||
| 64 | Irqs, | ||
| 65 | ); | ||
| 66 | 58 | ||
| 67 | touch_controller.discharge_io(true); | 59 | let acquisition_bank = touch_controller.create_acquisition_bank(TscAcquisitionBankPins { |
| 68 | Timer::after_millis(1).await; | 60 | g2_pin: Some(sensor0), |
| 61 | g7_pin: Some(sensor1), | ||
| 62 | ..Default::default() | ||
| 63 | }); | ||
| 69 | 64 | ||
| 70 | touch_controller.start(); | 65 | touch_controller.set_active_channels_bank(&acquisition_bank); |
| 71 | 66 | ||
| 72 | let mut group_two_val = 0; | ||
| 73 | let mut group_seven_val = 0; | ||
| 74 | info!("Starting touch_controller interface"); | 67 | info!("Starting touch_controller interface"); |
| 75 | loop { | 68 | loop { |
| 69 | touch_controller.start(); | ||
| 76 | touch_controller.pend_for_acquisition().await; | 70 | touch_controller.pend_for_acquisition().await; |
| 77 | touch_controller.discharge_io(true); | 71 | touch_controller.discharge_io(true); |
| 78 | Timer::after_millis(1).await; | 72 | Timer::after_millis(1).await; |
| 79 | 73 | ||
| 80 | if touch_controller.group_get_status(Group::Two) == GroupStatus::Complete { | 74 | let status = touch_controller.get_acquisition_bank_status(&acquisition_bank); |
| 81 | group_two_val = touch_controller.group_get_value(Group::Two); | ||
| 82 | } | ||
| 83 | 75 | ||
| 84 | if touch_controller.group_get_status(Group::Seven) == GroupStatus::Complete { | 76 | if status.all_complete() { |
| 85 | group_seven_val = touch_controller.group_get_value(Group::Seven); | 77 | let read_values = touch_controller.get_acquisition_bank_values(&acquisition_bank); |
| 78 | let group2_reading = read_values.get_group_reading(Group::Two).unwrap(); | ||
| 79 | let group7_reading = read_values.get_group_reading(Group::Seven).unwrap(); | ||
| 80 | info!("group 2 value: {}", group2_reading.sensor_value); | ||
| 81 | info!("group 7 value: {}", group7_reading.sensor_value); | ||
| 86 | } | 82 | } |
| 87 | |||
| 88 | info!( | ||
| 89 | "Group Two value: {}, Group Seven value: {},", | ||
| 90 | group_two_val, group_seven_val | ||
| 91 | ); | ||
| 92 | |||
| 93 | touch_controller.start(); | ||
| 94 | } | 83 | } |
| 95 | } | 84 | } |
