From 9131cbd9f2b28ff10be64162a3d55d288f27190a Mon Sep 17 00:00:00 2001 From: liebman Date: Thu, 30 Oct 2025 13:07:07 -0700 Subject: examples: : stm32wlex: add i2c example --- examples/stm32wle5/README.md | 1 + examples/stm32wle5/src/bin/adc.rs | 5 +- examples/stm32wle5/src/bin/blinky.rs | 5 +- examples/stm32wle5/src/bin/button_exti.rs | 5 +- examples/stm32wle5/src/bin/i2c.rs | 112 ++++++++++++++++++++++++++++++ 5 files changed, 116 insertions(+), 12 deletions(-) create mode 100644 examples/stm32wle5/src/bin/i2c.rs (limited to 'examples') diff --git a/examples/stm32wle5/README.md b/examples/stm32wle5/README.md index 63507f490..18c3b5071 100644 --- a/examples/stm32wle5/README.md +++ b/examples/stm32wle5/README.md @@ -15,6 +15,7 @@ All examples will set all pins to analog mode before configuring pins for the ex - the `adc` example will sleep in STOP1 betwen samples and the chip will only draw about 13uA while sleeping - the `blinky` example will sleep in STOP2 and the chip will only draw 1uA or less while sleeping - the `button_exti` example will sleep in STOP2 and the chip will only draw 1uA or less while sleeping +- the `i2c` examples will sleep in STOP1 between reads and the chip only draw about 10uA while sleeping For each example you will need to start `defmt-print` with the example binary and the correct serial port in a seperate terminal. Example: ``` diff --git a/examples/stm32wle5/src/bin/adc.rs b/examples/stm32wle5/src/bin/adc.rs index fabdb9cb3..b4af656ed 100644 --- a/examples/stm32wle5/src/bin/adc.rs +++ b/examples/stm32wle5/src/bin/adc.rs @@ -65,10 +65,7 @@ async fn async_main(_spawner: Spawner) { { use embassy_stm32::mode::Blocking; use embassy_stm32::usart::Uart; - let mut config = embassy_stm32::usart::Config::default(); - config.baudrate = 115200; - config.assume_noise_free = true; - config.detect_previous_overrun = true; + let config = embassy_stm32::usart::Config::default(); let uart = Uart::new_blocking(p.LPUART1, p.PC0, p.PC1, config).expect("failed to configure UART!"); static SERIAL: StaticCell> = StaticCell::new(); defmt_serial::defmt_serial(SERIAL.init(uart)); diff --git a/examples/stm32wle5/src/bin/blinky.rs b/examples/stm32wle5/src/bin/blinky.rs index f5ba97025..a7a571cb1 100644 --- a/examples/stm32wle5/src/bin/blinky.rs +++ b/examples/stm32wle5/src/bin/blinky.rs @@ -63,10 +63,7 @@ async fn async_main(_spawner: Spawner) { { use embassy_stm32::mode::Blocking; use embassy_stm32::usart::Uart; - let mut config = embassy_stm32::usart::Config::default(); - config.baudrate = 115200; - config.assume_noise_free = true; - config.detect_previous_overrun = true; + let config = embassy_stm32::usart::Config::default(); let uart = Uart::new_blocking(p.LPUART1, p.PC0, p.PC1, config).expect("failed to configure UART!"); static SERIAL: StaticCell> = StaticCell::new(); defmt_serial::defmt_serial(SERIAL.init(uart)); diff --git a/examples/stm32wle5/src/bin/button_exti.rs b/examples/stm32wle5/src/bin/button_exti.rs index dfa391a81..c8083a240 100644 --- a/examples/stm32wle5/src/bin/button_exti.rs +++ b/examples/stm32wle5/src/bin/button_exti.rs @@ -65,10 +65,7 @@ async fn async_main(_spawner: Spawner) { { use embassy_stm32::mode::Blocking; use embassy_stm32::usart::Uart; - let mut config = embassy_stm32::usart::Config::default(); - config.baudrate = 115200; - config.assume_noise_free = true; - config.detect_previous_overrun = true; + let config = embassy_stm32::usart::Config::default(); let uart = Uart::new_blocking(p.LPUART1, p.PC0, p.PC1, config).expect("failed to configure UART!"); static SERIAL: StaticCell> = StaticCell::new(); defmt_serial::defmt_serial(SERIAL.init(uart)); diff --git a/examples/stm32wle5/src/bin/i2c.rs b/examples/stm32wle5/src/bin/i2c.rs new file mode 100644 index 000000000..4a56773e9 --- /dev/null +++ b/examples/stm32wle5/src/bin/i2c.rs @@ -0,0 +1,112 @@ +#![no_std] +#![no_main] + +use defmt::*; +#[cfg(feature = "defmt-rtt")] +use defmt_rtt as _; +use embassy_executor::Spawner; +use embassy_stm32::i2c::I2c; +use embassy_stm32::low_power::Executor; +use embassy_stm32::rtc::{Rtc, RtcConfig}; +use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, i2c, peripherals}; +use embassy_time::{Duration, Timer}; +use panic_probe as _; +use static_cell::StaticCell; + +bind_interrupts!(struct IrqsI2C{ + I2C2_EV => i2c::EventInterruptHandler; + I2C2_ER => i2c::ErrorInterruptHandler; +}); + +#[cortex_m_rt::entry] +fn main() -> ! { + info!("main: Starting!"); + Executor::take().run(|spawner| { + spawner.spawn(unwrap!(async_main(spawner))); + }); +} + +#[embassy_executor::task] +async fn async_main(_spawner: Spawner) { + let mut config = embassy_stm32::Config::default(); + // enable HSI clock + config.rcc.hsi = true; + // enable LSI clock for RTC + config.rcc.ls = embassy_stm32::rcc::LsConfig::default_lsi(); + config.rcc.msi = Some(embassy_stm32::rcc::MSIRange::RANGE4M); + config.rcc.sys = embassy_stm32::rcc::Sysclk::MSI; + // enable ADC with HSI clock + config.rcc.mux.i2c2sel = embassy_stm32::pac::rcc::vals::I2c2sel::HSI; + #[cfg(feature = "defmt-serial")] + { + // disable debug during sleep to reduce power consumption since we are + // using defmt-serial on LPUART1. + config.enable_debug_during_sleep = false; + // if we are using defmt-serial on LPUART1, we need to use HSI for the clock + // so that its registers are preserved during STOP modes. + config.rcc.mux.lpuart1sel = embassy_stm32::pac::rcc::vals::Lpuart1sel::HSI; + } + // Initialize STM32WL peripherals (use default config like wio-e5-async example) + let p = embassy_stm32::init(config); + + // start with all GPIOs as analog to reduce power consumption + for r in [ + embassy_stm32::pac::GPIOA, + embassy_stm32::pac::GPIOB, + embassy_stm32::pac::GPIOC, + embassy_stm32::pac::GPIOH, + ] { + r.moder().modify(|w| { + for i in 0..16 { + // don't reset these if probe-rs should stay connected! + #[cfg(feature = "defmt-rtt")] + if config.enable_debug_during_sleep && r == embassy_stm32::pac::GPIOA && [13, 14].contains(&i) { + continue; + } + w.set_moder(i, embassy_stm32::pac::gpio::vals::Moder::ANALOG); + } + }); + } + #[cfg(feature = "defmt-serial")] + { + use embassy_stm32::mode::Blocking; + use embassy_stm32::usart::Uart; + let config = embassy_stm32::usart::Config::default(); + let uart = Uart::new_blocking(p.LPUART1, p.PC0, p.PC1, config).expect("failed to configure UART!"); + static SERIAL: StaticCell> = StaticCell::new(); + defmt_serial::defmt_serial(SERIAL.init(uart)); + } + + // give the RTC to the low_power executor... + let rtc_config = RtcConfig::default(); + let rtc = Rtc::new(p.RTC, rtc_config); + static RTC: StaticCell = StaticCell::new(); + let rtc = RTC.init(rtc); + embassy_stm32::low_power::stop_with_rtc(rtc); + + info!("Hello World!"); + let en3v3 = embassy_stm32::gpio::Output::new( + p.PA9, + embassy_stm32::gpio::Level::High, + embassy_stm32::gpio::Speed::High, + ); + core::mem::forget(en3v3); // keep the output pin enabled + + let mut i2c = I2c::new(p.I2C2, p.PB15, p.PA15, IrqsI2C, p.DMA1_CH6, p.DMA1_CH7, { + let mut config = i2c::Config::default(); + config.frequency = Hertz::khz(100); + config.timeout = Duration::from_millis(500); + config + }); + + loop { + let mut buffer = [0; 2]; + // read the temperature register of the onboard lm75 + match i2c.read(0x48, &mut buffer).await { + Ok(_) => info!("--> {:?}", buffer), + Err(e) => info!("--> Error: {:?}", e), + } + Timer::after_secs(5).await; + } +} -- cgit