aboutsummaryrefslogtreecommitdiff
path: root/examples/stm32wle5
diff options
context:
space:
mode:
authorliebman <[email protected]>2025-10-29 14:47:06 -0700
committerliebman <[email protected]>2025-11-03 12:50:41 -0800
commit46480285783390d90f8d99e530a1da28a292dc3c (patch)
treedaff2dd4ed4f42709e53d2c410073292f1120551 /examples/stm32wle5
parentccce1478c161662521a77284222f5710b1ee34d9 (diff)
examples: add low-power examples for `stm32wlex`
Diffstat (limited to 'examples/stm32wle5')
-rw-r--r--examples/stm32wle5/.cargo/config.toml9
-rw-r--r--examples/stm32wle5/Cargo.toml38
-rw-r--r--examples/stm32wle5/README.md45
-rw-r--r--examples/stm32wle5/build.rs5
-rw-r--r--examples/stm32wle5/src/bin/adc.rs105
-rw-r--r--examples/stm32wle5/src/bin/blinky.rs95
-rw-r--r--examples/stm32wle5/src/bin/button_exti.rs96
-rw-r--r--examples/stm32wle5/stm32wle5.code-workspace13
8 files changed, 406 insertions, 0 deletions
diff --git a/examples/stm32wle5/.cargo/config.toml b/examples/stm32wle5/.cargo/config.toml
new file mode 100644
index 000000000..0178d377c
--- /dev/null
+++ b/examples/stm32wle5/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip STM32WLE5JCIx --connect-under-reset"
4
5[build]
6target = "thumbv7em-none-eabi"
7
8[env]
9DEFMT_LOG = "info"
diff --git a/examples/stm32wle5/Cargo.toml b/examples/stm32wle5/Cargo.toml
new file mode 100644
index 000000000..f2fc4dd3d
--- /dev/null
+++ b/examples/stm32wle5/Cargo.toml
@@ -0,0 +1,38 @@
1[package]
2edition = "2024"
3name = "embassy-stm32wl-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6publish = false
7
8[dependencies]
9# Change stm32wl55jc-cm4 to your chip name, if necessary.
10embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = ["defmt", "stm32wle5jc", "time-driver-any", "memory-x", "unstable-pac", "exti", "low-power"] }
11embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
12embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
13embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-1_000"] }
14embassy-embedded-hal = { version = "0.5.0", path = "../../embassy-embedded-hal" }
15
16defmt = "1.0.1"
17defmt-rtt = { version = "1.1.0", optional = true }
18defmt-serial = { version = "0.10.0", optional = true }
19
20cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
21cortex-m-rt = "0.7.0"
22embedded-hal = "1.0.0"
23embedded-storage = "0.3.1"
24panic-probe = { version = "1.0.0", features = ["print-defmt"] }
25static_cell = { version = "2.1.1", default-features = false }
26
27[profile.release]
28debug = 2
29
30[package.metadata.embassy]
31build = [
32 { target = "thumbv7em-none-eabi", artifact-dir = "out/examples/stm32wl" }
33]
34
35[features]
36default = ["defmt-serial"]
37defmt-rtt = ["dep:defmt-rtt"]
38defmt-serial = ["dep:defmt-serial"]
diff --git a/examples/stm32wle5/README.md b/examples/stm32wle5/README.md
new file mode 100644
index 000000000..7435ed1be
--- /dev/null
+++ b/examples/stm32wle5/README.md
@@ -0,0 +1,45 @@
1# Low Power Examples for STM32WLEx family
2
3Examples in this repo should work with [LoRa-E5 Dev Board](https://www.st.com/en/partner-products-and-services/lora-e5-development-kit.html) board.
4
5## Prerequsits
6
7- Connect a usb serial adapter to LPUart1 (this is where ALL logging will go)
8- Optional: Connect an amp meter that ran measure down to 0.1uA to the power test pins
9
10## Example Notes
11
12All examples will set all pins to analog mode before configuring pins for the example, if any. This saves about 500uA!!!!
13
14- the `adc` example will sleep in STOP1 betwen samples and the chip will only draw about 13uA while sleeping
15- the `blinky` example will sleep in STOP2 and the chip will only draw 1uA or less while sleeping
16- the `button_exti` example will sleep in STOP2 and the chip will only draw 1uA or less while sleeping
17
18Run individual examples with
19```
20cargo flash --chip STM32WLE5JCIx --connect-under-reset --bin <module-name>
21```
22for example
23```
24cargo flash --chip STM32WLE5JCIx --connect-under-reset --bin blinky
25```
26
27You can also run them with with `run`. However in this case expect probe-rs to be disconnected as soon as flashing is done as all IO pins are set to analog input!
28```
29cargo run --bin blinky
30```
31
32## Checklist before running examples
33You 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.
34
35* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for L432KCU6 it should be `probe-rs run --chip STM32L432KCUx`. (use `probe-rs chip list` to find your chip)
36* [ ] Update Cargo.toml to have the correct `embassy-stm32` feature. For example for L432KCU6 it should be `stm32l432kc`. Look in the `Cargo.toml` file of the `embassy-stm32` project to find the correct feature flag for your chip.
37* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
38* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
39
40If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
41
42* Which example you are trying to run
43* Which chip and board you are using
44
45Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
diff --git a/examples/stm32wle5/build.rs b/examples/stm32wle5/build.rs
new file mode 100644
index 000000000..8cd32d7ed
--- /dev/null
+++ b/examples/stm32wle5/build.rs
@@ -0,0 +1,5 @@
1fn main() {
2 println!("cargo:rustc-link-arg-bins=--nmagic");
3 println!("cargo:rustc-link-arg-bins=-Tlink.x");
4 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
5}
diff --git a/examples/stm32wle5/src/bin/adc.rs b/examples/stm32wle5/src/bin/adc.rs
new file mode 100644
index 000000000..fabdb9cb3
--- /dev/null
+++ b/examples/stm32wle5/src/bin/adc.rs
@@ -0,0 +1,105 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5#[cfg(feature = "defmt-rtt")]
6use defmt_rtt as _;
7use embassy_executor::Spawner;
8use embassy_stm32::adc::{Adc, SampleTime};
9use embassy_stm32::low_power::Executor;
10use embassy_stm32::rtc::{Rtc, RtcConfig};
11use embassy_time::Timer;
12use panic_probe as _;
13use static_cell::StaticCell;
14
15#[cortex_m_rt::entry]
16fn main() -> ! {
17 info!("main: Starting!");
18 Executor::take().run(|spawner| {
19 spawner.spawn(unwrap!(async_main(spawner)));
20 });
21}
22
23#[embassy_executor::task]
24async fn async_main(_spawner: Spawner) {
25 let mut config = embassy_stm32::Config::default();
26 // enable HSI clock
27 config.rcc.hsi = true;
28 // enable LSI clock for RTC
29 config.rcc.ls = embassy_stm32::rcc::LsConfig::default_lsi();
30 config.rcc.msi = Some(embassy_stm32::rcc::MSIRange::RANGE4M);
31 config.rcc.sys = embassy_stm32::rcc::Sysclk::MSI;
32 // enable ADC with HSI clock
33 config.rcc.mux.adcsel = embassy_stm32::pac::rcc::vals::Adcsel::HSI;
34 #[cfg(feature = "defmt-serial")]
35 {
36 // disable debug during sleep to reduce power consumption since we are
37 // using defmt-serial on LPUART1.
38 config.enable_debug_during_sleep = false;
39 // if we are using defmt-serial on LPUART1, we need to use HSI for the clock
40 // so that its registers are preserved during STOP modes.
41 config.rcc.mux.lpuart1sel = embassy_stm32::pac::rcc::vals::Lpuart1sel::HSI;
42 }
43 // Initialize STM32WL peripherals (use default config like wio-e5-async example)
44 let p = embassy_stm32::init(config);
45
46 // start with all GPIOs as analog to reduce power consumption
47 for r in [
48 embassy_stm32::pac::GPIOA,
49 embassy_stm32::pac::GPIOB,
50 embassy_stm32::pac::GPIOC,
51 embassy_stm32::pac::GPIOH,
52 ] {
53 r.moder().modify(|w| {
54 for i in 0..16 {
55 // don't reset these if probe-rs should stay connected!
56 #[cfg(feature = "defmt-rtt")]
57 if config.enable_debug_during_sleep && r == embassy_stm32::pac::GPIOA && [13, 14].contains(&i) {
58 continue;
59 }
60 w.set_moder(i, embassy_stm32::pac::gpio::vals::Moder::ANALOG);
61 }
62 });
63 }
64 #[cfg(feature = "defmt-serial")]
65 {
66 use embassy_stm32::mode::Blocking;
67 use embassy_stm32::usart::Uart;
68 let mut config = embassy_stm32::usart::Config::default();
69 config.baudrate = 115200;
70 config.assume_noise_free = true;
71 config.detect_previous_overrun = true;
72 let uart = Uart::new_blocking(p.LPUART1, p.PC0, p.PC1, config).expect("failed to configure UART!");
73 static SERIAL: StaticCell<Uart<'static, Blocking>> = StaticCell::new();
74 defmt_serial::defmt_serial(SERIAL.init(uart));
75 }
76
77 // give the RTC to the low_power executor...
78 let rtc_config = RtcConfig::default();
79 let rtc = Rtc::new(p.RTC, rtc_config);
80 static RTC: StaticCell<Rtc> = StaticCell::new();
81 let rtc = RTC.init(rtc);
82 embassy_stm32::low_power::stop_with_rtc(rtc);
83
84 info!("Hello World!");
85
86 let mut adc = Adc::new(p.ADC1);
87 adc.set_sample_time(SampleTime::CYCLES79_5);
88 let mut pin = p.PA10;
89
90 let mut vrefint = adc.enable_vrefint();
91 let vrefint_sample = adc.blocking_read(&mut vrefint);
92 let convert_to_millivolts = |sample| {
93 // From https://www.st.com/resource/en/datasheet/stm32g031g8.pdf
94 // 6.3.3 Embedded internal reference voltage
95 const VREFINT_MV: u32 = 1212; // mV
96
97 (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16
98 };
99
100 loop {
101 let v = adc.blocking_read(&mut pin);
102 info!("--> {} - {} mV", v, convert_to_millivolts(v));
103 Timer::after_secs(1).await;
104 }
105}
diff --git a/examples/stm32wle5/src/bin/blinky.rs b/examples/stm32wle5/src/bin/blinky.rs
new file mode 100644
index 000000000..f5ba97025
--- /dev/null
+++ b/examples/stm32wle5/src/bin/blinky.rs
@@ -0,0 +1,95 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5#[cfg(feature = "defmt-rtt")]
6use defmt_rtt as _;
7use embassy_executor::Spawner;
8use embassy_stm32::gpio::{Level, Output, Speed};
9use embassy_stm32::low_power::Executor;
10use embassy_stm32::rtc::{Rtc, RtcConfig};
11use embassy_time::Timer;
12use panic_probe as _;
13use static_cell::StaticCell;
14
15#[cortex_m_rt::entry]
16fn main() -> ! {
17 info!("main: Starting!");
18 Executor::take().run(|spawner| {
19 spawner.spawn(unwrap!(async_main(spawner)));
20 });
21}
22
23#[embassy_executor::task]
24async fn async_main(_spawner: Spawner) {
25 let mut config = embassy_stm32::Config::default();
26 // enable HSI clock
27 config.rcc.hsi = true;
28 // enable LSI clock for RTC
29 config.rcc.ls = embassy_stm32::rcc::LsConfig::default_lsi();
30 config.rcc.msi = Some(embassy_stm32::rcc::MSIRange::RANGE4M);
31 config.rcc.sys = embassy_stm32::rcc::Sysclk::MSI;
32 #[cfg(feature = "defmt-serial")]
33 {
34 // disable debug during sleep to reduce power consumption since we are
35 // using defmt-serial on LPUART1.
36 config.enable_debug_during_sleep = false;
37 // if we are using defmt-serial on LPUART1, we need to use HSI for the clock
38 // so that its registers are preserved during STOP modes.
39 config.rcc.mux.lpuart1sel = embassy_stm32::pac::rcc::vals::Lpuart1sel::HSI;
40 }
41 // Initialize STM32WL peripherals (use default config like wio-e5-async example)
42 let p = embassy_stm32::init(config);
43
44 // start with all GPIOs as analog to reduce power consumption
45 for r in [
46 embassy_stm32::pac::GPIOA,
47 embassy_stm32::pac::GPIOB,
48 embassy_stm32::pac::GPIOC,
49 embassy_stm32::pac::GPIOH,
50 ] {
51 r.moder().modify(|w| {
52 for i in 0..16 {
53 // don't reset these if probe-rs should stay connected!
54 #[cfg(feature = "defmt-rtt")]
55 if config.enable_debug_during_sleep && r == embassy_stm32::pac::GPIOA && [13, 14].contains(&i) {
56 continue;
57 }
58 w.set_moder(i, embassy_stm32::pac::gpio::vals::Moder::ANALOG);
59 }
60 });
61 }
62 #[cfg(feature = "defmt-serial")]
63 {
64 use embassy_stm32::mode::Blocking;
65 use embassy_stm32::usart::Uart;
66 let mut config = embassy_stm32::usart::Config::default();
67 config.baudrate = 115200;
68 config.assume_noise_free = true;
69 config.detect_previous_overrun = true;
70 let uart = Uart::new_blocking(p.LPUART1, p.PC0, p.PC1, config).expect("failed to configure UART!");
71 static SERIAL: StaticCell<Uart<'static, Blocking>> = StaticCell::new();
72 defmt_serial::defmt_serial(SERIAL.init(uart));
73 }
74
75 // give the RTC to the low_power executor...
76 let rtc_config = RtcConfig::default();
77 let rtc = Rtc::new(p.RTC, rtc_config);
78 static RTC: StaticCell<Rtc> = StaticCell::new();
79 let rtc = RTC.init(rtc);
80 embassy_stm32::low_power::stop_with_rtc(rtc);
81
82 info!("Hello World!");
83
84 let mut led = Output::new(p.PB5, Level::High, Speed::Low);
85
86 loop {
87 info!("low");
88 led.set_low();
89 Timer::after_millis(500).await;
90
91 info!("high");
92 led.set_high();
93 Timer::after_millis(500).await;
94 }
95}
diff --git a/examples/stm32wle5/src/bin/button_exti.rs b/examples/stm32wle5/src/bin/button_exti.rs
new file mode 100644
index 000000000..dfa391a81
--- /dev/null
+++ b/examples/stm32wle5/src/bin/button_exti.rs
@@ -0,0 +1,96 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5#[cfg(feature = "defmt-rtt")]
6use defmt_rtt as _;
7use embassy_executor::Spawner;
8use embassy_stm32::exti::ExtiInput;
9use embassy_stm32::gpio::Pull;
10use embassy_stm32::low_power::Executor;
11use embassy_stm32::rtc::{Rtc, RtcConfig};
12use panic_probe as _;
13use static_cell::StaticCell;
14
15#[cortex_m_rt::entry]
16fn main() -> ! {
17 info!("main: Starting!");
18 Executor::take().run(|spawner| {
19 spawner.spawn(unwrap!(async_main(spawner)));
20 });
21}
22
23#[embassy_executor::task]
24async fn async_main(_spawner: Spawner) {
25 let mut config = embassy_stm32::Config::default();
26 // enable HSI clock
27 config.rcc.hsi = true;
28 // enable LSI clock for RTC
29 config.rcc.ls = embassy_stm32::rcc::LsConfig::default_lsi();
30 config.rcc.msi = Some(embassy_stm32::rcc::MSIRange::RANGE4M);
31 config.rcc.sys = embassy_stm32::rcc::Sysclk::MSI;
32 // enable ADC with HSI clock
33 config.rcc.mux.adcsel = embassy_stm32::pac::rcc::vals::Adcsel::HSI;
34 #[cfg(feature = "defmt-serial")]
35 {
36 // disable debug during sleep to reduce power consumption since we are
37 // using defmt-serial on LPUART1.
38 config.enable_debug_during_sleep = false;
39 // if we are using defmt-serial on LPUART1, we need to use HSI for the clock
40 // so that its registers are preserved during STOP modes.
41 config.rcc.mux.lpuart1sel = embassy_stm32::pac::rcc::vals::Lpuart1sel::HSI;
42 }
43 // Initialize STM32WL peripherals (use default config like wio-e5-async example)
44 let p = embassy_stm32::init(config);
45
46 // start with all GPIOs as analog to reduce power consumption
47 for r in [
48 embassy_stm32::pac::GPIOA,
49 embassy_stm32::pac::GPIOB,
50 embassy_stm32::pac::GPIOC,
51 embassy_stm32::pac::GPIOH,
52 ] {
53 r.moder().modify(|w| {
54 for i in 0..16 {
55 // don't reset these if probe-rs should stay connected!
56 #[cfg(feature = "defmt-rtt")]
57 if config.enable_debug_during_sleep && r == embassy_stm32::pac::GPIOA && [13, 14].contains(&i) {
58 continue;
59 }
60 w.set_moder(i, embassy_stm32::pac::gpio::vals::Moder::ANALOG);
61 }
62 });
63 }
64 #[cfg(feature = "defmt-serial")]
65 {
66 use embassy_stm32::mode::Blocking;
67 use embassy_stm32::usart::Uart;
68 let mut config = embassy_stm32::usart::Config::default();
69 config.baudrate = 115200;
70 config.assume_noise_free = true;
71 config.detect_previous_overrun = true;
72 let uart = Uart::new_blocking(p.LPUART1, p.PC0, p.PC1, config).expect("failed to configure UART!");
73 static SERIAL: StaticCell<Uart<'static, Blocking>> = StaticCell::new();
74 defmt_serial::defmt_serial(SERIAL.init(uart));
75 }
76
77 // give the RTC to the low_power executor...
78 let rtc_config = RtcConfig::default();
79 let rtc = Rtc::new(p.RTC, rtc_config);
80 static RTC: StaticCell<Rtc> = StaticCell::new();
81 let rtc = RTC.init(rtc);
82 embassy_stm32::low_power::stop_with_rtc(rtc);
83
84 info!("Hello World!");
85
86 let mut button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Up);
87
88 info!("Press the USER button...");
89
90 loop {
91 button.wait_for_falling_edge().await;
92 info!("Pressed!");
93 button.wait_for_rising_edge().await;
94 info!("Released!");
95 }
96}
diff --git a/examples/stm32wle5/stm32wle5.code-workspace b/examples/stm32wle5/stm32wle5.code-workspace
new file mode 100644
index 000000000..a7c4a0ebd
--- /dev/null
+++ b/examples/stm32wle5/stm32wle5.code-workspace
@@ -0,0 +1,13 @@
1{
2 "folders": [
3 {
4 "path": "."
5 }
6 ],
7 "settings": {
8 "rust-analyzer.cargo.target": "thumbv7em-none-eabi",
9 "rust-analyzer.cargo.allTargets": false,
10 "rust-analyzer.cargo.targetDir": "target/rust-analyzer",
11 "rust-analyzer.checkOnSave": true,
12 }
13}