Skip to content

Commit

Permalink
add examples for stm32l4
Browse files Browse the repository at this point in the history
  • Loading branch information
michelrandahl committed Aug 23, 2024
1 parent ce6bb46 commit 1a5fb2a
Show file tree
Hide file tree
Showing 10 changed files with 540 additions and 16 deletions.
6 changes: 3 additions & 3 deletions examples/stm32f3/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Examples for STM32L0 family
# Examples for STM32F3 family
Run individual examples with
```
cargo run --bin <module-name>
Expand All @@ -11,8 +11,8 @@ cargo run --bin blinky
## Checklist before running examples
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.

* [ ] 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`.
* [ ] Update Cargo.toml to have the correct `embassy-stm32` feature. For example for F303ZE it should be `stm32f303ze`.
* [ ] 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)
* [ ] 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.
* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic

Expand Down
4 changes: 2 additions & 2 deletions examples/stm32l0/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ cargo run --bin blinky
## Checklist before running examples
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.

* [ ] 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`.
* [ ] Update Cargo.toml to have the correct `embassy-stm32` feature. For example for L073RZ it should be `stm32l073rz`.
* [ ] 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)
* [ ] 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.
* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic

Expand Down
11 changes: 5 additions & 6 deletions examples/stm32l0/src/bin/tsc_async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,14 @@ async fn main(_spawner: embassy_executor::Spawner) {
pin_group.set_io1(context.PA0, PinType::Sample);
let sensor = pin_group.set_io2(context.PA1, PinType::Channel);

let config = tsc::Config {
ct_pulse_high_length: ChargeTransferPulseCycle::_16,
ct_pulse_low_length: ChargeTransferPulseCycle::_16,
let tsc_conf = Config {
ct_pulse_high_length: ChargeTransferPulseCycle::_4,
ct_pulse_low_length: ChargeTransferPulseCycle::_4,
spread_spectrum: false,
spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
spread_spectrum_prescaler: false,
pulse_generator_prescaler: PGPrescalerDivider::_16,
max_count_value: MaxCount::_8191,
max_count_value: MaxCount::_255,
io_default_mode: false,
synchro_pin_polarity: false,
acquisition_mode: false,
Expand All @@ -80,7 +80,7 @@ async fn main(_spawner: embassy_executor::Spawner) {
..Default::default()
};

let mut touch_controller = tsc::Tsc::new_async(context.TSC, pin_groups, config, Irqs).unwrap();
let mut touch_controller = tsc::Tsc::new_async(context.TSC, pin_groups, tsc_conf, Irqs).unwrap();

// Check if TSC is ready
if touch_controller.get_state() != State::Ready {
Expand All @@ -102,7 +102,6 @@ async fn main(_spawner: embassy_executor::Spawner) {
touch_controller.discharge_io(true);
Timer::after_millis(discharge_delay).await;

// TODO check group_status before attempting read?
let group_val = touch_controller.group_get_value(sensor.group());
info!("Touch value: {}", group_val);

Expand Down
3 changes: 0 additions & 3 deletions examples/stm32l0/src/bin/tsc_multipin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ async fn main(_spawner: embassy_executor::Spawner) {
let context = embassy_stm32::init(device_config);

// ---------- initial configuration of TSC ----------

let mut pin_group1: PinGroup<peripherals::TSC, G1> = PinGroup::new();
pin_group1.set_io1(context.PA0, PinType::Sample);
let sensor0 = pin_group1.set_io2(context.PA1, PinType::Channel);
Expand Down Expand Up @@ -231,7 +230,5 @@ async fn main(_spawner: embassy_executor::Spawner) {
}
_ => crate::unreachable!(), // This case should never occur with 3 sensors
}

Timer::after_millis(100).await;
}
}
3 changes: 2 additions & 1 deletion examples/stm32l4/.cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
#runner = "probe-rs run --chip STM32L475VGT6"
#runner = "probe-rs run --chip STM32L475VG"
runner = "probe-rs run --chip STM32L4S5QI"
#runner = "probe-rs run --chip STM32L4S5QI"
runner = "probe-rs run --chip STM32L4R5ZITxP"

[build]
target = "thumbv7em-none-eabi"
Expand Down
2 changes: 1 addition & 1 deletion examples/stm32l4/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"

[dependencies]
# Change stm32l4s5vi to your chip name, if necessary.
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4r5zi", "memory-x", "time-driver-any", "exti", "chrono"] }
embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] }
Expand Down
24 changes: 24 additions & 0 deletions examples/stm32l4/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Examples for STM32L4 family
Run individual examples with
```
cargo run --bin <module-name>
```
for example
```
cargo run --bin blinky
```

## Checklist before running examples
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.

* [ ] 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)
* [ ] 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.
* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic

If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:

* Which example you are trying to run
* Which chip and board you are using

Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
121 changes: 121 additions & 0 deletions examples/stm32l4/src/bin/tsc_async.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// # Example of async TSC (Touch Sensing Controller) that lights an LED when touch is detected
//
// This example demonstrates how to use the Touch Sensing Controller (TSC) in asynchronous mode on an STM32L4R5ZI-P board.
//
// ## This example demonstrates:
//
// 1. Configuring a single TSC channel pin
// 2. Using the async TSC interface
// 3. Waiting for acquisition completion using `pend_for_acquisition`
// 4. Reading touch values and controlling an LED based on the results
//
// ## Suggested physical setup on STM32L4R5ZI-P board:
//
// - Connect a 1000pF capacitor between pin PB4 (D25) and GND. This is your sampling capacitor.
// - Connect one end of a 1K resistor to pin PB5 (D21) and leave the other end loose.
// The loose end will act as the touch sensor which will register your touch.
//
// ## Pin Configuration:
//
// The example uses two pins from Group 2 of the TSC:
// - PB4 (D25) as the sampling capacitor, TSC group 2 IO1
// - PB5 (D21) as the channel pin, TSC group 2 IO2
//
// ## Program Behavior:
//
// The program continuously reads the touch sensor value:
// - It starts acquisition, waits for completion using `pend_for_acquisition`, and reads the value.
// - The LED (connected to PB14) is turned on when touch is detected (sensor value < SENSOR_THRESHOLD).
// - Touch values are logged to the console.
//
// ## Troubleshooting:
//
// - If touch is not detected, try adjusting the SENSOR_THRESHOLD value (currently set to 25).
// - 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.
// - Be aware that for some boards, there might be overlapping concerns between some pins,
// such as UART connections for the programmer. No errors or warnings will be emitted if you
// try to use such a pin for TSC, but you may get strange sensor readings.
//
// Note: Configuration values and sampling capacitor value 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.

#![no_std]
#![no_main]

use defmt::*;
use embassy_stm32::gpio::{Level, Output, Speed};
use embassy_stm32::tsc::{self, *};
use embassy_stm32::{bind_interrupts, peripherals};
use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};

bind_interrupts!(struct Irqs {
TSC => InterruptHandler<embassy_stm32::peripherals::TSC>;
});
const SENSOR_THRESHOLD: u16 = 25; // Adjust this value based on your setup

#[embassy_executor::main]
async fn main(_spawner: embassy_executor::Spawner) {
let device_config = embassy_stm32::Config::default();
let context = embassy_stm32::init(device_config);

let mut g2: PinGroup<peripherals::TSC, G2> = PinGroup::new();
// D25
g2.set_io1(context.PB4, PinType::Sample);
// D21
let tsc_sensor = g2.set_io2(context.PB5, PinType::Channel);

let pin_groups: PinGroups<peripherals::TSC> = PinGroups {
g2: Some(g2),
..Default::default()
};

let tsc_conf = Config {
ct_pulse_high_length: ChargeTransferPulseCycle::_4,
ct_pulse_low_length: ChargeTransferPulseCycle::_4,
spread_spectrum: false,
spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
spread_spectrum_prescaler: false,
pulse_generator_prescaler: PGPrescalerDivider::_16,
max_count_value: MaxCount::_255,
io_default_mode: false,
synchro_pin_polarity: false,
acquisition_mode: false,
max_count_interrupt: false,
};

let mut touch_controller = tsc::Tsc::new_async(context.TSC, pin_groups, tsc_conf, Irqs).unwrap();

// Check if TSC is ready
if touch_controller.get_state() != State::Ready {
info!("TSC not ready!");
return;
}
info!("TSC initialized successfully");

let mut led = Output::new(context.PB14, Level::High, Speed::Low);

let discharge_delay = 1; // ms

info!("Starting touch_controller interface");
loop {
touch_controller.set_active_channels_mask(tsc_sensor.into());
touch_controller.start();
touch_controller.pend_for_acquisition().await;
touch_controller.discharge_io(true);
Timer::after_millis(discharge_delay).await;

let group_val = touch_controller.group_get_value(tsc_sensor.group());
info!("Touch value: {}", group_val);

if group_val < SENSOR_THRESHOLD {
led.set_high();
} else {
led.set_low();
}

Timer::after_millis(100).await;
}
}
147 changes: 147 additions & 0 deletions examples/stm32l4/src/bin/tsc_blocking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// # Example of blocking TSC (Touch Sensing Controller) that lights an LED when touch is detected
//
// This example demonstrates how to use the Touch Sensing Controller (TSC) in blocking mode on an STM32L4R5ZI-P board.
//
// ## This example demonstrates:
//
// 1. Configuring a single TSC channel pin
// 2. Using the blocking TSC interface with polling
// 3. Waiting for acquisition completion using `poll_for_acquisition`
// 4. Reading touch values and controlling an LED based on the results
//
// ## Suggested physical setup on STM32L4R5ZI-P board:
//
// - Connect a 1000pF capacitor between pin PB4 (D25) and GND. This is your sampling capacitor.
// - Connect one end of a 1K resistor to pin PB5 (D21) and leave the other end loose.
// The loose end will act as the touch sensor which will register your touch.
//
// ## Pin Configuration:
//
// The example uses two pins from Group 2 of the TSC:
// - PB4 (D25) as the sampling capacitor, TSC group 2 IO1
// - PB5 (D21) as the channel pin, TSC group 2 IO2
//
// ## Program Behavior:
//
// The program continuously reads the touch sensor value:
// - It starts acquisition, waits for completion using `poll_for_acquisition`, and reads the value.
// - The LED (connected to PB14) is turned on when touch is detected (sensor value < SENSOR_THRESHOLD).
// - Touch values are logged to the console.
//
// ## Troubleshooting:
//
// - If touch is not detected, try adjusting the SENSOR_THRESHOLD value (currently set to 25).
// - 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.
// - Be aware that for some boards, there might be overlapping concerns between some pins,
// such as UART connections for the programmer. No errors or warnings will be emitted if you
// try to use such a pin for TSC, but you may get strange sensor readings.
//
// Note: Configuration values and sampling capacitor value 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.

#![no_std]
#![no_main]

use defmt::*;
use embassy_stm32::gpio::{Level, Output, Speed};
use embassy_stm32::tsc::{self, *};
use embassy_stm32::{mode, peripherals};
use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};

const SENSOR_THRESHOLD: u16 = 25; // Adjust this value based on your setup

#[embassy_executor::main]
async fn main(_spawner: embassy_executor::Spawner) {
let device_config = embassy_stm32::Config::default();
let context = embassy_stm32::init(device_config);

let tsc_conf = Config {
ct_pulse_high_length: ChargeTransferPulseCycle::_4,
ct_pulse_low_length: ChargeTransferPulseCycle::_4,
spread_spectrum: false,
spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
spread_spectrum_prescaler: false,
pulse_generator_prescaler: PGPrescalerDivider::_16,
max_count_value: MaxCount::_255,
io_default_mode: false,
synchro_pin_polarity: false,
acquisition_mode: false,
max_count_interrupt: false,
};

let mut g2: PinGroup<peripherals::TSC, G2> = PinGroup::new();
// D25
g2.set_io1(context.PB4, PinType::Sample);
// D21
let tsc_sensor = g2.set_io2(context.PB5, PinType::Channel);

let pin_groups: PinGroups<peripherals::TSC> = PinGroups {
g2: Some(g2),
..Default::default()
};

let mut touch_controller = tsc::Tsc::new_blocking(context.TSC, pin_groups, tsc_conf).unwrap();

// Check if TSC is ready
if touch_controller.get_state() != State::Ready {
crate::panic!("TSC not ready!");
}
info!("TSC initialized successfully");

let mut led = Output::new(context.PB14, Level::High, Speed::Low);

// smaller sample capacitor discharge faster and can be used with shorter delay.
let discharge_delay = 5; // ms

// the interval at which the loop polls for new touch sensor values
let polling_interval = 100; // ms

info!("polling for touch");
loop {
touch_controller.set_active_channels_mask(tsc_sensor.into());
touch_controller.start();
touch_controller.poll_for_acquisition();
touch_controller.discharge_io(true);
Timer::after_millis(discharge_delay).await;

match read_touch_value(&mut touch_controller, tsc_sensor).await {
Some(v) => {
info!("sensor value {}", v);
if v < SENSOR_THRESHOLD {
led.set_high();
} else {
led.set_low();
}
}
None => led.set_low(),
}

Timer::after_millis(polling_interval).await;
}
}

const MAX_GROUP_STATUS_READ_ATTEMPTS: usize = 10;

// attempt to read group status and delay when still ongoing
async fn read_touch_value(
touch_controller: &mut tsc::Tsc<'_, peripherals::TSC, mode::Blocking>,
sensor_pin: TscIOPin,
) -> Option<u16> {
for _ in 0..MAX_GROUP_STATUS_READ_ATTEMPTS {
match touch_controller.group_get_status(sensor_pin.group()) {
GroupStatus::Complete => {
return Some(touch_controller.group_get_value(sensor_pin.group()));
}
GroupStatus::Ongoing => {
// if you end up here a lot, then you prob need to increase discharge_delay
// or consider changing the code to adjust the discharge_delay dynamically
info!("Acquisition still ongoing");
Timer::after_millis(1).await;
}
}
}
None
}
Loading

0 comments on commit 1a5fb2a

Please sign in to comment.