From 572a40b4eee99b177733f50b08e29ff9b5ab6fa5 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Sat, 23 Aug 2025 08:31:41 +0200 Subject: stm32/i2c_v1: Add async and blocking example code --- examples/stm32f4/src/bin/i2c_slave_async.rs | 123 +++++++++++++++++++++++++ examples/stm32f4/src/bin/i2c_slave_blocking.rs | 118 ++++++++++++++++++++++++ 2 files changed, 241 insertions(+) create mode 100644 examples/stm32f4/src/bin/i2c_slave_async.rs create mode 100644 examples/stm32f4/src/bin/i2c_slave_blocking.rs (limited to 'examples') diff --git a/examples/stm32f4/src/bin/i2c_slave_async.rs b/examples/stm32f4/src/bin/i2c_slave_async.rs new file mode 100644 index 000000000..072c9875e --- /dev/null +++ b/examples/stm32f4/src/bin/i2c_slave_async.rs @@ -0,0 +1,123 @@ +//! I2C slave example using async operations with DMA +//! +//! This example demonstrates DMA-accelerated I2C slave operations, +//! which provide better performance and lower CPU overhead for +//! high-frequency I2C transactions. + +#![no_std] +#![no_main] + +use defmt_rtt as _; +use defmt::{error, info}; +use embassy_executor::Spawner; +use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_stm32::i2c::{self, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind, Address}; +use embassy_stm32::time::Hertz; +use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; +use embassy_sync::mutex::Mutex; +use embassy_time::{Duration, Timer}; +use panic_probe as _; + +pub const I2C_SLAVE_ADDR: u8 = 0x42; +pub const BUFFER_SIZE: usize = 8; +static I2C_BUFFER: Mutex = Mutex::new([0; BUFFER_SIZE]); + +bind_interrupts!(struct Irqs { + I2C1_EV => i2c::EventInterruptHandler; + I2C1_ER => i2c::ErrorInterruptHandler; +}); + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + + // Configure I2C + let mut i2c_config = i2c::Config::default(); + i2c_config.sda_pullup = false; + i2c_config.scl_pullup = false; + i2c_config.frequency = Hertz(100_000); // 100kHz I2C speed + + // Initialize I2C as master first + let i2c_master = I2c::new( + p.I2C1, + p.PB8, // SCL + p.PB9, // SDA + Irqs, + p.DMA1_CH6, // TX DMA + p.DMA1_CH0, // RX DMA + i2c_config, + ); + + // Convert to MultiMaster mode + let slave_config = SlaveAddrConfig::basic(I2C_SLAVE_ADDR); + let i2c_slave = i2c_master.into_slave_multimaster(slave_config); + + spawner.spawn(i2c_slave_task(i2c_slave)).unwrap(); +} + +#[embassy_executor::task] +pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Async, i2c::mode::MultiMaster>) { + info!("Async I2C slave ready at address 0x{:02X}", I2C_SLAVE_ADDR); + + loop { + match i2c_slave.listen().await { + Ok(SlaveCommand { kind: SlaveCommandKind::Write, address }) => { + let addr_val = match address { + Address::SevenBit(addr) => addr, + Address::TenBit(addr) => (addr & 0xFF) as u8, + }; + + info!("I2C: Received write command - Address 0x{:02X}", addr_val); + + let mut data_buffer = I2C_BUFFER.lock().await; + + match i2c_slave.respond_to_write(&mut *data_buffer).await { + Ok(_) => { + info!("I2C: Data received - Buffer now contains: 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}", + data_buffer[0], data_buffer[1], data_buffer[2], data_buffer[3], data_buffer[4], data_buffer[5], data_buffer[6], data_buffer[7]); + } + Err(e) => { + error!("I2C: Write error: {}", format_i2c_error(&e)); + } + } + } + + Ok(SlaveCommand { kind: SlaveCommandKind::Read, address }) => { + let addr_val = match address { + Address::SevenBit(addr) => addr, + Address::TenBit(addr) => (addr & 0xFF) as u8, // Show low byte for 10-bit + }; + + info!("I2C: Received read command - Address 0x{:02X}", addr_val); + + let data_buffer = I2C_BUFFER.lock().await; + + match i2c_slave.respond_to_read(&data_buffer[..BUFFER_SIZE]).await { + Ok(_) => { + info!("I2C: Responded to read command"); + } + Err(e) => { + error!("I2C: Read error: {}", format_i2c_error(&e)); + } + } + } + + Err(e) => { + error!("I2C: Listen error: {}", format_i2c_error(&e)); + Timer::after(Duration::from_millis(100)).await; + } + } + } +} + +fn format_i2c_error(e: &embassy_stm32::i2c::Error) -> &'static str { + match e { + embassy_stm32::i2c::Error::Bus => "Bus", + embassy_stm32::i2c::Error::Arbitration => "Arbitration", + embassy_stm32::i2c::Error::Nack => "Nack", + embassy_stm32::i2c::Error::Timeout => "Timeout", + embassy_stm32::i2c::Error::Crc => "Crc", + embassy_stm32::i2c::Error::Overrun => "Overrun", + embassy_stm32::i2c::Error::ZeroLengthTransfer => "ZeroLengthTransfer", + } +} diff --git a/examples/stm32f4/src/bin/i2c_slave_blocking.rs b/examples/stm32f4/src/bin/i2c_slave_blocking.rs new file mode 100644 index 000000000..c55f2f6c1 --- /dev/null +++ b/examples/stm32f4/src/bin/i2c_slave_blocking.rs @@ -0,0 +1,118 @@ +//! Complete I2C slave example using blocking operations +//! +//! This example shows how to set up an STM32F4 as an I2C slave device +//! that can handle both read and write transactions from master devices. + +#![no_std] +#![no_main] + +use defmt_rtt as _; +use defmt::{error, info}; +use embassy_executor::Spawner; +use embassy_stm32::i2c::{self, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind, Address}; +use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_stm32::time::Hertz; +use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; +use embassy_sync::mutex::Mutex; +use embassy_time::{Duration, Timer}; +use panic_probe as _; + +pub const I2C_SLAVE_ADDR: u8 = 0x42; +pub const BUFFER_SIZE: usize = 8; +static I2C_BUFFER: Mutex = Mutex::new([0; BUFFER_SIZE]); + +bind_interrupts!(struct Irqs { + I2C1_EV => i2c::EventInterruptHandler; + I2C1_ER => i2c::ErrorInterruptHandler; +}); + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + + // Configure I2C + let mut i2c_config = i2c::Config::default(); + i2c_config.sda_pullup = false; + i2c_config.scl_pullup = false; + i2c_config.frequency = Hertz(100_000); + i2c_config.timeout = embassy_time::Duration::from_millis(30000); + + // Initialize I2C as master first + let i2c_master = I2c::new_blocking( + p.I2C1, + p.PB8, // SCL + p.PB9, // SDA + i2c_config, + ); + + // Convert to slave+master mode + let slave_config = SlaveAddrConfig::basic(I2C_SLAVE_ADDR); + let i2c_slave = i2c_master.into_slave_multimaster(slave_config); + + spawner.spawn(i2c_slave_task(i2c_slave)).unwrap(); +} + +#[embassy_executor::task] +pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Blocking, i2c::mode::MultiMaster>) { + info!("Blocking I2C slave ready at address 0x{:02X}", I2C_SLAVE_ADDR); + + loop { + match i2c_slave.blocking_listen() { + Ok(SlaveCommand { kind: SlaveCommandKind::Write, address }) => { + let addr_val = match address { + Address::SevenBit(addr) => addr, + Address::TenBit(addr) => (addr & 0xFF) as u8, + }; + + info!("I2C: Received write command - Address 0x{:02X}", addr_val); + let mut data_buffer = I2C_BUFFER.lock().await; + + match i2c_slave.blocking_respond_to_write(&mut *data_buffer) { + Ok(bytes_received) => { + info!("I2C: Received {} bytes - Buffer now contains: 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}", + bytes_received, data_buffer[0], data_buffer[1], data_buffer[2], data_buffer[3], data_buffer[4], data_buffer[5], data_buffer[6], data_buffer[7]); + } + Err(e) => { + error!("I2C: Write error: {}", format_i2c_error(&e)); + } + } + } + + Ok(SlaveCommand { kind: SlaveCommandKind::Read, address }) => { + let addr_val = match address { + Address::SevenBit(addr) => addr, + Address::TenBit(addr) => (addr & 0xFF) as u8, // Show low byte for 10-bit + }; + + info!("I2C: Received read command - Address 0x{:02X}", addr_val); + let data_buffer = I2C_BUFFER.lock().await; + + match i2c_slave.blocking_respond_to_read(&data_buffer[..BUFFER_SIZE]) { + Ok(bytes_sent) => { + info!("I2C: Responded to read - {} bytes sent", bytes_sent); + } + Err(e) => { + error!("I2C: Read error: {}", format_i2c_error(&e)); + } + } + } + + Err(e) => { + error!("I2C: Listen error: {}", format_i2c_error(&e)); + Timer::after(Duration::from_millis(100)).await; + } + } + } +} + +fn format_i2c_error(e: &embassy_stm32::i2c::Error) -> &'static str { + match e { + embassy_stm32::i2c::Error::Bus => "Bus", + embassy_stm32::i2c::Error::Arbitration => "Arbitration", + embassy_stm32::i2c::Error::Nack => "Nack", + embassy_stm32::i2c::Error::Timeout => "Timeout", + embassy_stm32::i2c::Error::Crc => "Crc", + embassy_stm32::i2c::Error::Overrun => "Overrun", + embassy_stm32::i2c::Error::ZeroLengthTransfer => "ZeroLengthTransfer", + } +} -- cgit From 944ac0bf138ab78f602627fae97891024c8fd082 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Sat, 23 Aug 2025 10:50:05 +0200 Subject: Run cargo fmt for examples --- examples/stm32f4/src/bin/i2c_slave_async.rs | 44 ++++++++++++++------------ examples/stm32f4/src/bin/i2c_slave_blocking.rs | 41 +++++++++++++----------- 2 files changed, 47 insertions(+), 38 deletions(-) (limited to 'examples') diff --git a/examples/stm32f4/src/bin/i2c_slave_async.rs b/examples/stm32f4/src/bin/i2c_slave_async.rs index 072c9875e..c0719af5e 100644 --- a/examples/stm32f4/src/bin/i2c_slave_async.rs +++ b/examples/stm32f4/src/bin/i2c_slave_async.rs @@ -1,5 +1,5 @@ //! I2C slave example using async operations with DMA -//! +//! //! This example demonstrates DMA-accelerated I2C slave operations, //! which provide better performance and lower CPU overhead for //! high-frequency I2C transactions. @@ -7,12 +7,12 @@ #![no_std] #![no_main] -use defmt_rtt as _; use defmt::{error, info}; +use defmt_rtt as _; use embassy_executor::Spawner; -use embassy_stm32::{bind_interrupts, peripherals}; -use embassy_stm32::i2c::{self, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind, Address}; +use embassy_stm32::i2c::{self, Address, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind}; use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Timer}; @@ -30,38 +30,39 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - + // Configure I2C let mut i2c_config = i2c::Config::default(); i2c_config.sda_pullup = false; i2c_config.scl_pullup = false; i2c_config.frequency = Hertz(100_000); // 100kHz I2C speed - + // Initialize I2C as master first let i2c_master = I2c::new( - p.I2C1, - p.PB8, // SCL - p.PB9, // SDA - Irqs, - p.DMA1_CH6, // TX DMA + p.I2C1, p.PB8, // SCL + p.PB9, // SDA + Irqs, p.DMA1_CH6, // TX DMA p.DMA1_CH0, // RX DMA i2c_config, ); - + // Convert to MultiMaster mode let slave_config = SlaveAddrConfig::basic(I2C_SLAVE_ADDR); let i2c_slave = i2c_master.into_slave_multimaster(slave_config); - + spawner.spawn(i2c_slave_task(i2c_slave)).unwrap(); } #[embassy_executor::task] pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Async, i2c::mode::MultiMaster>) { info!("Async I2C slave ready at address 0x{:02X}", I2C_SLAVE_ADDR); - + loop { match i2c_slave.listen().await { - Ok(SlaveCommand { kind: SlaveCommandKind::Write, address }) => { + Ok(SlaveCommand { + kind: SlaveCommandKind::Write, + address, + }) => { let addr_val = match address { Address::SevenBit(addr) => addr, Address::TenBit(addr) => (addr & 0xFF) as u8, @@ -70,7 +71,7 @@ pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Asy info!("I2C: Received write command - Address 0x{:02X}", addr_val); let mut data_buffer = I2C_BUFFER.lock().await; - + match i2c_slave.respond_to_write(&mut *data_buffer).await { Ok(_) => { info!("I2C: Data received - Buffer now contains: 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}", @@ -81,8 +82,11 @@ pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Asy } } } - - Ok(SlaveCommand { kind: SlaveCommandKind::Read, address }) => { + + Ok(SlaveCommand { + kind: SlaveCommandKind::Read, + address, + }) => { let addr_val = match address { Address::SevenBit(addr) => addr, Address::TenBit(addr) => (addr & 0xFF) as u8, // Show low byte for 10-bit @@ -91,7 +95,7 @@ pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Asy info!("I2C: Received read command - Address 0x{:02X}", addr_val); let data_buffer = I2C_BUFFER.lock().await; - + match i2c_slave.respond_to_read(&data_buffer[..BUFFER_SIZE]).await { Ok(_) => { info!("I2C: Responded to read command"); @@ -101,7 +105,7 @@ pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Asy } } } - + Err(e) => { error!("I2C: Listen error: {}", format_i2c_error(&e)); Timer::after(Duration::from_millis(100)).await; diff --git a/examples/stm32f4/src/bin/i2c_slave_blocking.rs b/examples/stm32f4/src/bin/i2c_slave_blocking.rs index c55f2f6c1..e027cd511 100644 --- a/examples/stm32f4/src/bin/i2c_slave_blocking.rs +++ b/examples/stm32f4/src/bin/i2c_slave_blocking.rs @@ -1,17 +1,17 @@ //! Complete I2C slave example using blocking operations -//! +//! //! This example shows how to set up an STM32F4 as an I2C slave device //! that can handle both read and write transactions from master devices. #![no_std] #![no_main] -use defmt_rtt as _; use defmt::{error, info}; +use defmt_rtt as _; use embassy_executor::Spawner; -use embassy_stm32::i2c::{self, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind, Address}; -use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_stm32::i2c::{self, Address, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind}; use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Timer}; @@ -29,36 +29,38 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - + // Configure I2C let mut i2c_config = i2c::Config::default(); i2c_config.sda_pullup = false; i2c_config.scl_pullup = false; i2c_config.frequency = Hertz(100_000); i2c_config.timeout = embassy_time::Duration::from_millis(30000); - + // Initialize I2C as master first let i2c_master = I2c::new_blocking( - p.I2C1, - p.PB8, // SCL - p.PB9, // SDA + p.I2C1, p.PB8, // SCL + p.PB9, // SDA i2c_config, ); - + // Convert to slave+master mode let slave_config = SlaveAddrConfig::basic(I2C_SLAVE_ADDR); let i2c_slave = i2c_master.into_slave_multimaster(slave_config); - + spawner.spawn(i2c_slave_task(i2c_slave)).unwrap(); } #[embassy_executor::task] pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Blocking, i2c::mode::MultiMaster>) { info!("Blocking I2C slave ready at address 0x{:02X}", I2C_SLAVE_ADDR); - + loop { match i2c_slave.blocking_listen() { - Ok(SlaveCommand { kind: SlaveCommandKind::Write, address }) => { + Ok(SlaveCommand { + kind: SlaveCommandKind::Write, + address, + }) => { let addr_val = match address { Address::SevenBit(addr) => addr, Address::TenBit(addr) => (addr & 0xFF) as u8, @@ -66,7 +68,7 @@ pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Blo info!("I2C: Received write command - Address 0x{:02X}", addr_val); let mut data_buffer = I2C_BUFFER.lock().await; - + match i2c_slave.blocking_respond_to_write(&mut *data_buffer) { Ok(bytes_received) => { info!("I2C: Received {} bytes - Buffer now contains: 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}", @@ -77,8 +79,11 @@ pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Blo } } } - - Ok(SlaveCommand { kind: SlaveCommandKind::Read, address }) => { + + Ok(SlaveCommand { + kind: SlaveCommandKind::Read, + address, + }) => { let addr_val = match address { Address::SevenBit(addr) => addr, Address::TenBit(addr) => (addr & 0xFF) as u8, // Show low byte for 10-bit @@ -86,7 +91,7 @@ pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Blo info!("I2C: Received read command - Address 0x{:02X}", addr_val); let data_buffer = I2C_BUFFER.lock().await; - + match i2c_slave.blocking_respond_to_read(&data_buffer[..BUFFER_SIZE]) { Ok(bytes_sent) => { info!("I2C: Responded to read - {} bytes sent", bytes_sent); @@ -96,7 +101,7 @@ pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Blo } } } - + Err(e) => { error!("I2C: Listen error: {}", format_i2c_error(&e)); Timer::after(Duration::from_millis(100)).await; -- cgit From 524db5a935e506036c282e3c0dfa9abc807ac7ee Mon Sep 17 00:00:00 2001 From: HybridChild Date: Sat, 23 Aug 2025 10:53:22 +0200 Subject: Fix formatting in examples --- examples/stm32f4/src/bin/i2c_slave_async.rs | 3 +-- examples/stm32f4/src/bin/i2c_slave_blocking.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/stm32f4/src/bin/i2c_slave_async.rs b/examples/stm32f4/src/bin/i2c_slave_async.rs index c0719af5e..1c48f1ac7 100644 --- a/examples/stm32f4/src/bin/i2c_slave_async.rs +++ b/examples/stm32f4/src/bin/i2c_slave_async.rs @@ -8,7 +8,7 @@ #![no_main] use defmt::{error, info}; -use defmt_rtt as _; +use {defmt_rtt as _, panic_probe as _}; use embassy_executor::Spawner; use embassy_stm32::i2c::{self, Address, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind}; use embassy_stm32::time::Hertz; @@ -16,7 +16,6 @@ use embassy_stm32::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Timer}; -use panic_probe as _; pub const I2C_SLAVE_ADDR: u8 = 0x42; pub const BUFFER_SIZE: usize = 8; diff --git a/examples/stm32f4/src/bin/i2c_slave_blocking.rs b/examples/stm32f4/src/bin/i2c_slave_blocking.rs index e027cd511..a6f4da747 100644 --- a/examples/stm32f4/src/bin/i2c_slave_blocking.rs +++ b/examples/stm32f4/src/bin/i2c_slave_blocking.rs @@ -7,7 +7,7 @@ #![no_main] use defmt::{error, info}; -use defmt_rtt as _; +use {defmt_rtt as _, panic_probe as _}; use embassy_executor::Spawner; use embassy_stm32::i2c::{self, Address, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind}; use embassy_stm32::time::Hertz; @@ -15,7 +15,6 @@ use embassy_stm32::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Timer}; -use panic_probe as _; pub const I2C_SLAVE_ADDR: u8 = 0x42; pub const BUFFER_SIZE: usize = 8; -- cgit From 3c8d078525c69867710bbd291dc135b3a5011702 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Sat, 23 Aug 2025 10:55:00 +0200 Subject: Fix formatting in examples --- examples/stm32f4/src/bin/i2c_slave_async.rs | 2 +- examples/stm32f4/src/bin/i2c_slave_blocking.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/stm32f4/src/bin/i2c_slave_async.rs b/examples/stm32f4/src/bin/i2c_slave_async.rs index 1c48f1ac7..db4a805b6 100644 --- a/examples/stm32f4/src/bin/i2c_slave_async.rs +++ b/examples/stm32f4/src/bin/i2c_slave_async.rs @@ -8,7 +8,6 @@ #![no_main] use defmt::{error, info}; -use {defmt_rtt as _, panic_probe as _}; use embassy_executor::Spawner; use embassy_stm32::i2c::{self, Address, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind}; use embassy_stm32::time::Hertz; @@ -16,6 +15,7 @@ use embassy_stm32::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; pub const I2C_SLAVE_ADDR: u8 = 0x42; pub const BUFFER_SIZE: usize = 8; diff --git a/examples/stm32f4/src/bin/i2c_slave_blocking.rs b/examples/stm32f4/src/bin/i2c_slave_blocking.rs index a6f4da747..a62087a29 100644 --- a/examples/stm32f4/src/bin/i2c_slave_blocking.rs +++ b/examples/stm32f4/src/bin/i2c_slave_blocking.rs @@ -7,7 +7,6 @@ #![no_main] use defmt::{error, info}; -use {defmt_rtt as _, panic_probe as _}; use embassy_executor::Spawner; use embassy_stm32::i2c::{self, Address, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind}; use embassy_stm32::time::Hertz; @@ -15,6 +14,7 @@ use embassy_stm32::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; pub const I2C_SLAVE_ADDR: u8 = 0x42; pub const BUFFER_SIZE: usize = 8; -- cgit From 14a047a9ad75709e0bde8b0fa71f3b4bddedc576 Mon Sep 17 00:00:00 2001 From: maor malka Date: Sun, 24 Aug 2025 21:36:33 -0400 Subject: stm32/adc/v3: added support for DMA based adc sampling --- examples/stm32l4/src/bin/adc_dma.rs | 49 +++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 examples/stm32l4/src/bin/adc_dma.rs (limited to 'examples') diff --git a/examples/stm32l4/src/bin/adc_dma.rs b/examples/stm32l4/src/bin/adc_dma.rs new file mode 100644 index 000000000..1769c735a --- /dev/null +++ b/examples/stm32l4/src/bin/adc_dma.rs @@ -0,0 +1,49 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::adc::{Adc, AdcChannel, SampleTime}; +use embassy_stm32::Config; +use {defmt_rtt as _, panic_probe as _}; + +const DMA_BUF_LEN: usize = 512; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + info!("Hello World!"); + + let config = Config::default(); + + let p = embassy_stm32::init(config); + + let mut adc = Adc::new(p.ADC1); + let mut adc_pin0 = p.PA0.degrade_adc(); + let mut adc_pin1 = p.PA1.degrade_adc(); + let mut adc_dma_buf = [0u16; DMA_BUF_LEN]; + let mut measurements = [0u16; DMA_BUF_LEN / 2]; + let mut ring_buffered_adc = adc.into_ring_buffered( + p.DMA1_CH1, + &mut adc_dma_buf, + [ + (&mut adc_pin0, SampleTime::CYCLES640_5), + (&mut adc_pin1, SampleTime::CYCLES640_5), + ] + .into_iter(), + ); + + info!("starting measurement loop"); + loop { + match ring_buffered_adc.read(&mut measurements).await { + Ok(_) => { + //note: originally there was a print here showing all the samples, + //but even that takes too much time and would cause adc overruns + info!("adc1 first 10 samples: {}",measurements[0..10]); + } + Err(e) => { + warn!("Error: {:?}", e); + } + } + } + +} -- cgit From 0b8da5ab8f6469bdf2adf7462e7ebedee93dde3f Mon Sep 17 00:00:00 2001 From: maor malka Date: Sun, 24 Aug 2025 21:42:30 -0400 Subject: stm32l4/example/adc_dma: missing clock configuration --- examples/stm32l4/src/bin/adc_dma.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/stm32l4/src/bin/adc_dma.rs b/examples/stm32l4/src/bin/adc_dma.rs index 1769c735a..a5b7b0c5e 100644 --- a/examples/stm32l4/src/bin/adc_dma.rs +++ b/examples/stm32l4/src/bin/adc_dma.rs @@ -13,8 +13,11 @@ const DMA_BUF_LEN: usize = 512; async fn main(_spawner: Spawner) { info!("Hello World!"); - let config = Config::default(); - + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.mux.adcsel = mux::Adcsel::SYS; + } let p = embassy_stm32::init(config); let mut adc = Adc::new(p.ADC1); @@ -36,14 +39,13 @@ async fn main(_spawner: Spawner) { loop { match ring_buffered_adc.read(&mut measurements).await { Ok(_) => { - //note: originally there was a print here showing all the samples, + //note: originally there was a print here showing all the samples, //but even that takes too much time and would cause adc overruns - info!("adc1 first 10 samples: {}",measurements[0..10]); + info!("adc1 first 10 samples: {}", measurements[0..10]); } Err(e) => { warn!("Error: {:?}", e); } } } - } -- cgit From cb0175a89f072d38393368ef380d9db8e3994740 Mon Sep 17 00:00:00 2001 From: maor malka Date: Tue, 7 Oct 2025 15:03:31 -0400 Subject: stm32/adc/v3: missing cfg option for adc_u0 fro into_ring_buffered --- examples/stm32l4/src/bin/adc_dma.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32l4/src/bin/adc_dma.rs b/examples/stm32l4/src/bin/adc_dma.rs index a5b7b0c5e..7a9200edd 100644 --- a/examples/stm32l4/src/bin/adc_dma.rs +++ b/examples/stm32l4/src/bin/adc_dma.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, AdcChannel, SampleTime}; use embassy_stm32::Config; +use embassy_stm32::adc::{Adc, AdcChannel, SampleTime}; use {defmt_rtt as _, panic_probe as _}; const DMA_BUF_LEN: usize = 512; -- cgit From c685d80578b0fea8f66f8f8c858c9d59857586b5 Mon Sep 17 00:00:00 2001 From: crispaudio Date: Fri, 29 Aug 2025 12:32:38 +0200 Subject: mspm0-i2c-target: add i2c target with example --- examples/mspm0g3507/src/bin/i2c_target.rs | 60 +++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 examples/mspm0g3507/src/bin/i2c_target.rs (limited to 'examples') diff --git a/examples/mspm0g3507/src/bin/i2c_target.rs b/examples/mspm0g3507/src/bin/i2c_target.rs new file mode 100644 index 000000000..b1336cdd2 --- /dev/null +++ b/examples/mspm0g3507/src/bin/i2c_target.rs @@ -0,0 +1,60 @@ +//! Example of using blocking I2C +//! +//! This uses the virtual COM port provided on the LP-MSPM0G3507 board. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::i2c_target::{Command, I2cTarget, ReadStatus}; +use embassy_mspm0::peripherals::I2C1; +use embassy_mspm0::{bind_interrupts, i2c}; +use {defmt_rtt as _, panic_halt as _}; + +bind_interrupts!(struct Irqs { + I2C1 => i2c::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + let p = embassy_mspm0::init(Default::default()); + + let instance = p.I2C1; + let scl = p.PB2; + let sda = p.PB3; + + let mut config = i2c::Config::default(); + config.general_call = true; + let mut i2c = I2cTarget::new(instance, scl, sda, Irqs, config).unwrap(); + + let mut read = [0u8; 8]; + let data = [8u8; 2]; + let data_wr = [9u8; 2]; + + loop { + match i2c.listen(&mut read).await { + Ok(Command::GeneralCall(_)) => info!("General call received"), + Ok(Command::Read) => { + info!("Read command received"); + match i2c.respond_to_read(&data).await.unwrap() { + ReadStatus::Done => info!("Finished reading"), + ReadStatus::NeedMoreBytes => { + info!("Read needs more bytes - will reset"); + i2c.reset().unwrap(); + } + ReadStatus::LeftoverBytes(_) => { + info!("Leftover bytes received"); + i2c.flush_tx_fifo(); + } + } + } + Ok(Command::Write(_)) => info!("Write command received"), + Ok(Command::WriteRead(_)) => { + info!("Write-Read command received"); + i2c.respond_and_fill(&data_wr, 0xFE).await.unwrap(); + } + Err(e) => info!("Got error {}", e), + } + } +} -- cgit From a12299d35d4641a8dfee27c52ec274257815cb3f Mon Sep 17 00:00:00 2001 From: crispaudio Date: Fri, 29 Aug 2025 12:44:40 +0200 Subject: mspm0-i2c-target: fix comment in example --- examples/mspm0g3507/src/bin/i2c_target.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/mspm0g3507/src/bin/i2c_target.rs b/examples/mspm0g3507/src/bin/i2c_target.rs index b1336cdd2..cb1d315fe 100644 --- a/examples/mspm0g3507/src/bin/i2c_target.rs +++ b/examples/mspm0g3507/src/bin/i2c_target.rs @@ -1,4 +1,4 @@ -//! Example of using blocking I2C +//! Example of using async I2C target //! //! This uses the virtual COM port provided on the LP-MSPM0G3507 board. -- cgit From 7797cc0effa069b78be29ff19b81068b17f98ac2 Mon Sep 17 00:00:00 2001 From: Iooon Date: Wed, 1 Oct 2025 11:00:44 +0200 Subject: mspm0-i2c-target: add mspm0l1306 example and set target address explicitly in examples --- examples/mspm0g3507/src/bin/i2c_target.rs | 1 + examples/mspm0l1306/src/bin/i2c_target.rs | 61 +++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 examples/mspm0l1306/src/bin/i2c_target.rs (limited to 'examples') diff --git a/examples/mspm0g3507/src/bin/i2c_target.rs b/examples/mspm0g3507/src/bin/i2c_target.rs index cb1d315fe..ac7083a20 100644 --- a/examples/mspm0g3507/src/bin/i2c_target.rs +++ b/examples/mspm0g3507/src/bin/i2c_target.rs @@ -25,6 +25,7 @@ async fn main(_spawner: Spawner) -> ! { let sda = p.PB3; let mut config = i2c::Config::default(); + config.target_addr = 0x48; config.general_call = true; let mut i2c = I2cTarget::new(instance, scl, sda, Irqs, config).unwrap(); diff --git a/examples/mspm0l1306/src/bin/i2c_target.rs b/examples/mspm0l1306/src/bin/i2c_target.rs new file mode 100644 index 000000000..38d309e6b --- /dev/null +++ b/examples/mspm0l1306/src/bin/i2c_target.rs @@ -0,0 +1,61 @@ +//! Example of using async I2C target +//! +//! This uses the virtual COM port provided on the LP-MSPM0L1306 board. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::i2c_target::{Command, I2cTarget, ReadStatus}; +use embassy_mspm0::peripherals::I2C0; +use embassy_mspm0::{bind_interrupts, i2c}; +use {defmt_rtt as _, panic_halt as _}; + +bind_interrupts!(struct Irqs { + I2C0 => i2c::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + let p = embassy_mspm0::init(Default::default()); + + let instance = p.I2C0; + let scl = p.PA1; + let sda = p.PA0; + + let mut config = i2c::Config::default(); + config.target_addr = 0x48; + config.general_call = true; + let mut i2c = I2cTarget::new(instance, scl, sda, Irqs, config).unwrap(); + + let mut read = [0u8; 8]; + let data = [8u8; 2]; + let data_wr = [9u8; 2]; + + loop { + match i2c.listen(&mut read).await { + Ok(Command::GeneralCall(_)) => info!("General call received"), + Ok(Command::Read) => { + info!("Read command received"); + match i2c.respond_to_read(&data).await.unwrap() { + ReadStatus::Done => info!("Finished reading"), + ReadStatus::NeedMoreBytes => { + info!("Read needs more bytes - will reset"); + i2c.reset().unwrap(); + } + ReadStatus::LeftoverBytes(_) => { + info!("Leftover bytes received"); + i2c.flush_tx_fifo(); + } + } + } + Ok(Command::Write(_)) => info!("Write command received"), + Ok(Command::WriteRead(_)) => { + info!("Write-Read command received"); + i2c.respond_and_fill(&data_wr, 0xFE).await.unwrap(); + } + Err(e) => info!("Got error {}", e), + } + } +} -- cgit From 4217a264dba3a77da38897537f90e1fdfe5b9ddb Mon Sep 17 00:00:00 2001 From: crispaudio Date: Mon, 6 Oct 2025 10:06:28 +0200 Subject: mspm0-i2c-target: update examples with split config --- examples/mspm0g3507/src/bin/i2c_target.rs | 12 +++++++----- examples/mspm0l1306/src/bin/i2c_target.rs | 12 +++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) (limited to 'examples') diff --git a/examples/mspm0g3507/src/bin/i2c_target.rs b/examples/mspm0g3507/src/bin/i2c_target.rs index ac7083a20..5dd718eaf 100644 --- a/examples/mspm0g3507/src/bin/i2c_target.rs +++ b/examples/mspm0g3507/src/bin/i2c_target.rs @@ -7,7 +7,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::i2c_target::{Command, I2cTarget, ReadStatus}; +use embassy_mspm0::i2c::Config; +use embassy_mspm0::i2c_target::{Command, Config as TargetConfig, I2cTarget, ReadStatus}; use embassy_mspm0::peripherals::I2C1; use embassy_mspm0::{bind_interrupts, i2c}; use {defmt_rtt as _, panic_halt as _}; @@ -24,10 +25,11 @@ async fn main(_spawner: Spawner) -> ! { let scl = p.PB2; let sda = p.PB3; - let mut config = i2c::Config::default(); - config.target_addr = 0x48; - config.general_call = true; - let mut i2c = I2cTarget::new(instance, scl, sda, Irqs, config).unwrap(); + let config = Config::default(); + let mut target_config = TargetConfig::default(); + target_config.target_addr = 0x48; + target_config.general_call = true; + let mut i2c = I2cTarget::new(instance, scl, sda, Irqs, config, target_config).unwrap(); let mut read = [0u8; 8]; let data = [8u8; 2]; diff --git a/examples/mspm0l1306/src/bin/i2c_target.rs b/examples/mspm0l1306/src/bin/i2c_target.rs index 38d309e6b..4d147d08b 100644 --- a/examples/mspm0l1306/src/bin/i2c_target.rs +++ b/examples/mspm0l1306/src/bin/i2c_target.rs @@ -7,7 +7,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::i2c_target::{Command, I2cTarget, ReadStatus}; +use embassy_mspm0::i2c::Config; +use embassy_mspm0::i2c_target::{Command, Config as TargetConfig, I2cTarget, ReadStatus}; use embassy_mspm0::peripherals::I2C0; use embassy_mspm0::{bind_interrupts, i2c}; use {defmt_rtt as _, panic_halt as _}; @@ -24,10 +25,11 @@ async fn main(_spawner: Spawner) -> ! { let scl = p.PA1; let sda = p.PA0; - let mut config = i2c::Config::default(); - config.target_addr = 0x48; - config.general_call = true; - let mut i2c = I2cTarget::new(instance, scl, sda, Irqs, config).unwrap(); + let config = Config::default(); + let mut target_config = TargetConfig::default(); + target_config.target_addr = 0x48; + target_config.general_call = true; + let mut i2c = I2cTarget::new(instance, scl, sda, Irqs, config, target_config).unwrap(); let mut read = [0u8; 8]; let data = [8u8; 2]; -- cgit From 6fef28da94d133ce0cd36b5fb6ef2ef302c8eea0 Mon Sep 17 00:00:00 2001 From: Haobo Gu Date: Tue, 14 Oct 2025 23:39:52 +0800 Subject: feat(nrf): add rtc support for nRF54L Signed-off-by: Haobo Gu --- examples/nrf54l15/Cargo.toml | 2 ++ examples/nrf54l15/src/bin/rtc.rs | 56 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 examples/nrf54l15/src/bin/rtc.rs (limited to 'examples') diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml index a053dd0ec..541e79fcb 100644 --- a/examples/nrf54l15/Cargo.toml +++ b/examples/nrf54l15/Cargo.toml @@ -8,6 +8,7 @@ publish = false [dependencies] embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "1.0.1" @@ -18,6 +19,7 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing cortex-m-rt = "0.7.0" embedded-storage = "0.3.1" +portable-atomic = "1" [profile.release] debug = 2 diff --git a/examples/nrf54l15/src/bin/rtc.rs b/examples/nrf54l15/src/bin/rtc.rs new file mode 100644 index 000000000..a45aaca52 --- /dev/null +++ b/examples/nrf54l15/src/bin/rtc.rs @@ -0,0 +1,56 @@ +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use embassy_executor::Spawner; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_nrf::interrupt; +use embassy_nrf::rtc::Rtc; +use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use portable_atomic::AtomicU64; +use {defmt_rtt as _, panic_probe as _}; + +// 64 bit counter which will never overflow. +static TICK_COUNTER: AtomicU64 = AtomicU64::new(0); +static RTC: Mutex>>> = Mutex::new(RefCell::new(None)); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + defmt::println!("nRF54L15 RTC example"); + let p = embassy_nrf::init(Default::default()); + let mut led = Output::new(p.P2_09, Level::High, OutputDrive::Standard); + // Counter resolution is 125 ms. + let mut rtc = Rtc::new(p.RTC10, (1 << 12) - 1).unwrap(); + rtc.enable_interrupt(embassy_nrf::rtc::Interrupt::Tick, true); + rtc.enable_event(embassy_nrf::rtc::Interrupt::Tick); + rtc.enable(); + RTC.lock(|r| { + let mut rtc_borrow = r.borrow_mut(); + *rtc_borrow = Some(rtc); + }); + + let mut last_counter_val = 0; + loop { + let current = TICK_COUNTER.load(core::sync::atomic::Ordering::Relaxed); + if current != last_counter_val { + led.toggle(); + last_counter_val = current; + } + } +} + +#[interrupt] +fn RTC10() { + // For 64-bit, we do not need to worry about overflowing, at least not for realistic program + // lifetimes. + TICK_COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed); + RTC.lock(|r| { + let mut rtc_borrow = r.borrow_mut(); + rtc_borrow + .as_mut() + .unwrap() + .reset_event(embassy_nrf::rtc::Interrupt::Tick); + }); +} -- cgit From 369959e654d095d0e3d95597693bd64fcdb50ec5 Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Wed, 15 Oct 2025 14:53:40 +0200 Subject: embassy_nrf: update examples --- examples/nrf52840/src/bin/i2s_monitor.rs | 9 ++++----- examples/nrf52840/src/bin/pwm.rs | 14 ++++++++------ examples/nrf52840/src/bin/pwm_servo.rs | 14 +++++++------- 3 files changed, 19 insertions(+), 18 deletions(-) (limited to 'examples') diff --git a/examples/nrf52840/src/bin/i2s_monitor.rs b/examples/nrf52840/src/bin/i2s_monitor.rs index 66b429b09..a54659101 100644 --- a/examples/nrf52840/src/bin/i2s_monitor.rs +++ b/examples/nrf52840/src/bin/i2s_monitor.rs @@ -4,7 +4,7 @@ use defmt::{debug, error, info}; use embassy_executor::Spawner; use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, I2S, MasterClock, Sample as _, SampleWidth}; -use embassy_nrf::pwm::{Prescaler, SimplePwm}; +use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm}; use embassy_nrf::{bind_interrupts, peripherals}; use {defmt_rtt as _, panic_probe as _}; @@ -34,7 +34,7 @@ async fn main(_spawner: Spawner) { I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers); // Configure the PWM to use the pins corresponding to the RGB leds - let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24); + let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24, &Default::default()); pwm.set_prescaler(Prescaler::Div1); pwm.set_max_duty(255); @@ -47,9 +47,8 @@ async fn main(_spawner: Spawner) { let rgb = rgb_from_rms(rms); debug!("RMS: {}, RGB: {:?}", rms, rgb); - for i in 0..3 { - pwm.set_duty(i, rgb[i].into()); - } + let duties = rgb.map(|byte| DutyCycle::normal(u16::from(byte))); + pwm.set_all_duties([duties[0], duties[1], duties[2], DutyCycle::normal(0)]); if let Err(err) = input_stream.receive().await { error!("{}", err); diff --git a/examples/nrf52840/src/bin/pwm.rs b/examples/nrf52840/src/bin/pwm.rs index a5bb1347a..02f9b4191 100644 --- a/examples/nrf52840/src/bin/pwm.rs +++ b/examples/nrf52840/src/bin/pwm.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_nrf::pwm::{Prescaler, SimplePwm}; +use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -71,7 +71,7 @@ static DUTY: [u16; 1024] = [ #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); - let mut pwm = SimplePwm::new_4ch(p.PWM0, p.P0_13, p.P0_14, p.P0_16, p.P0_15); + let mut pwm = SimplePwm::new_4ch(p.PWM0, p.P0_13, p.P0_14, p.P0_16, p.P0_15, &Default::default()); pwm.set_prescaler(Prescaler::Div1); pwm.set_max_duty(32767); info!("pwm initialized!"); @@ -79,10 +79,12 @@ async fn main(_spawner: Spawner) { let mut i = 0; loop { i += 1; - pwm.set_duty(0, DUTY[i % 1024]); - pwm.set_duty(1, DUTY[(i + 256) % 1024]); - pwm.set_duty(2, DUTY[(i + 512) % 1024]); - pwm.set_duty(3, DUTY[(i + 768) % 1024]); + pwm.set_all_duties([ + DutyCycle::normal(DUTY[i % 1024]), + DutyCycle::normal(DUTY[(i + 256) % 1024]), + DutyCycle::normal(DUTY[(i + 512) % 1024]), + DutyCycle::normal(DUTY[(i + 768) % 1024]), + ]); Timer::after_millis(3).await; } } diff --git a/examples/nrf52840/src/bin/pwm_servo.rs b/examples/nrf52840/src/bin/pwm_servo.rs index d772d2f5d..93cb984e6 100644 --- a/examples/nrf52840/src/bin/pwm_servo.rs +++ b/examples/nrf52840/src/bin/pwm_servo.rs @@ -3,14 +3,14 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_nrf::pwm::{Prescaler, SimplePwm}; +use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); - let mut pwm = SimplePwm::new_1ch(p.PWM0, p.P0_05); + let mut pwm = SimplePwm::new_1ch(p.PWM0, p.P0_05, &Default::default()); // sg90 microervo requires 50hz or 20ms period // set_period can only set down to 125khz so we cant use it directly // Div128 is 125khz or 0.000008s or 0.008ms, 20/0.008 is 2500 is top @@ -24,23 +24,23 @@ async fn main(_spawner: Spawner) { loop { info!("45 deg"); // poor mans inverting, subtract our value from max_duty - pwm.set_duty(0, 2500 - 156); + pwm.set_duty(0, DutyCycle::normal(2500 - 156)); Timer::after_millis(5000).await; info!("90 deg"); - pwm.set_duty(0, 2500 - 187); + pwm.set_duty(0, DutyCycle::normal(2500 - 187)); Timer::after_millis(5000).await; info!("135 deg"); - pwm.set_duty(0, 2500 - 218); + pwm.set_duty(0, DutyCycle::normal(2500 - 218)); Timer::after_millis(5000).await; info!("180 deg"); - pwm.set_duty(0, 2500 - 250); + pwm.set_duty(0, DutyCycle::normal(2500 - 250)); Timer::after_millis(5000).await; info!("0 deg"); - pwm.set_duty(0, 2500 - 125); + pwm.set_duty(0, DutyCycle::normal(2500 - 125)); Timer::after_millis(5000).await; } } -- cgit From 5ed604fc0453066f0d0cf0c161823df5f4b7900f Mon Sep 17 00:00:00 2001 From: Roi Bachynskyi Date: Thu, 25 Sep 2025 15:19:45 +0300 Subject: nxp/lpc55: pwm simple --- examples/lpc55s69/src/bin/pwm.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 examples/lpc55s69/src/bin/pwm.rs (limited to 'examples') diff --git a/examples/lpc55s69/src/bin/pwm.rs b/examples/lpc55s69/src/bin/pwm.rs new file mode 100644 index 000000000..93b898b9d --- /dev/null +++ b/examples/lpc55s69/src/bin/pwm.rs @@ -0,0 +1,18 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_nxp::pwm::{Config, Pwm}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_halt as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nxp::init(Default::default()); + let pwm = Pwm::new_output(p.PWM_OUTPUT1, p.PIO0_18, Config::new(1_000_000_000, 2_000_000_000)); + loop { + info!("Counter: {}", pwm.counter()); + Timer::after_millis(50).await; + } +} -- cgit From de5760cc81a00966c61d668c41f6e3e4709f0283 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 14 Oct 2025 13:23:50 +0200 Subject: feat: improve nrf54 support using new nrf-pac * Update nrf-pac to version that modifies nrf52 register layout to match nrf54 to reduce the amount of cfg needed for nrf54 support. * Make the following peripherals available on nrf54: twim, twis, spim, spis, uart, buffered uarte, dppi, gpiote, pwm, saadc * Add examples tested on the nrf54 dk Some code is based on or copied from other pull requests, modified to match the new nrf-pac layout. Co-authored-by: Dmitry Tarnyagin --- examples/nrf52840/src/bin/egu.rs | 15 +++-- examples/nrf52840/src/bin/gpiote_channel.rs | 26 ++------ examples/nrf52840/src/bin/ppi.rs | 34 ++++------- examples/nrf52840/src/bin/pwm_sequence_ppi.rs | 14 +---- examples/nrf5340/src/bin/gpiote_channel.rs | 26 ++------ examples/nrf54l15/Cargo.toml | 5 ++ examples/nrf54l15/src/bin/buffered_uart.rs | 49 +++++++++++++++ examples/nrf54l15/src/bin/gpiote_channel.rs | 49 +++++++++++++++ examples/nrf54l15/src/bin/gpiote_port.rs | 33 ++++++++++ examples/nrf54l15/src/bin/pwm.rs | 86 +++++++++++++++++++++++++++ examples/nrf54l15/src/bin/saadc.rs | 28 +++++++++ examples/nrf54l15/src/bin/spim.rs | 72 ++++++++++++++++++++++ examples/nrf54l15/src/bin/twim.rs | 37 ++++++++++++ examples/nrf54l15/src/bin/twis.rs | 47 +++++++++++++++ examples/nrf54l15/src/bin/uart.rs | 37 ++++++++++++ 15 files changed, 476 insertions(+), 82 deletions(-) create mode 100644 examples/nrf54l15/src/bin/buffered_uart.rs create mode 100644 examples/nrf54l15/src/bin/gpiote_channel.rs create mode 100644 examples/nrf54l15/src/bin/gpiote_port.rs create mode 100644 examples/nrf54l15/src/bin/pwm.rs create mode 100644 examples/nrf54l15/src/bin/saadc.rs create mode 100644 examples/nrf54l15/src/bin/spim.rs create mode 100644 examples/nrf54l15/src/bin/twim.rs create mode 100644 examples/nrf54l15/src/bin/twis.rs create mode 100644 examples/nrf54l15/src/bin/uart.rs (limited to 'examples') diff --git a/examples/nrf52840/src/bin/egu.rs b/examples/nrf52840/src/bin/egu.rs index 8bf712697..36eba8084 100644 --- a/examples/nrf52840/src/bin/egu.rs +++ b/examples/nrf52840/src/bin/egu.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_nrf::egu::{Egu, TriggerNumber}; -use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; +use embassy_nrf::gpio::{Level, OutputDrive, Pull}; use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity, OutputChannel, OutputChannelPolarity}; use embassy_nrf::peripherals::{PPI_CH0, PPI_CH1, PPI_CH2}; use embassy_nrf::ppi::Ppi; @@ -17,12 +17,15 @@ use {defmt_rtt as _, panic_probe as _}; async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); - let led1 = Output::new(p.P0_13, Level::High, OutputDrive::Standard); - let btn1 = Input::new(p.P0_11, Pull::Up); - let mut egu1 = Egu::new(p.EGU0); - let led1 = OutputChannel::new(p.GPIOTE_CH0, led1, OutputChannelPolarity::Toggle); - let btn1 = InputChannel::new(p.GPIOTE_CH1, btn1, InputChannelPolarity::LoToHi); + let led1 = OutputChannel::new( + p.GPIOTE_CH0, + p.P0_13, + Level::High, + OutputDrive::Standard, + OutputChannelPolarity::Toggle, + ); + let btn1 = InputChannel::new(p.GPIOTE_CH1, p.P0_11, Pull::Up, InputChannelPolarity::LoToHi); let trigger0 = egu1.trigger(TriggerNumber::Trigger0); let trigger1 = egu1.trigger(TriggerNumber::Trigger1); diff --git a/examples/nrf52840/src/bin/gpiote_channel.rs b/examples/nrf52840/src/bin/gpiote_channel.rs index dcfe7723a..c7ddc1d8d 100644 --- a/examples/nrf52840/src/bin/gpiote_channel.rs +++ b/examples/nrf52840/src/bin/gpiote_channel.rs @@ -3,7 +3,7 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_nrf::gpio::{Input, Pull}; +use embassy_nrf::gpio::Pull; use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity}; use {defmt_rtt as _, panic_probe as _}; @@ -12,26 +12,10 @@ async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); info!("Starting!"); - let ch1 = InputChannel::new( - p.GPIOTE_CH0, - Input::new(p.P0_11, Pull::Up), - InputChannelPolarity::HiToLo, - ); - let ch2 = InputChannel::new( - p.GPIOTE_CH1, - Input::new(p.P0_12, Pull::Up), - InputChannelPolarity::LoToHi, - ); - let ch3 = InputChannel::new( - p.GPIOTE_CH2, - Input::new(p.P0_24, Pull::Up), - InputChannelPolarity::Toggle, - ); - let ch4 = InputChannel::new( - p.GPIOTE_CH3, - Input::new(p.P0_25, Pull::Up), - InputChannelPolarity::Toggle, - ); + let ch1 = InputChannel::new(p.GPIOTE_CH0, p.P0_11, Pull::Up, InputChannelPolarity::HiToLo); + let ch2 = InputChannel::new(p.GPIOTE_CH1, p.P0_12, Pull::Up, InputChannelPolarity::LoToHi); + let ch3 = InputChannel::new(p.GPIOTE_CH2, p.P0_24, Pull::Up, InputChannelPolarity::Toggle); + let ch4 = InputChannel::new(p.GPIOTE_CH3, p.P0_25, Pull::Up, InputChannelPolarity::Toggle); let button1 = async { loop { diff --git a/examples/nrf52840/src/bin/ppi.rs b/examples/nrf52840/src/bin/ppi.rs index 129ad06e7..177f6a06d 100644 --- a/examples/nrf52840/src/bin/ppi.rs +++ b/examples/nrf52840/src/bin/ppi.rs @@ -5,7 +5,7 @@ use core::future::pending; use defmt::info; use embassy_executor::Spawner; -use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; +use embassy_nrf::gpio::{Level, OutputDrive, Pull}; use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity}; use embassy_nrf::ppi::Ppi; use gpiote::{OutputChannel, OutputChannelPolarity}; @@ -16,36 +16,24 @@ async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); info!("Starting!"); - let button1 = InputChannel::new( - p.GPIOTE_CH0, - Input::new(p.P0_11, Pull::Up), - InputChannelPolarity::HiToLo, - ); - let button2 = InputChannel::new( - p.GPIOTE_CH1, - Input::new(p.P0_12, Pull::Up), - InputChannelPolarity::HiToLo, - ); - let button3 = InputChannel::new( - p.GPIOTE_CH2, - Input::new(p.P0_24, Pull::Up), - InputChannelPolarity::HiToLo, - ); - let button4 = InputChannel::new( - p.GPIOTE_CH3, - Input::new(p.P0_25, Pull::Up), - InputChannelPolarity::HiToLo, - ); + let button1 = InputChannel::new(p.GPIOTE_CH0, p.P0_11, Pull::Up, InputChannelPolarity::HiToLo); + let button2 = InputChannel::new(p.GPIOTE_CH1, p.P0_12, Pull::Up, InputChannelPolarity::HiToLo); + let button3 = InputChannel::new(p.GPIOTE_CH2, p.P0_24, Pull::Up, InputChannelPolarity::HiToLo); + let button4 = InputChannel::new(p.GPIOTE_CH3, p.P0_25, Pull::Up, InputChannelPolarity::HiToLo); let led1 = OutputChannel::new( p.GPIOTE_CH4, - Output::new(p.P0_13, Level::Low, OutputDrive::Standard), + p.P0_13, + Level::Low, + OutputDrive::Standard, OutputChannelPolarity::Toggle, ); let led2 = OutputChannel::new( p.GPIOTE_CH5, - Output::new(p.P0_14, Level::Low, OutputDrive::Standard), + p.P0_14, + Level::Low, + OutputDrive::Standard, OutputChannelPolarity::Toggle, ); diff --git a/examples/nrf52840/src/bin/pwm_sequence_ppi.rs b/examples/nrf52840/src/bin/pwm_sequence_ppi.rs index 60ea712b5..fff7decb2 100644 --- a/examples/nrf52840/src/bin/pwm_sequence_ppi.rs +++ b/examples/nrf52840/src/bin/pwm_sequence_ppi.rs @@ -5,7 +5,7 @@ use core::future::pending; use defmt::*; use embassy_executor::Spawner; -use embassy_nrf::gpio::{Input, Pull}; +use embassy_nrf::gpio::Pull; use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity}; use embassy_nrf::ppi::Ppi; use embassy_nrf::pwm::{Config, Prescaler, SequenceConfig, SequencePwm, SingleSequenceMode, SingleSequencer}; @@ -30,17 +30,9 @@ async fn main(_spawner: Spawner) { // pwm.stop() deconfigures pins, and then the task_start_seq0 task cant work // so its going to have to start running in order load the configuration - let button1 = InputChannel::new( - p.GPIOTE_CH0, - Input::new(p.P0_11, Pull::Up), - InputChannelPolarity::HiToLo, - ); + let button1 = InputChannel::new(p.GPIOTE_CH0, p.P0_11, Pull::Up, InputChannelPolarity::HiToLo); - let button2 = InputChannel::new( - p.GPIOTE_CH1, - Input::new(p.P0_12, Pull::Up), - InputChannelPolarity::HiToLo, - ); + let button2 = InputChannel::new(p.GPIOTE_CH1, p.P0_12, Pull::Up, InputChannelPolarity::HiToLo); // messing with the pwm tasks is ill advised // Times::Ininite and Times even are seq0, Times odd is seq1 diff --git a/examples/nrf5340/src/bin/gpiote_channel.rs b/examples/nrf5340/src/bin/gpiote_channel.rs index 23f6fca98..a085310ce 100644 --- a/examples/nrf5340/src/bin/gpiote_channel.rs +++ b/examples/nrf5340/src/bin/gpiote_channel.rs @@ -3,7 +3,7 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_nrf::gpio::{Input, Pull}; +use embassy_nrf::gpio::Pull; use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity}; use {defmt_rtt as _, panic_probe as _}; @@ -12,26 +12,10 @@ async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); info!("Starting!"); - let ch1 = InputChannel::new( - p.GPIOTE_CH0, - Input::new(p.P0_23, Pull::Up), - InputChannelPolarity::HiToLo, - ); - let ch2 = InputChannel::new( - p.GPIOTE_CH1, - Input::new(p.P0_24, Pull::Up), - InputChannelPolarity::LoToHi, - ); - let ch3 = InputChannel::new( - p.GPIOTE_CH2, - Input::new(p.P0_08, Pull::Up), - InputChannelPolarity::Toggle, - ); - let ch4 = InputChannel::new( - p.GPIOTE_CH3, - Input::new(p.P0_09, Pull::Up), - InputChannelPolarity::Toggle, - ); + let ch1 = InputChannel::new(p.GPIOTE_CH0, p.P0_23, Pull::Up, InputChannelPolarity::HiToLo); + let ch2 = InputChannel::new(p.GPIOTE_CH1, p.P0_24, Pull::Up, InputChannelPolarity::LoToHi); + let ch3 = InputChannel::new(p.GPIOTE_CH2, p.P0_08, Pull::Up, InputChannelPolarity::Toggle); + let ch4 = InputChannel::new(p.GPIOTE_CH3, p.P0_09, Pull::Up, InputChannelPolarity::Toggle); let button1 = async { loop { diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml index 541e79fcb..14a80efe7 100644 --- a/examples/nrf54l15/Cargo.toml +++ b/examples/nrf54l15/Cargo.toml @@ -6,10 +6,13 @@ license = "MIT OR Apache-2.0" publish = false [dependencies] +embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embedded-io = { version = "0.6.0", features = ["defmt-03"] } +embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } defmt = "1.0.1" defmt-rtt = "1.0.0" @@ -21,6 +24,8 @@ cortex-m-rt = "0.7.0" embedded-storage = "0.3.1" portable-atomic = "1" +static_cell = "2" + [profile.release] debug = 2 diff --git a/examples/nrf54l15/src/bin/buffered_uart.rs b/examples/nrf54l15/src/bin/buffered_uart.rs new file mode 100644 index 000000000..41fa1ca4e --- /dev/null +++ b/examples/nrf54l15/src/bin/buffered_uart.rs @@ -0,0 +1,49 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_nrf::buffered_uarte::{self, BufferedUarte}; +use embassy_nrf::{bind_interrupts, peripherals, uarte}; +use embedded_io_async::Write; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + SERIAL20 => buffered_uarte::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + let mut config = uarte::Config::default(); + config.parity = uarte::Parity::EXCLUDED; + config.baudrate = uarte::Baudrate::BAUD115200; + + let mut tx_buffer = [0u8; 4096]; + let mut rx_buffer = [0u8; 4096]; + + let mut u = BufferedUarte::new( + p.SERIAL20, + p.P1_12, + p.P1_13, + Irqs, + config, + &mut rx_buffer, + &mut tx_buffer, + ); + + info!("uarte initialized!"); + + unwrap!(u.write_all(b"Hello!\r\n").await); + info!("wrote hello in uart!"); + + loop { + info!("reading..."); + let buf = unwrap!(u.fill_buf().await); + info!("read done, got {}", buf); + + // Read bytes have to be explicitly consumed, otherwise fill_buf() will return them again + let n = buf.len(); + u.consume(n); + } +} diff --git a/examples/nrf54l15/src/bin/gpiote_channel.rs b/examples/nrf54l15/src/bin/gpiote_channel.rs new file mode 100644 index 000000000..3fa0972a7 --- /dev/null +++ b/examples/nrf54l15/src/bin/gpiote_channel.rs @@ -0,0 +1,49 @@ +#![no_std] +#![no_main] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_nrf::gpio::Pull; +use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + info!("Starting!"); + + let ch1 = InputChannel::new(p.GPIOTE_CH0, p.P1_13, Pull::Up, InputChannelPolarity::HiToLo); + let ch2 = InputChannel::new(p.GPIOTE_CH1, p.P1_09, Pull::Up, InputChannelPolarity::LoToHi); + let ch3 = InputChannel::new(p.GPIOTE_CH2, p.P1_08, Pull::Up, InputChannelPolarity::Toggle); + let ch4 = InputChannel::new(p.GPIOTE_CH8, p.P0_04, Pull::Up, InputChannelPolarity::Toggle); + + let button1 = async { + loop { + ch1.wait().await; + info!("Button 1 pressed") + } + }; + + let button2 = async { + loop { + ch2.wait().await; + info!("Button 2 released") + } + }; + + let button3 = async { + loop { + ch3.wait().await; + info!("Button 3 toggled") + } + }; + + let button4 = async { + loop { + ch4.wait().await; + info!("Button 4 toggled") + } + }; + + embassy_futures::join::join4(button1, button2, button3, button4).await; +} diff --git a/examples/nrf54l15/src/bin/gpiote_port.rs b/examples/nrf54l15/src/bin/gpiote_port.rs new file mode 100644 index 000000000..620cb2435 --- /dev/null +++ b/examples/nrf54l15/src/bin/gpiote_port.rs @@ -0,0 +1,33 @@ +#![no_std] +#![no_main] + +use defmt::{info, unwrap}; +use embassy_executor::Spawner; +use embassy_nrf::gpio::{Input, Pull}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::task(pool_size = 4)] +async fn button_task(n: usize, mut pin: Input<'static>) { + loop { + pin.wait_for_low().await; + info!("Button {:?} pressed!", n); + pin.wait_for_high().await; + info!("Button {:?} released!", n); + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + info!("Starting!"); + + let btn1 = Input::new(p.P1_13, Pull::Up); + let btn2 = Input::new(p.P1_09, Pull::Up); + let btn3 = Input::new(p.P1_08, Pull::Up); + let btn4 = Input::new(p.P0_04, Pull::Up); + + spawner.spawn(unwrap!(button_task(1, btn1))); + spawner.spawn(unwrap!(button_task(2, btn2))); + spawner.spawn(unwrap!(button_task(3, btn3))); + spawner.spawn(unwrap!(button_task(4, btn4))); +} diff --git a/examples/nrf54l15/src/bin/pwm.rs b/examples/nrf54l15/src/bin/pwm.rs new file mode 100644 index 000000000..b438978f1 --- /dev/null +++ b/examples/nrf54l15/src/bin/pwm.rs @@ -0,0 +1,86 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +// for i in range(1024): print(int((math.sin(i/512*math.pi)*0.4+0.5)**2*32767), ', ', end='') +static DUTY: [u16; 1024] = [ + 8191, 8272, 8353, 8434, 8516, 8598, 8681, 8764, 8847, 8931, 9015, 9099, 9184, 9269, 9354, 9440, 9526, 9613, 9700, + 9787, 9874, 9962, 10050, 10139, 10227, 10316, 10406, 10495, 10585, 10675, 10766, 10857, 10948, 11039, 11131, 11223, + 11315, 11407, 11500, 11592, 11685, 11779, 11872, 11966, 12060, 12154, 12248, 12343, 12438, 12533, 12628, 12723, + 12818, 12914, 13010, 13106, 13202, 13298, 13394, 13491, 13587, 13684, 13781, 13878, 13975, 14072, 14169, 14266, + 14364, 14461, 14558, 14656, 14754, 14851, 14949, 15046, 15144, 15242, 15339, 15437, 15535, 15632, 15730, 15828, + 15925, 16023, 16120, 16218, 16315, 16412, 16510, 16607, 16704, 16801, 16898, 16995, 17091, 17188, 17284, 17380, + 17477, 17572, 17668, 17764, 17859, 17955, 18050, 18145, 18239, 18334, 18428, 18522, 18616, 18710, 18803, 18896, + 18989, 19082, 19174, 19266, 19358, 19449, 19540, 19631, 19722, 19812, 19902, 19991, 20081, 20169, 20258, 20346, + 20434, 20521, 20608, 20695, 20781, 20867, 20952, 21037, 21122, 21206, 21290, 21373, 21456, 21538, 21620, 21701, + 21782, 21863, 21943, 22022, 22101, 22179, 22257, 22335, 22412, 22488, 22564, 22639, 22714, 22788, 22861, 22934, + 23007, 23079, 23150, 23220, 23290, 23360, 23429, 23497, 23564, 23631, 23698, 23763, 23828, 23892, 23956, 24019, + 24081, 24143, 24204, 24264, 24324, 24383, 24441, 24499, 24555, 24611, 24667, 24721, 24775, 24828, 24881, 24933, + 24983, 25034, 25083, 25132, 25180, 25227, 25273, 25319, 25363, 25407, 25451, 25493, 25535, 25575, 25615, 25655, + 25693, 25731, 25767, 25803, 25838, 25873, 25906, 25939, 25971, 26002, 26032, 26061, 26089, 26117, 26144, 26170, + 26195, 26219, 26242, 26264, 26286, 26307, 26327, 26346, 26364, 26381, 26397, 26413, 26427, 26441, 26454, 26466, + 26477, 26487, 26496, 26505, 26512, 26519, 26525, 26530, 26534, 26537, 26539, 26540, 26541, 26540, 26539, 26537, + 26534, 26530, 26525, 26519, 26512, 26505, 26496, 26487, 26477, 26466, 26454, 26441, 26427, 26413, 26397, 26381, + 26364, 26346, 26327, 26307, 26286, 26264, 26242, 26219, 26195, 26170, 26144, 26117, 26089, 26061, 26032, 26002, + 25971, 25939, 25906, 25873, 25838, 25803, 25767, 25731, 25693, 25655, 25615, 25575, 25535, 25493, 25451, 25407, + 25363, 25319, 25273, 25227, 25180, 25132, 25083, 25034, 24983, 24933, 24881, 24828, 24775, 24721, 24667, 24611, + 24555, 24499, 24441, 24383, 24324, 24264, 24204, 24143, 24081, 24019, 23956, 23892, 23828, 23763, 23698, 23631, + 23564, 23497, 23429, 23360, 23290, 23220, 23150, 23079, 23007, 22934, 22861, 22788, 22714, 22639, 22564, 22488, + 22412, 22335, 22257, 22179, 22101, 22022, 21943, 21863, 21782, 21701, 21620, 21538, 21456, 21373, 21290, 21206, + 21122, 21037, 20952, 20867, 20781, 20695, 20608, 20521, 20434, 20346, 20258, 20169, 20081, 19991, 19902, 19812, + 19722, 19631, 19540, 19449, 19358, 19266, 19174, 19082, 18989, 18896, 18803, 18710, 18616, 18522, 18428, 18334, + 18239, 18145, 18050, 17955, 17859, 17764, 17668, 17572, 17477, 17380, 17284, 17188, 17091, 16995, 16898, 16801, + 16704, 16607, 16510, 16412, 16315, 16218, 16120, 16023, 15925, 15828, 15730, 15632, 15535, 15437, 15339, 15242, + 15144, 15046, 14949, 14851, 14754, 14656, 14558, 14461, 14364, 14266, 14169, 14072, 13975, 13878, 13781, 13684, + 13587, 13491, 13394, 13298, 13202, 13106, 13010, 12914, 12818, 12723, 12628, 12533, 12438, 12343, 12248, 12154, + 12060, 11966, 11872, 11779, 11685, 11592, 11500, 11407, 11315, 11223, 11131, 11039, 10948, 10857, 10766, 10675, + 10585, 10495, 10406, 10316, 10227, 10139, 10050, 9962, 9874, 9787, 9700, 9613, 9526, 9440, 9354, 9269, 9184, 9099, + 9015, 8931, 8847, 8764, 8681, 8598, 8516, 8434, 8353, 8272, 8191, 8111, 8031, 7952, 7873, 7794, 7716, 7638, 7561, + 7484, 7407, 7331, 7255, 7180, 7105, 7031, 6957, 6883, 6810, 6738, 6665, 6594, 6522, 6451, 6381, 6311, 6241, 6172, + 6104, 6036, 5968, 5901, 5834, 5767, 5702, 5636, 5571, 5507, 5443, 5379, 5316, 5253, 5191, 5130, 5068, 5008, 4947, + 4888, 4828, 4769, 4711, 4653, 4596, 4539, 4482, 4426, 4371, 4316, 4261, 4207, 4153, 4100, 4047, 3995, 3943, 3892, + 3841, 3791, 3741, 3691, 3642, 3594, 3546, 3498, 3451, 3404, 3358, 3312, 3267, 3222, 3178, 3134, 3090, 3047, 3005, + 2962, 2921, 2879, 2839, 2798, 2758, 2719, 2680, 2641, 2603, 2565, 2528, 2491, 2454, 2418, 2382, 2347, 2312, 2278, + 2244, 2210, 2177, 2144, 2112, 2080, 2048, 2017, 1986, 1956, 1926, 1896, 1867, 1838, 1810, 1781, 1754, 1726, 1699, + 1673, 1646, 1620, 1595, 1570, 1545, 1520, 1496, 1472, 1449, 1426, 1403, 1380, 1358, 1336, 1315, 1294, 1273, 1252, + 1232, 1212, 1192, 1173, 1154, 1135, 1117, 1099, 1081, 1063, 1046, 1029, 1012, 996, 980, 964, 948, 933, 918, 903, + 888, 874, 860, 846, 833, 819, 806, 793, 781, 768, 756, 744, 733, 721, 710, 699, 688, 677, 667, 657, 647, 637, 627, + 618, 609, 599, 591, 582, 574, 565, 557, 549, 541, 534, 526, 519, 512, 505, 498, 492, 485, 479, 473, 467, 461, 455, + 450, 444, 439, 434, 429, 424, 419, 415, 410, 406, 402, 398, 394, 390, 386, 383, 379, 376, 373, 370, 367, 364, 361, + 359, 356, 354, 351, 349, 347, 345, 343, 342, 340, 338, 337, 336, 334, 333, 332, 331, 330, 330, 329, 328, 328, 328, + 327, 327, 327, 327, 327, 328, 328, 328, 329, 330, 330, 331, 332, 333, 334, 336, 337, 338, 340, 342, 343, 345, 347, + 349, 351, 354, 356, 359, 361, 364, 367, 370, 373, 376, 379, 383, 386, 390, 394, 398, 402, 406, 410, 415, 419, 424, + 429, 434, 439, 444, 450, 455, 461, 467, 473, 479, 485, 492, 498, 505, 512, 519, 526, 534, 541, 549, 557, 565, 574, + 582, 591, 599, 609, 618, 627, 637, 647, 657, 667, 677, 688, 699, 710, 721, 733, 744, 756, 768, 781, 793, 806, 819, + 833, 846, 860, 874, 888, 903, 918, 933, 948, 964, 980, 996, 1012, 1029, 1046, 1063, 1081, 1099, 1117, 1135, 1154, + 1173, 1192, 1212, 1232, 1252, 1273, 1294, 1315, 1336, 1358, 1380, 1403, 1426, 1449, 1472, 1496, 1520, 1545, 1570, + 1595, 1620, 1646, 1673, 1699, 1726, 1754, 1781, 1810, 1838, 1867, 1896, 1926, 1956, 1986, 2017, 2048, 2080, 2112, + 2144, 2177, 2210, 2244, 2278, 2312, 2347, 2382, 2418, 2454, 2491, 2528, 2565, 2603, 2641, 2680, 2719, 2758, 2798, + 2839, 2879, 2921, 2962, 3005, 3047, 3090, 3134, 3178, 3222, 3267, 3312, 3358, 3404, 3451, 3498, 3546, 3594, 3642, + 3691, 3741, 3791, 3841, 3892, 3943, 3995, 4047, 4100, 4153, 4207, 4261, 4316, 4371, 4426, 4482, 4539, 4596, 4653, + 4711, 4769, 4828, 4888, 4947, 5008, 5068, 5130, 5191, 5253, 5316, 5379, 5443, 5507, 5571, 5636, 5702, 5767, 5834, + 5901, 5968, 6036, 6104, 6172, 6241, 6311, 6381, 6451, 6522, 6594, 6665, 6738, 6810, 6883, 6957, 7031, 7105, 7180, + 7255, 7331, 7407, 7484, 7561, 7638, 7716, 7794, 7873, 7952, 8031, 8111, +]; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + let mut pwm = SimplePwm::new_2ch(p.PWM20, p.P1_10, p.P1_14, &Default::default()); + pwm.set_prescaler(Prescaler::Div1); + pwm.set_max_duty(32767); + info!("pwm initialized!"); + + let mut i = 0; + loop { + i += 1; + pwm.set_duty(0, DutyCycle::normal(DUTY[i % 1024])); + pwm.set_duty(1, DutyCycle::normal(DUTY[(i + 512) % 1024])); + Timer::after_millis(3).await; + } +} diff --git a/examples/nrf54l15/src/bin/saadc.rs b/examples/nrf54l15/src/bin/saadc.rs new file mode 100644 index 000000000..567177894 --- /dev/null +++ b/examples/nrf54l15/src/bin/saadc.rs @@ -0,0 +1,28 @@ +#![no_std] +#![no_main] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_nrf::saadc::{ChannelConfig, Config, Saadc}; +use embassy_nrf::{bind_interrupts, saadc}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + SAADC => saadc::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_p: Spawner) { + let mut p = embassy_nrf::init(Default::default()); + let config = Config::default(); + let channel_config = ChannelConfig::single_ended(p.P1_04.reborrow()); + let mut saadc = Saadc::new(p.SAADC, Irqs, config, [channel_config]); + + loop { + let mut buf = [0; 1]; + saadc.sample(&mut buf).await; + info!("sample: {=i16}", &buf[0]); + Timer::after_millis(100).await; + } +} diff --git a/examples/nrf54l15/src/bin/spim.rs b/examples/nrf54l15/src/bin/spim.rs new file mode 100644 index 000000000..0520bf08c --- /dev/null +++ b/examples/nrf54l15/src/bin/spim.rs @@ -0,0 +1,72 @@ +#![no_std] +#![no_main] + +use defmt::{info, unwrap}; +use embassy_executor::Spawner; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_nrf::{bind_interrupts, peripherals, spim}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + SERIAL00 => spim::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + info!("running!"); + + let mut config = spim::Config::default(); + config.frequency = spim::Frequency::M16; + + let mut spim = spim::Spim::new(p.SERIAL00, Irqs, p.P0_01, p.P0_00, p.P0_02, config); + + // Example on how to talk to an ADXL343 + + let mut ncs = Output::new(p.P0_03, Level::High, OutputDrive::Standard); + + // Example on how to talk to an ENC28J60 chip + + // softreset + cortex_m::asm::delay(10); + ncs.set_low(); + cortex_m::asm::delay(5); + let tx = [0xFF]; + unwrap!(spim.transfer(&mut [], &tx).await); + cortex_m::asm::delay(10); + ncs.set_high(); + + cortex_m::asm::delay(100000); + + let mut rx = [0; 2]; + + // read ESTAT + cortex_m::asm::delay(5000); + ncs.set_low(); + cortex_m::asm::delay(5000); + let tx = [0b000_11101, 0]; + unwrap!(spim.transfer(&mut rx, &tx).await); + cortex_m::asm::delay(5000); + ncs.set_high(); + info!("estat: {=[?]}", rx); + + // Switch to bank 3 + cortex_m::asm::delay(10); + ncs.set_low(); + cortex_m::asm::delay(5); + let tx = [0b100_11111, 0b11]; + unwrap!(spim.transfer(&mut rx, &tx).await); + cortex_m::asm::delay(10); + ncs.set_high(); + + // read EREVID + cortex_m::asm::delay(10); + ncs.set_low(); + cortex_m::asm::delay(5); + let tx = [0b000_10010, 0]; + unwrap!(spim.transfer(&mut rx, &tx).await); + cortex_m::asm::delay(10); + ncs.set_high(); + + info!("erevid: {=[?]}", rx); +} diff --git a/examples/nrf54l15/src/bin/twim.rs b/examples/nrf54l15/src/bin/twim.rs new file mode 100644 index 000000000..53b85034e --- /dev/null +++ b/examples/nrf54l15/src/bin/twim.rs @@ -0,0 +1,37 @@ +//! Example on how to read a 24C/24LC i2c eeprom. +//! +//! Connect SDA to P0.03, SCL to P0.04 + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_nrf::twim::{self, Twim}; +use embassy_nrf::{bind_interrupts, peripherals}; +use static_cell::ConstStaticCell; +use {defmt_rtt as _, panic_probe as _}; + +const ADDRESS: u8 = 0x18; +const WHOAMI: u8 = 0x0F; + +bind_interrupts!(struct Irqs { + SERIAL20 => twim::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + info!("Initializing TWI..."); + let config = twim::Config::default(); + static RAM_BUFFER: ConstStaticCell<[u8; 16]> = ConstStaticCell::new([0; 16]); + let mut twi = Twim::new(p.SERIAL20, Irqs, p.P1_13, p.P1_12, config, RAM_BUFFER.take()); + + info!("Reading..."); + + let mut data = [0u8; 1]; + match twi.write_read(ADDRESS, &[WHOAMI], &mut data).await { + Ok(()) => info!("Whoami: {}", data[0]), + Err(e) => error!("I2c Error: {:?}", e), + } +} diff --git a/examples/nrf54l15/src/bin/twis.rs b/examples/nrf54l15/src/bin/twis.rs new file mode 100644 index 000000000..34c04aee3 --- /dev/null +++ b/examples/nrf54l15/src/bin/twis.rs @@ -0,0 +1,47 @@ +//! TWIS example + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_nrf::twis::{self, Command, Twis}; +use embassy_nrf::{bind_interrupts, peripherals}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + SERIAL20 => twis::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + + let mut config = twis::Config::default(); + config.address0 = 0x55; // Set i2c address + let mut i2c = Twis::new(p.SERIAL20, Irqs, p.P0_03, p.P0_04, config); + + info!("Listening..."); + loop { + let response = [1, 2, 3, 4, 5, 6, 7, 8]; + // This buffer is used if the i2c master performs a Write or WriteRead + let mut buf = [0u8; 16]; + match i2c.listen(&mut buf).await { + Ok(Command::Read) => { + info!("Got READ command. Respond with data:\n{:?}\n", response); + if let Err(e) = i2c.respond_to_read(&response).await { + error!("{:?}", e); + } + } + Ok(Command::Write(n)) => info!("Got WRITE command with data:\n{:?}\n", buf[..n]), + Ok(Command::WriteRead(n)) => { + info!("Got WRITE/READ command with data:\n{:?}", buf[..n]); + info!("Respond with data:\n{:?}\n", response); + if let Err(e) = i2c.respond_to_read(&response).await { + error!("{:?}", e); + } + } + Err(e) => error!("{:?}", e), + } + } +} diff --git a/examples/nrf54l15/src/bin/uart.rs b/examples/nrf54l15/src/bin/uart.rs new file mode 100644 index 000000000..cc6528a6f --- /dev/null +++ b/examples/nrf54l15/src/bin/uart.rs @@ -0,0 +1,37 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_nrf::{bind_interrupts, peripherals, uarte}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + SERIAL20 => uarte::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + let mut config = uarte::Config::default(); + config.parity = uarte::Parity::EXCLUDED; + config.baudrate = uarte::Baudrate::BAUD115200; + + let mut uart = uarte::Uarte::new(p.SERIAL20, p.P1_12, p.P1_13, Irqs, config); + + info!("uarte initialized!"); + + // Message must be in SRAM + let mut buf = [0; 8]; + buf.copy_from_slice(b"Hello!\r\n"); + + unwrap!(uart.write(&buf).await); + info!("wrote hello in uart!"); + + loop { + info!("reading..."); + unwrap!(uart.read(&mut buf).await); + info!("writing..."); + unwrap!(uart.write(&buf).await); + } +} -- cgit From e64fc05a91cc78f54c7a2440324d21dee54c0b04 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 28 Oct 2025 13:36:49 +0100 Subject: chore: make it clear which gpiotec for a channel --- examples/nrf54l15/src/bin/gpiote_channel.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/nrf54l15/src/bin/gpiote_channel.rs b/examples/nrf54l15/src/bin/gpiote_channel.rs index 3fa0972a7..6333250ba 100644 --- a/examples/nrf54l15/src/bin/gpiote_channel.rs +++ b/examples/nrf54l15/src/bin/gpiote_channel.rs @@ -12,10 +12,10 @@ async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); info!("Starting!"); - let ch1 = InputChannel::new(p.GPIOTE_CH0, p.P1_13, Pull::Up, InputChannelPolarity::HiToLo); - let ch2 = InputChannel::new(p.GPIOTE_CH1, p.P1_09, Pull::Up, InputChannelPolarity::LoToHi); - let ch3 = InputChannel::new(p.GPIOTE_CH2, p.P1_08, Pull::Up, InputChannelPolarity::Toggle); - let ch4 = InputChannel::new(p.GPIOTE_CH8, p.P0_04, Pull::Up, InputChannelPolarity::Toggle); + let ch1 = InputChannel::new(p.GPIOTE20_CH0, p.P1_13, Pull::Up, InputChannelPolarity::HiToLo); + let ch2 = InputChannel::new(p.GPIOTE20_CH1, p.P1_09, Pull::Up, InputChannelPolarity::LoToHi); + let ch3 = InputChannel::new(p.GPIOTE20_CH2, p.P1_08, Pull::Up, InputChannelPolarity::Toggle); + let ch4 = InputChannel::new(p.GPIOTE30_CH0, p.P0_04, Pull::Up, InputChannelPolarity::Toggle); let button1 = async { loop { -- cgit From 83deef3672c651ac86e7ad497eccc52119b3a27f Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 28 Oct 2025 14:38:02 +0100 Subject: chore: simplify spim example to be testable on devkit --- examples/nrf54l15/src/bin/spim.rs | 70 ++++++++------------------------------- 1 file changed, 14 insertions(+), 56 deletions(-) (limited to 'examples') diff --git a/examples/nrf54l15/src/bin/spim.rs b/examples/nrf54l15/src/bin/spim.rs index 0520bf08c..3f5980647 100644 --- a/examples/nrf54l15/src/bin/spim.rs +++ b/examples/nrf54l15/src/bin/spim.rs @@ -1,9 +1,7 @@ #![no_std] #![no_main] -use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_nrf::gpio::{Level, Output, OutputDrive}; use embassy_nrf::{bind_interrupts, peripherals, spim}; use {defmt_rtt as _, panic_probe as _}; @@ -14,59 +12,19 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); - info!("running!"); - let mut config = spim::Config::default(); - config.frequency = spim::Frequency::M16; - - let mut spim = spim::Spim::new(p.SERIAL00, Irqs, p.P0_01, p.P0_00, p.P0_02, config); - - // Example on how to talk to an ADXL343 - - let mut ncs = Output::new(p.P0_03, Level::High, OutputDrive::Standard); - - // Example on how to talk to an ENC28J60 chip - - // softreset - cortex_m::asm::delay(10); - ncs.set_low(); - cortex_m::asm::delay(5); - let tx = [0xFF]; - unwrap!(spim.transfer(&mut [], &tx).await); - cortex_m::asm::delay(10); - ncs.set_high(); - - cortex_m::asm::delay(100000); - - let mut rx = [0; 2]; - - // read ESTAT - cortex_m::asm::delay(5000); - ncs.set_low(); - cortex_m::asm::delay(5000); - let tx = [0b000_11101, 0]; - unwrap!(spim.transfer(&mut rx, &tx).await); - cortex_m::asm::delay(5000); - ncs.set_high(); - info!("estat: {=[?]}", rx); - - // Switch to bank 3 - cortex_m::asm::delay(10); - ncs.set_low(); - cortex_m::asm::delay(5); - let tx = [0b100_11111, 0b11]; - unwrap!(spim.transfer(&mut rx, &tx).await); - cortex_m::asm::delay(10); - ncs.set_high(); - - // read EREVID - cortex_m::asm::delay(10); - ncs.set_low(); - cortex_m::asm::delay(5); - let tx = [0b000_10010, 0]; - unwrap!(spim.transfer(&mut rx, &tx).await); - cortex_m::asm::delay(10); - ncs.set_high(); - - info!("erevid: {=[?]}", rx); + config.frequency = spim::Frequency::M32; + let mut spim = spim::Spim::new(p.SERIAL00, Irqs, p.P2_05, p.P2_09, p.P2_08, config.clone()); + let data = [ + 0x42, 0x43, 0x44, 0x45, 0x66, 0x12, 0x23, 0x34, 0x45, 0x19, 0x91, 0xaa, 0xff, 0xa5, 0x5a, 0x77, + ]; + let mut buf = [0u8; 16]; + + buf.fill(0); + spim.blocking_transfer(&mut buf, &data).unwrap(); + assert_eq!(data, buf); + + buf.fill(0); + spim.transfer(&mut buf, &data).await.unwrap(); + assert_eq!(data, buf); } -- cgit From 98de11e5e3ae437676198a105ffab8c0f4977513 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 29 Oct 2025 17:49:55 +0100 Subject: net-esp-hosted: add Interface trait. --- examples/nrf52840/src/bin/wifi_esp_hosted.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'examples') diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs index 07752ffc4..2f9c06b56 100644 --- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs +++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs @@ -27,14 +27,12 @@ bind_interrupts!(struct Irqs { async fn wifi_task( runner: hosted::Runner< 'static, - ExclusiveDevice, Output<'static>, Delay>, - Input<'static>, + hosted::SpiInterface, Output<'static>, Delay>, Input<'static>>, Output<'static>, >, ) -> ! { runner.run().await } - #[embassy_executor::task] async fn net_task(mut runner: embassy_net::Runner<'static, hosted::NetDriver<'static>>) -> ! { runner.run().await @@ -60,15 +58,11 @@ async fn main(spawner: Spawner) { let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config); let spi = ExclusiveDevice::new(spi, cs, Delay); + let iface = hosted::SpiInterface::new(spi, handshake, ready); + static ESP_STATE: StaticCell = StaticCell::new(); - let (device, mut control, runner) = embassy_net_esp_hosted::new( - ESP_STATE.init(embassy_net_esp_hosted::State::new()), - spi, - handshake, - ready, - reset, - ) - .await; + let (device, mut control, runner) = + embassy_net_esp_hosted::new(ESP_STATE.init(embassy_net_esp_hosted::State::new()), iface, reset).await; spawner.spawn(unwrap!(wifi_task(runner))); -- cgit From 65438769024b657f98da20646beb10e7e5a1b960 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 30 Oct 2025 14:37:10 -0500 Subject: rustfmt and update --- examples/stm32f4/src/bin/i2c_slave_async.rs | 15 ++++++++++++--- examples/stm32f4/src/bin/i2c_slave_blocking.rs | 16 +++++++++++++--- 2 files changed, 25 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/stm32f4/src/bin/i2c_slave_async.rs b/examples/stm32f4/src/bin/i2c_slave_async.rs index db4a805b6..5065bcdd8 100644 --- a/examples/stm32f4/src/bin/i2c_slave_async.rs +++ b/examples/stm32f4/src/bin/i2c_slave_async.rs @@ -49,7 +49,7 @@ async fn main(spawner: Spawner) { let slave_config = SlaveAddrConfig::basic(I2C_SLAVE_ADDR); let i2c_slave = i2c_master.into_slave_multimaster(slave_config); - spawner.spawn(i2c_slave_task(i2c_slave)).unwrap(); + spawner.spawn(i2c_slave_task(i2c_slave).unwrap()); } #[embassy_executor::task] @@ -73,8 +73,17 @@ pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Asy match i2c_slave.respond_to_write(&mut *data_buffer).await { Ok(_) => { - info!("I2C: Data received - Buffer now contains: 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}", - data_buffer[0], data_buffer[1], data_buffer[2], data_buffer[3], data_buffer[4], data_buffer[5], data_buffer[6], data_buffer[7]); + info!( + "I2C: Data received - Buffer now contains: 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}", + data_buffer[0], + data_buffer[1], + data_buffer[2], + data_buffer[3], + data_buffer[4], + data_buffer[5], + data_buffer[6], + data_buffer[7] + ); } Err(e) => { error!("I2C: Write error: {}", format_i2c_error(&e)); diff --git a/examples/stm32f4/src/bin/i2c_slave_blocking.rs b/examples/stm32f4/src/bin/i2c_slave_blocking.rs index a62087a29..ee06d4ac4 100644 --- a/examples/stm32f4/src/bin/i2c_slave_blocking.rs +++ b/examples/stm32f4/src/bin/i2c_slave_blocking.rs @@ -47,7 +47,7 @@ async fn main(spawner: Spawner) { let slave_config = SlaveAddrConfig::basic(I2C_SLAVE_ADDR); let i2c_slave = i2c_master.into_slave_multimaster(slave_config); - spawner.spawn(i2c_slave_task(i2c_slave)).unwrap(); + spawner.spawn(i2c_slave_task(i2c_slave).unwrap()); } #[embassy_executor::task] @@ -70,8 +70,18 @@ pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Blo match i2c_slave.blocking_respond_to_write(&mut *data_buffer) { Ok(bytes_received) => { - info!("I2C: Received {} bytes - Buffer now contains: 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}", - bytes_received, data_buffer[0], data_buffer[1], data_buffer[2], data_buffer[3], data_buffer[4], data_buffer[5], data_buffer[6], data_buffer[7]); + info!( + "I2C: Received {} bytes - Buffer now contains: 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}", + bytes_received, + data_buffer[0], + data_buffer[1], + data_buffer[2], + data_buffer[3], + data_buffer[4], + data_buffer[5], + data_buffer[6], + data_buffer[7] + ); } Err(e) => { error!("I2C: Write error: {}", format_i2c_error(&e)); -- cgit From 719c2bbbb89c0121bbd2b62f9aeb98327e583d2b Mon Sep 17 00:00:00 2001 From: Michael Turner Date: Sun, 2 Nov 2025 14:10:02 -0800 Subject: Correct the temperature reading to preserve the sign bits --- examples/rp/src/bin/pio_onewire.rs | 2 +- examples/rp/src/bin/pio_onewire_parasite.rs | 2 +- examples/rp235x/src/bin/pio_onewire.rs | 2 +- examples/rp235x/src/bin/pio_onewire_parasite.rs | 2 +- examples/stm32g0/src/bin/onewire_ds18b20.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/rp/src/bin/pio_onewire.rs b/examples/rp/src/bin/pio_onewire.rs index 102f13c45..6432edb8a 100644 --- a/examples/rp/src/bin/pio_onewire.rs +++ b/examples/rp/src/bin/pio_onewire.rs @@ -61,7 +61,7 @@ async fn main(_spawner: Spawner) { let mut data = [0; 9]; onewire.read_bytes(&mut data).await; if crc8(&data) == 0 { - let temp = ((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.; + let temp = ((data[1] as i16) << 8 | data[0] as i16) as f32 / 16.; info!("Read device {:x}: {} deg C", device, temp); } else { warn!("Reading device {:x} failed", device); diff --git a/examples/rp/src/bin/pio_onewire_parasite.rs b/examples/rp/src/bin/pio_onewire_parasite.rs index fd076dee0..78fb94b18 100644 --- a/examples/rp/src/bin/pio_onewire_parasite.rs +++ b/examples/rp/src/bin/pio_onewire_parasite.rs @@ -63,7 +63,7 @@ async fn main(_spawner: Spawner) { let mut data = [0; 9]; onewire.read_bytes(&mut data).await; if crc8(&data) == 0 { - let temp = ((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.; + let temp = ((data[1] as i16) << 8 | data[0] as i16) as f32 / 16.; info!("Read device {:x}: {} deg C", device, temp); } else { warn!("Reading device {:x} failed. {:02x}", device, data); diff --git a/examples/rp235x/src/bin/pio_onewire.rs b/examples/rp235x/src/bin/pio_onewire.rs index 102f13c45..6432edb8a 100644 --- a/examples/rp235x/src/bin/pio_onewire.rs +++ b/examples/rp235x/src/bin/pio_onewire.rs @@ -61,7 +61,7 @@ async fn main(_spawner: Spawner) { let mut data = [0; 9]; onewire.read_bytes(&mut data).await; if crc8(&data) == 0 { - let temp = ((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.; + let temp = ((data[1] as i16) << 8 | data[0] as i16) as f32 / 16.; info!("Read device {:x}: {} deg C", device, temp); } else { warn!("Reading device {:x} failed", device); diff --git a/examples/rp235x/src/bin/pio_onewire_parasite.rs b/examples/rp235x/src/bin/pio_onewire_parasite.rs index fd076dee0..78fb94b18 100644 --- a/examples/rp235x/src/bin/pio_onewire_parasite.rs +++ b/examples/rp235x/src/bin/pio_onewire_parasite.rs @@ -63,7 +63,7 @@ async fn main(_spawner: Spawner) { let mut data = [0; 9]; onewire.read_bytes(&mut data).await; if crc8(&data) == 0 { - let temp = ((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.; + let temp = ((data[1] as i16) << 8 | data[0] as i16) as f32 / 16.; info!("Read device {:x}: {} deg C", device, temp); } else { warn!("Reading device {:x} failed. {:02x}", device, data); diff --git a/examples/stm32g0/src/bin/onewire_ds18b20.rs b/examples/stm32g0/src/bin/onewire_ds18b20.rs index 62f8711a6..43ecca8c4 100644 --- a/examples/stm32g0/src/bin/onewire_ds18b20.rs +++ b/examples/stm32g0/src/bin/onewire_ds18b20.rs @@ -267,7 +267,7 @@ where } match Self::crc8(&data) == 0 { - true => Ok(((data[1] as u16) << 8 | data[0] as u16) as f32 / 16.), + true => Ok(((data[1] as i16) << 8 | data[0] as i16) as f32 / 16.), false => Err(()), } } -- cgit From d25b5ce3bec44f4a023403a8b479e034d8386275 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 3 Nov 2025 13:02:08 -0600 Subject: low_power: update api to allow reconfig --- examples/stm32h5/src/bin/stop.rs | 2 -- examples/stm32l5/src/bin/stop.rs | 2 -- 2 files changed, 4 deletions(-) (limited to 'examples') diff --git a/examples/stm32h5/src/bin/stop.rs b/examples/stm32h5/src/bin/stop.rs index 3c4f49f64..29a735ed2 100644 --- a/examples/stm32h5/src/bin/stop.rs +++ b/examples/stm32h5/src/bin/stop.rs @@ -39,8 +39,6 @@ async fn async_main(spawner: Spawner) { // give the RTC to the executor... let rtc = Rtc::new(p.RTC, RtcConfig::default()); - static RTC: StaticCell = StaticCell::new(); - let rtc = RTC.init(rtc); embassy_stm32::low_power::stop_with_rtc(rtc); spawner.spawn(unwrap!(blinky(p.PB4.into()))); diff --git a/examples/stm32l5/src/bin/stop.rs b/examples/stm32l5/src/bin/stop.rs index c34053190..fd2aca372 100644 --- a/examples/stm32l5/src/bin/stop.rs +++ b/examples/stm32l5/src/bin/stop.rs @@ -30,8 +30,6 @@ async fn async_main(spawner: Spawner) { // give the RTC to the executor... let rtc = Rtc::new(p.RTC, RtcConfig::default()); - static RTC: StaticCell = StaticCell::new(); - let rtc = RTC.init(rtc); embassy_stm32::low_power::stop_with_rtc(rtc); spawner.spawn(unwrap!(blinky(p.PC7.into()))); -- cgit From 5043f1483e12ce5dbe7a394d5a87c657ff203625 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 3 Nov 2025 13:12:12 -0600 Subject: rustfmt --- examples/stm32h5/src/bin/stop.rs | 1 - examples/stm32l5/src/bin/stop.rs | 1 - 2 files changed, 2 deletions(-) (limited to 'examples') diff --git a/examples/stm32h5/src/bin/stop.rs b/examples/stm32h5/src/bin/stop.rs index 29a735ed2..2026d8f99 100644 --- a/examples/stm32h5/src/bin/stop.rs +++ b/examples/stm32h5/src/bin/stop.rs @@ -12,7 +12,6 @@ use embassy_stm32::rcc::{HSIPrescaler, LsConfig}; use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::{Config, Peri}; use embassy_time::Timer; -use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[cortex_m_rt::entry] diff --git a/examples/stm32l5/src/bin/stop.rs b/examples/stm32l5/src/bin/stop.rs index fd2aca372..7662dbfa8 100644 --- a/examples/stm32l5/src/bin/stop.rs +++ b/examples/stm32l5/src/bin/stop.rs @@ -9,7 +9,6 @@ use embassy_stm32::rcc::LsConfig; use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::{Config, Peri}; use embassy_time::Timer; -use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[cortex_m_rt::entry] -- cgit From 5abbd67815e634cf6e6c80f12318cd531b983e4e Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 3 Nov 2025 14:46:58 -0600 Subject: stm32/adc: fix example --- examples/stm32f4/src/bin/adc_dma.rs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'examples') diff --git a/examples/stm32f4/src/bin/adc_dma.rs b/examples/stm32f4/src/bin/adc_dma.rs index c24f01753..65adb47e6 100644 --- a/examples/stm32f4/src/bin/adc_dma.rs +++ b/examples/stm32f4/src/bin/adc_dma.rs @@ -4,7 +4,7 @@ use cortex_m::singleton; use defmt::*; use embassy_executor::Spawner; use embassy_stm32::Peripherals; -use embassy_stm32::adc::{Adc, RingBufferedAdc, SampleTime, Sequence}; +use embassy_stm32::adc::{Adc, AdcChannel, RingBufferedAdc, SampleTime}; use embassy_time::Instant; use {defmt_rtt as _, panic_probe as _}; @@ -23,13 +23,24 @@ async fn adc_task(mut p: Peripherals) { let adc = Adc::new(p.ADC1); let adc2 = Adc::new(p.ADC2); - let mut adc: RingBufferedAdc = adc.into_ring_buffered(p.DMA2_CH0, adc_data); - let mut adc2: RingBufferedAdc = adc2.into_ring_buffered(p.DMA2_CH2, adc_data2); - - adc.set_sample_sequence(Sequence::One, &mut p.PA0, SampleTime::CYCLES112); - adc.set_sample_sequence(Sequence::Two, &mut p.PA2, SampleTime::CYCLES112); - adc2.set_sample_sequence(Sequence::One, &mut p.PA1, SampleTime::CYCLES112); - adc2.set_sample_sequence(Sequence::Two, &mut p.PA3, SampleTime::CYCLES112); + let mut adc: RingBufferedAdc = adc.into_ring_buffered( + p.DMA2_CH0, + adc_data, + [ + (&mut p.PA0.degrade_adc(), SampleTime::CYCLES112), + (&mut p.PA2.degrade_adc(), SampleTime::CYCLES112), + ] + .into_iter(), + ); + let mut adc2: RingBufferedAdc = adc2.into_ring_buffered( + p.DMA2_CH2, + adc_data2, + [ + (&mut p.PA1.degrade_adc(), SampleTime::CYCLES112), + (&mut p.PA3.degrade_adc(), SampleTime::CYCLES112), + ] + .into_iter(), + ); // Note that overrun is a big consideration in this implementation. Whatever task is running the adc.read() calls absolutely must circle back around // to the adc.read() call before the DMA buffer is wrapped around > 1 time. At this point, the overrun is so significant that the context of -- cgit From 46480285783390d90f8d99e530a1da28a292dc3c Mon Sep 17 00:00:00 2001 From: liebman Date: Wed, 29 Oct 2025 14:47:06 -0700 Subject: examples: add low-power examples for `stm32wlex` --- examples/stm32wle5/.cargo/config.toml | 9 +++ examples/stm32wle5/Cargo.toml | 38 ++++++++++ examples/stm32wle5/README.md | 45 ++++++++++++ examples/stm32wle5/build.rs | 5 ++ examples/stm32wle5/src/bin/adc.rs | 105 ++++++++++++++++++++++++++++ examples/stm32wle5/src/bin/blinky.rs | 95 +++++++++++++++++++++++++ examples/stm32wle5/src/bin/button_exti.rs | 96 +++++++++++++++++++++++++ examples/stm32wle5/stm32wle5.code-workspace | 13 ++++ 8 files changed, 406 insertions(+) create mode 100644 examples/stm32wle5/.cargo/config.toml create mode 100644 examples/stm32wle5/Cargo.toml create mode 100644 examples/stm32wle5/README.md create mode 100644 examples/stm32wle5/build.rs create mode 100644 examples/stm32wle5/src/bin/adc.rs create mode 100644 examples/stm32wle5/src/bin/blinky.rs create mode 100644 examples/stm32wle5/src/bin/button_exti.rs create mode 100644 examples/stm32wle5/stm32wle5.code-workspace (limited to 'examples') 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 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32WLE5JCIx --connect-under-reset" + +[build] +target = "thumbv7em-none-eabi" + +[env] +DEFMT_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 @@ +[package] +edition = "2024" +name = "embassy-stm32wl-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" +publish = false + +[dependencies] +# Change stm32wl55jc-cm4 to your chip name, if necessary. +embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = ["defmt", "stm32wle5jc", "time-driver-any", "memory-x", "unstable-pac", "exti", "low-power"] } +embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-1_000"] } +embassy-embedded-hal = { version = "0.5.0", path = "../../embassy-embedded-hal" } + +defmt = "1.0.1" +defmt-rtt = { version = "1.1.0", optional = true } +defmt-serial = { version = "0.10.0", optional = true } + +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = "0.7.0" +embedded-hal = "1.0.0" +embedded-storage = "0.3.1" +panic-probe = { version = "1.0.0", features = ["print-defmt"] } +static_cell = { version = "2.1.1", default-features = false } + +[profile.release] +debug = 2 + +[package.metadata.embassy] +build = [ + { target = "thumbv7em-none-eabi", artifact-dir = "out/examples/stm32wl" } +] + +[features] +default = ["defmt-serial"] +defmt-rtt = ["dep:defmt-rtt"] +defmt-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 @@ +# Low Power Examples for STM32WLEx family + +Examples 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. + +## Prerequsits + +- Connect a usb serial adapter to LPUart1 (this is where ALL logging will go) +- Optional: Connect an amp meter that ran measure down to 0.1uA to the power test pins + +## Example Notes + +All examples will set all pins to analog mode before configuring pins for the example, if any. This saves about 500uA!!!! + +- 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 + +Run individual examples with +``` +cargo flash --chip STM32WLE5JCIx --connect-under-reset --bin +``` +for example +``` +cargo flash --chip STM32WLE5JCIx --connect-under-reset --bin blinky +``` + +You 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! +``` +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 L432KCU6 it should be `probe-rs run --chip STM32L432KCUx`. (use `probe-rs chip list` to find your chip) +* [ ] 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. +* [ ] 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 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 @@ +fn main() { + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} 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 @@ +#![no_std] +#![no_main] + +use defmt::*; +#[cfg(feature = "defmt-rtt")] +use defmt_rtt as _; +use embassy_executor::Spawner; +use embassy_stm32::adc::{Adc, SampleTime}; +use embassy_stm32::low_power::Executor; +use embassy_stm32::rtc::{Rtc, RtcConfig}; +use embassy_time::Timer; +use panic_probe as _; +use static_cell::StaticCell; + +#[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.adcsel = embassy_stm32::pac::rcc::vals::Adcsel::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 mut config = embassy_stm32::usart::Config::default(); + config.baudrate = 115200; + config.assume_noise_free = true; + config.detect_previous_overrun = true; + 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 mut adc = Adc::new(p.ADC1); + adc.set_sample_time(SampleTime::CYCLES79_5); + let mut pin = p.PA10; + + let mut vrefint = adc.enable_vrefint(); + let vrefint_sample = adc.blocking_read(&mut vrefint); + let convert_to_millivolts = |sample| { + // From https://www.st.com/resource/en/datasheet/stm32g031g8.pdf + // 6.3.3 Embedded internal reference voltage + const VREFINT_MV: u32 = 1212; // mV + + (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16 + }; + + loop { + let v = adc.blocking_read(&mut pin); + info!("--> {} - {} mV", v, convert_to_millivolts(v)); + Timer::after_secs(1).await; + } +} 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 @@ +#![no_std] +#![no_main] + +use defmt::*; +#[cfg(feature = "defmt-rtt")] +use defmt_rtt as _; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::low_power::Executor; +use embassy_stm32::rtc::{Rtc, RtcConfig}; +use embassy_time::Timer; +use panic_probe as _; +use static_cell::StaticCell; + +#[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; + #[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 mut config = embassy_stm32::usart::Config::default(); + config.baudrate = 115200; + config.assume_noise_free = true; + config.detect_previous_overrun = true; + 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 mut led = Output::new(p.PB5, Level::High, Speed::Low); + + loop { + info!("low"); + led.set_low(); + Timer::after_millis(500).await; + + info!("high"); + led.set_high(); + Timer::after_millis(500).await; + } +} 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 @@ +#![no_std] +#![no_main] + +use defmt::*; +#[cfg(feature = "defmt-rtt")] +use defmt_rtt as _; +use embassy_executor::Spawner; +use embassy_stm32::exti::ExtiInput; +use embassy_stm32::gpio::Pull; +use embassy_stm32::low_power::Executor; +use embassy_stm32::rtc::{Rtc, RtcConfig}; +use panic_probe as _; +use static_cell::StaticCell; + +#[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.adcsel = embassy_stm32::pac::rcc::vals::Adcsel::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 mut config = embassy_stm32::usart::Config::default(); + config.baudrate = 115200; + config.assume_noise_free = true; + config.detect_previous_overrun = true; + 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 mut button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Up); + + info!("Press the USER button..."); + + loop { + button.wait_for_falling_edge().await; + info!("Pressed!"); + button.wait_for_rising_edge().await; + info!("Released!"); + } +} 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 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "rust-analyzer.cargo.target": "thumbv7em-none-eabi", + "rust-analyzer.cargo.allTargets": false, + "rust-analyzer.cargo.targetDir": "target/rust-analyzer", + "rust-analyzer.checkOnSave": true, + } +} -- cgit From 5b70da2256747853ac4f866e60493241ac34bcd3 Mon Sep 17 00:00:00 2001 From: liebman Date: Wed, 29 Oct 2025 15:08:01 -0700 Subject: examples: : stm32wlex: mention `defmt-print` --- examples/stm32wle5/README.md | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'examples') diff --git a/examples/stm32wle5/README.md b/examples/stm32wle5/README.md index 7435ed1be..63507f490 100644 --- a/examples/stm32wle5/README.md +++ b/examples/stm32wle5/README.md @@ -6,6 +6,7 @@ Examples in this repo should work with [LoRa-E5 Dev Board](https://www.st.com/en - Connect a usb serial adapter to LPUart1 (this is where ALL logging will go) - Optional: Connect an amp meter that ran measure down to 0.1uA to the power test pins +- `cargo install defmt-print` so you can print log messahes from LPUart1 ## Example Notes @@ -15,6 +16,11 @@ All examples will set all pins to analog mode before configuring pins for the ex - 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 +For each example you will need to start `defmt-print` with the example binary and the correct serial port in a seperate terminal. Example: +``` +defmt-print -w -v -e target/thumbv7em-none-eabi/debug/ serial --path /dev/cu.usbserial-00000000 --baud 115200 +``` + Run individual examples with ``` cargo flash --chip STM32WLE5JCIx --connect-under-reset --bin -- cgit 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 From 9f9ce2274a96f9d5395c814fc139abe594453625 Mon Sep 17 00:00:00 2001 From: liebman Date: Mon, 3 Nov 2025 12:59:06 -0800 Subject: stm32wle5 update low-power examples --- examples/stm32wle5/src/bin/adc.rs | 2 -- examples/stm32wle5/src/bin/blinky.rs | 2 -- examples/stm32wle5/src/bin/button_exti.rs | 2 -- examples/stm32wle5/src/bin/i2c.rs | 2 -- 4 files changed, 8 deletions(-) (limited to 'examples') diff --git a/examples/stm32wle5/src/bin/adc.rs b/examples/stm32wle5/src/bin/adc.rs index b4af656ed..ff1a5fa16 100644 --- a/examples/stm32wle5/src/bin/adc.rs +++ b/examples/stm32wle5/src/bin/adc.rs @@ -74,8 +74,6 @@ async fn async_main(_spawner: Spawner) { // 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!"); diff --git a/examples/stm32wle5/src/bin/blinky.rs b/examples/stm32wle5/src/bin/blinky.rs index a7a571cb1..1191a1157 100644 --- a/examples/stm32wle5/src/bin/blinky.rs +++ b/examples/stm32wle5/src/bin/blinky.rs @@ -72,8 +72,6 @@ async fn async_main(_spawner: Spawner) { // 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!"); diff --git a/examples/stm32wle5/src/bin/button_exti.rs b/examples/stm32wle5/src/bin/button_exti.rs index c8083a240..f07f9724d 100644 --- a/examples/stm32wle5/src/bin/button_exti.rs +++ b/examples/stm32wle5/src/bin/button_exti.rs @@ -74,8 +74,6 @@ async fn async_main(_spawner: Spawner) { // 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!"); diff --git a/examples/stm32wle5/src/bin/i2c.rs b/examples/stm32wle5/src/bin/i2c.rs index 4a56773e9..af07f911e 100644 --- a/examples/stm32wle5/src/bin/i2c.rs +++ b/examples/stm32wle5/src/bin/i2c.rs @@ -81,8 +81,6 @@ async fn async_main(_spawner: Spawner) { // 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!"); -- cgit From edaff5fb7900d0435241f27710b1d333383a30eb Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 3 Nov 2025 15:36:29 -0600 Subject: fmt --- examples/stm32f4/src/bin/adc_dma.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32f4/src/bin/adc_dma.rs b/examples/stm32f4/src/bin/adc_dma.rs index 65adb47e6..f8da91336 100644 --- a/examples/stm32f4/src/bin/adc_dma.rs +++ b/examples/stm32f4/src/bin/adc_dma.rs @@ -15,7 +15,7 @@ async fn main(spawner: Spawner) { } #[embassy_executor::task] -async fn adc_task(mut p: Peripherals) { +async fn adc_task(p: Peripherals) { const ADC_BUF_SIZE: usize = 1024; let adc_data: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap(); let adc_data2: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT2 : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap(); -- cgit From 729a7c2cc5e5fe1d9badb0a0f1c758ba2c57b6aa Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 4 Nov 2025 13:10:45 +0100 Subject: feat: initial support for nrf54 CRACEN peripheral The CRACEN peripheral supports random number generation, digest and key generation, and key exchange. The initial support implements random number generation. --- examples/nrf54l15/Cargo.toml | 2 ++ examples/nrf54l15/src/bin/rng.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 examples/nrf54l15/src/bin/rng.rs (limited to 'examples') diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml index 14a80efe7..4ef77279f 100644 --- a/examples/nrf54l15/Cargo.toml +++ b/examples/nrf54l15/Cargo.toml @@ -14,6 +14,8 @@ embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defm embedded-io = { version = "0.6.0", features = ["defmt-03"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } +rand = { version = "0.9.0", default-features = false } + defmt = "1.0.1" defmt-rtt = "1.0.0" panic-probe = { version = "1.0.0", features = ["print-defmt"] } diff --git a/examples/nrf54l15/src/bin/rng.rs b/examples/nrf54l15/src/bin/rng.rs new file mode 100644 index 000000000..3be035b9c --- /dev/null +++ b/examples/nrf54l15/src/bin/rng.rs @@ -0,0 +1,29 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_nrf::cracen::Cracen; +use embassy_nrf::{bind_interrupts, cracen, peripherals}; +use rand::Rng as _; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + let mut rng = Cracen::new_blocking(p.CRACEN); + + // Async API + let mut bytes = [0; 4]; + rng.blocking_fill_bytes(&mut bytes); + defmt::info!("Some random bytes: {:?}", bytes); + + // Sync API with `rand` + defmt::info!("A random number from 1 to 10: {:?}", rng.random_range(1..=10)); + + let mut bytes = [0; 1024]; + rng.blocking_fill_bytes(&mut bytes); + let zero_count: u32 = bytes.iter().fold(0, |acc, val| acc + val.count_zeros()); + let one_count: u32 = bytes.iter().fold(0, |acc, val| acc + val.count_ones()); + defmt::info!("Chance of zero: {}%", zero_count * 100 / (bytes.len() as u32 * 8)); + defmt::info!("Chance of one: {}%", one_count * 100 / (bytes.len() as u32 * 8)); +} -- cgit From 43af352733fc93ce05304b3122e52a6a9da50e22 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 4 Nov 2025 13:39:59 +0100 Subject: chore: warnings --- examples/nrf54l15/src/bin/rng.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'examples') diff --git a/examples/nrf54l15/src/bin/rng.rs b/examples/nrf54l15/src/bin/rng.rs index 3be035b9c..b2d7f906b 100644 --- a/examples/nrf54l15/src/bin/rng.rs +++ b/examples/nrf54l15/src/bin/rng.rs @@ -3,7 +3,6 @@ use embassy_executor::Spawner; use embassy_nrf::cracen::Cracen; -use embassy_nrf::{bind_interrupts, cracen, peripherals}; use rand::Rng as _; use {defmt_rtt as _, panic_probe as _}; -- cgit From 488d06c0e9da673f770b41d8f79bf26227dc6d53 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 4 Nov 2025 12:26:37 -0600 Subject: stm32/stop: move stop_with_rtc into init --- examples/stm32h5/src/bin/stop.rs | 5 ----- examples/stm32l5/src/bin/stop.rs | 5 ----- examples/stm32wle5/src/bin/adc.rs | 6 ------ examples/stm32wle5/src/bin/blinky.rs | 6 ------ examples/stm32wle5/src/bin/button_exti.rs | 6 ------ examples/stm32wle5/src/bin/i2c.rs | 6 ------ 6 files changed, 34 deletions(-) (limited to 'examples') diff --git a/examples/stm32h5/src/bin/stop.rs b/examples/stm32h5/src/bin/stop.rs index 2026d8f99..caebc9daf 100644 --- a/examples/stm32h5/src/bin/stop.rs +++ b/examples/stm32h5/src/bin/stop.rs @@ -9,7 +9,6 @@ use embassy_executor::Spawner; use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; use embassy_stm32::low_power::Executor; use embassy_stm32::rcc::{HSIPrescaler, LsConfig}; -use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::{Config, Peri}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -36,10 +35,6 @@ async fn async_main(spawner: Spawner) { // config.enable_debug_during_sleep = false; let p = embassy_stm32::init(config); - // give the RTC to the executor... - let rtc = Rtc::new(p.RTC, RtcConfig::default()); - embassy_stm32::low_power::stop_with_rtc(rtc); - spawner.spawn(unwrap!(blinky(p.PB4.into()))); spawner.spawn(unwrap!(timeout())); } diff --git a/examples/stm32l5/src/bin/stop.rs b/examples/stm32l5/src/bin/stop.rs index 7662dbfa8..3d119f90f 100644 --- a/examples/stm32l5/src/bin/stop.rs +++ b/examples/stm32l5/src/bin/stop.rs @@ -6,7 +6,6 @@ use embassy_executor::Spawner; use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; use embassy_stm32::low_power::Executor; use embassy_stm32::rcc::LsConfig; -use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::{Config, Peri}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -27,10 +26,6 @@ async fn async_main(spawner: Spawner) { // config.enable_debug_during_sleep = false; let p = embassy_stm32::init(config); - // give the RTC to the executor... - let rtc = Rtc::new(p.RTC, RtcConfig::default()); - embassy_stm32::low_power::stop_with_rtc(rtc); - spawner.spawn(unwrap!(blinky(p.PC7.into()))); spawner.spawn(unwrap!(timeout())); } diff --git a/examples/stm32wle5/src/bin/adc.rs b/examples/stm32wle5/src/bin/adc.rs index ff1a5fa16..8b830a1e6 100644 --- a/examples/stm32wle5/src/bin/adc.rs +++ b/examples/stm32wle5/src/bin/adc.rs @@ -7,7 +7,6 @@ use defmt_rtt as _; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::low_power::Executor; -use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_time::Timer; use panic_probe as _; use static_cell::StaticCell; @@ -71,11 +70,6 @@ async fn async_main(_spawner: Spawner) { 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); - embassy_stm32::low_power::stop_with_rtc(rtc); - info!("Hello World!"); let mut adc = Adc::new(p.ADC1); diff --git a/examples/stm32wle5/src/bin/blinky.rs b/examples/stm32wle5/src/bin/blinky.rs index 1191a1157..b2745fdaf 100644 --- a/examples/stm32wle5/src/bin/blinky.rs +++ b/examples/stm32wle5/src/bin/blinky.rs @@ -7,7 +7,6 @@ use defmt_rtt as _; use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::low_power::Executor; -use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_time::Timer; use panic_probe as _; use static_cell::StaticCell; @@ -69,11 +68,6 @@ async fn async_main(_spawner: Spawner) { 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); - embassy_stm32::low_power::stop_with_rtc(rtc); - info!("Hello World!"); let mut led = Output::new(p.PB5, Level::High, Speed::Low); diff --git a/examples/stm32wle5/src/bin/button_exti.rs b/examples/stm32wle5/src/bin/button_exti.rs index f07f9724d..db1bff0be 100644 --- a/examples/stm32wle5/src/bin/button_exti.rs +++ b/examples/stm32wle5/src/bin/button_exti.rs @@ -8,7 +8,6 @@ use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; use embassy_stm32::gpio::Pull; use embassy_stm32::low_power::Executor; -use embassy_stm32::rtc::{Rtc, RtcConfig}; use panic_probe as _; use static_cell::StaticCell; @@ -71,11 +70,6 @@ async fn async_main(_spawner: Spawner) { 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); - embassy_stm32::low_power::stop_with_rtc(rtc); - info!("Hello World!"); let mut button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Up); diff --git a/examples/stm32wle5/src/bin/i2c.rs b/examples/stm32wle5/src/bin/i2c.rs index af07f911e..c31c673c9 100644 --- a/examples/stm32wle5/src/bin/i2c.rs +++ b/examples/stm32wle5/src/bin/i2c.rs @@ -7,7 +7,6 @@ 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}; @@ -78,11 +77,6 @@ async fn async_main(_spawner: Spawner) { 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); - embassy_stm32::low_power::stop_with_rtc(rtc); - info!("Hello World!"); let en3v3 = embassy_stm32::gpio::Output::new( p.PA9, -- cgit From 8184bb809b65281cfcf0035e40c7c215d6b9aeda Mon Sep 17 00:00:00 2001 From: Jakob Date: Tue, 4 Nov 2025 19:55:09 +0100 Subject: Implement into_ring_buffered for g4. Add methods for configuring injected sampling for g4. --- examples/stm32g4/.cargo/config.toml | 2 +- examples/stm32g4/Cargo.toml | 13 +- examples/stm32g4/src/bin/adc_dma.rs | 4 +- .../stm32g4/src/bin/adc_injected_and_regular.rs | 144 +++++++++++++++++++++ 4 files changed, 154 insertions(+), 9 deletions(-) create mode 100644 examples/stm32g4/src/bin/adc_injected_and_regular.rs (limited to 'examples') diff --git a/examples/stm32g4/.cargo/config.toml b/examples/stm32g4/.cargo/config.toml index d28ad069e..de3e5718e 100644 --- a/examples/stm32g4/.cargo/config.toml +++ b/examples/stm32g4/.cargo/config.toml @@ -6,4 +6,4 @@ runner = "probe-rs run --chip STM32G484VETx" target = "thumbv7em-none-eabi" [env] -DEFMT_LOG = "trace" +DEFMT_LOG = "trace" \ No newline at end of file diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 6fd282d6d..8bbeb594c 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -7,12 +7,12 @@ publish = false [dependencies] # Change stm32g491re to your chip name, if necessary. -embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } -embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } -embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } +embassy-stm32 = { path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } +embassy-sync = { path = "../../embassy-sync", features = ["defmt"] } +embassy-executor = { path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-usb = { path = "../../embassy-usb", features = ["defmt"] } +embassy-futures = { path = "../../embassy-futures" } usbd-hid = "0.8.1" defmt = "1.0.1" @@ -25,6 +25,7 @@ embedded-can = { version = "0.4" } panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } static_cell = "2.0.0" +critical-section = "1.1" [profile.release] debug = 2 diff --git a/examples/stm32g4/src/bin/adc_dma.rs b/examples/stm32g4/src/bin/adc_dma.rs index a82067049..ef8b0c3c2 100644 --- a/examples/stm32g4/src/bin/adc_dma.rs +++ b/examples/stm32g4/src/bin/adc_dma.rs @@ -12,7 +12,7 @@ static mut DMA_BUF: [u16; 2] = [0; 2]; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let mut read_buffer = unsafe { &mut DMA_BUF[..] }; + let read_buffer = unsafe { &mut DMA_BUF[..] }; let mut config = Config::default(); { @@ -47,7 +47,7 @@ async fn main(_spawner: Spawner) { (&mut pa0, SampleTime::CYCLES247_5), ] .into_iter(), - &mut read_buffer, + read_buffer, ) .await; diff --git a/examples/stm32g4/src/bin/adc_injected_and_regular.rs b/examples/stm32g4/src/bin/adc_injected_and_regular.rs new file mode 100644 index 000000000..5db1a4fa0 --- /dev/null +++ b/examples/stm32g4/src/bin/adc_injected_and_regular.rs @@ -0,0 +1,144 @@ +//! adc injected and regular conversions +//! +//! This example both regular and injected ADC conversions at the same time +//! p:pa0 n:pa2 + +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use defmt::info; +use embassy_stm32::adc::{Adc, AdcChannel as _, Exten, RxDma, SampleTime}; +use embassy_stm32::interrupt::typelevel::{ADC1_2, Interrupt}; +use embassy_stm32::peripherals::ADC1; +use embassy_stm32::time::Hertz; +use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, Mms2}; +use embassy_stm32::timer::low_level::CountingMode; +use embassy_stm32::{Config, interrupt}; +use embassy_sync::blocking_mutex::CriticalSectionMutex; +use {critical_section, defmt_rtt as _, panic_probe as _}; + +static ADC1_HANDLE: CriticalSectionMutex>>> = + CriticalSectionMutex::new(RefCell::new(None)); + +/// This example showcases how to use both regular ADC conversions with DMA and injected ADC +/// conversions with ADC interrupt simultaneously. Both conversion types can be configured with +/// different triggers and thanks to DMA it is possible to use the measurements in different task +/// without needing to access the ADC peripheral. +/// +/// If you don't need both regular and injected conversions the example code can easily be reworked +/// to only include one of the ADC conversion types. +#[embassy_executor::main] +async fn main(_spawner: embassy_executor::Spawner) { + // See Table 166 and 167 in RM0440 Rev 9 for ADC1/2 External triggers + // Note: Regular and Injected channels use different tables!! + const ADC1_INJECTED_TRIGGER_TIM1_TRGO2: u8 = 8; + const ADC1_REGULAR_TRIGGER_TIM1_TRGO2: u8 = 10; + + // --- RCC config --- + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.pll = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL85, + divp: None, + divq: None, + divr: Some(PllRDiv::DIV2), + }); + config.rcc.mux.adc12sel = mux::Adcsel::SYS; + config.rcc.sys = Sysclk::PLL1_R; + } + let p = embassy_stm32::init(config); + + // In this example we use tim1_trgo2 event to trigger the ADC conversions + let tim1 = p.TIM1; + let pwm_freq = 1; + let mut pwm = ComplementaryPwm::new( + tim1, + None, + None, + None, + None, + None, + None, + None, + None, + Hertz::hz(pwm_freq), + CountingMode::EdgeAlignedUp, + ); + pwm.set_master_output_enable(false); + // Mms2 is used to configure which timer event that is connected to tim1_trgo2. + // In this case we use the update event of the timer. + pwm.set_mms2(Mms2::UPDATE); + + // Configure regular conversions with DMA + let mut adc1 = Adc::new(p.ADC1); + + let mut vrefint_channel = adc1.enable_vrefint().degrade_adc(); + let mut pa0 = p.PC1.degrade_adc(); + let regular_sequence = [ + (&mut vrefint_channel, SampleTime::CYCLES247_5), + (&mut pa0, SampleTime::CYCLES247_5), + ] + .into_iter(); + + // Configure DMA for retrieving regular ADC measurements + let dma1_ch1 = p.DMA1_CH1; + // Using buffer of double size means the half-full interrupts will generate at the expected rate + let mut readings = [0u16; 4]; + let mut ring_buffered_adc = adc1.into_ring_buffered(dma1_ch1, &mut readings, regular_sequence); + + // Configurations of Injected ADC measurements + let mut pa2 = p.PA2.degrade_adc(); + let injected_seq = [(&mut pa2, SampleTime::CYCLES247_5)].into_iter(); + adc1.configure_injected_sequence(injected_seq); + + adc1.set_regular_conversion_trigger(ADC1_REGULAR_TRIGGER_TIM1_TRGO2, Exten::RISING_EDGE); + adc1.set_injected_conversion_trigger(ADC1_INJECTED_TRIGGER_TIM1_TRGO2, Exten::RISING_EDGE); + + // ADC must be started after all configurations are completed + adc1.start_injected_conversion(); + + // Enable interrupt at end of injected ADC conversion + adc1.enable_injected_eos_interrupt(true); + + // Store ADC globally to allow access from ADC interrupt + critical_section::with(|cs| { + ADC1_HANDLE.borrow(cs).replace(Some(adc1)); + }); + // Enable interrupt for ADC1_2 + unsafe { ADC1_2::enable() }; + + // Main loop for reading regular ADC measurements periodically + let mut data = [0u16; 2]; + loop { + { + match ring_buffered_adc.read(&mut data).await { + Ok(n) => { + defmt::info!("Regular ADC reading, VrefInt: {}, PA0: {}", data[0], data[1]); + defmt::info!("Remaining samples: {}", n,); + } + Err(e) => { + defmt::error!("DMA error: {:?}", e); + ring_buffered_adc.clear(); + } + } + } + } +} + +/// Use ADC1_2 interrupt to retrieve injected ADC measurements +/// Interrupt must be unsafe as hardware can invoke it any-time. Critical sections ensure safety +/// within the interrupt. +#[interrupt] +unsafe fn ADC1_2() { + critical_section::with(|cs| { + if let Some(adc) = ADC1_HANDLE.borrow(cs).borrow_mut().as_mut() { + let injected_data = adc.clear_injected_eos(); + info!("Injected reading of PA2: {}", injected_data[0]); + } + }); +} -- cgit From c5da0610f5fab70f9d0ede4b818161517460664f Mon Sep 17 00:00:00 2001 From: Jakob Date: Tue, 4 Nov 2025 20:16:13 +0100 Subject: Remove unused import from example --- examples/stm32g4/src/bin/adc_injected_and_regular.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32g4/src/bin/adc_injected_and_regular.rs b/examples/stm32g4/src/bin/adc_injected_and_regular.rs index 5db1a4fa0..c2985e1d6 100644 --- a/examples/stm32g4/src/bin/adc_injected_and_regular.rs +++ b/examples/stm32g4/src/bin/adc_injected_and_regular.rs @@ -9,7 +9,7 @@ use core::cell::RefCell; use defmt::info; -use embassy_stm32::adc::{Adc, AdcChannel as _, Exten, RxDma, SampleTime}; +use embassy_stm32::adc::{Adc, AdcChannel as _, Exten, SampleTime}; use embassy_stm32::interrupt::typelevel::{ADC1_2, Interrupt}; use embassy_stm32::peripherals::ADC1; use embassy_stm32::time::Hertz; -- cgit From b9559c7713bc7f773cdef0df14f1158840d06d06 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 4 Nov 2025 16:35:07 -0600 Subject: rtc: use consistent api between stop and non-stop --- examples/stm32c0/src/bin/rtc.rs | 4 ++-- examples/stm32f4/src/bin/rtc.rs | 4 ++-- examples/stm32g0/src/bin/rtc.rs | 4 ++-- examples/stm32h7/src/bin/rtc.rs | 4 ++-- examples/stm32h7rs/src/bin/rtc.rs | 4 ++-- examples/stm32l4/src/bin/rtc.rs | 4 ++-- examples/stm32u0/src/bin/rtc.rs | 4 ++-- examples/stm32wl/src/bin/rtc.rs | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) (limited to 'examples') diff --git a/examples/stm32c0/src/bin/rtc.rs b/examples/stm32c0/src/bin/rtc.rs index feb27f6d9..5ff705ca2 100644 --- a/examples/stm32c0/src/bin/rtc.rs +++ b/examples/stm32c0/src/bin/rtc.rs @@ -21,12 +21,12 @@ async fn main(_spawner: Spawner) { .and_hms_opt(10, 30, 15) .unwrap(); - let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); + let (mut rtc, time_provider) = Rtc::new(p.RTC, RtcConfig::default()); rtc.set_datetime(now.into()).expect("datetime not set"); loop { - let now: NaiveDateTime = rtc.now().unwrap().into(); + let now: NaiveDateTime = time_provider.now().unwrap().into(); info!("{}", now.and_utc().timestamp()); diff --git a/examples/stm32f4/src/bin/rtc.rs b/examples/stm32f4/src/bin/rtc.rs index feb27f6d9..5ff705ca2 100644 --- a/examples/stm32f4/src/bin/rtc.rs +++ b/examples/stm32f4/src/bin/rtc.rs @@ -21,12 +21,12 @@ async fn main(_spawner: Spawner) { .and_hms_opt(10, 30, 15) .unwrap(); - let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); + let (mut rtc, time_provider) = Rtc::new(p.RTC, RtcConfig::default()); rtc.set_datetime(now.into()).expect("datetime not set"); loop { - let now: NaiveDateTime = rtc.now().unwrap().into(); + let now: NaiveDateTime = time_provider.now().unwrap().into(); info!("{}", now.and_utc().timestamp()); diff --git a/examples/stm32g0/src/bin/rtc.rs b/examples/stm32g0/src/bin/rtc.rs index 21da204cc..d8b58de22 100644 --- a/examples/stm32g0/src/bin/rtc.rs +++ b/examples/stm32g0/src/bin/rtc.rs @@ -17,12 +17,12 @@ async fn main(_spawner: Spawner) { let now = DateTime::from(2023, 6, 14, DayOfWeek::Friday, 15, 59, 10, 0); - let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); + let (mut rtc, time_provider) = Rtc::new(p.RTC, RtcConfig::default()); rtc.set_datetime(now.unwrap()).expect("datetime not set"); loop { - let now: DateTime = rtc.now().unwrap().into(); + let now: DateTime = time_provider.now().unwrap().into(); info!("{}:{}:{}", now.hour(), now.minute(), now.second()); diff --git a/examples/stm32h7/src/bin/rtc.rs b/examples/stm32h7/src/bin/rtc.rs index 1bd71637b..965716d23 100644 --- a/examples/stm32h7/src/bin/rtc.rs +++ b/examples/stm32h7/src/bin/rtc.rs @@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) { .and_hms_opt(10, 30, 15) .unwrap(); - let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); + let (mut rtc, time_provider) = Rtc::new(p.RTC, RtcConfig::default()); info!("Got RTC! {:?}", now.and_utc().timestamp()); rtc.set_datetime(now.into()).expect("datetime not set"); @@ -31,6 +31,6 @@ async fn main(_spawner: Spawner) { // In reality the delay would be much longer Timer::after_millis(20000).await; - let then: NaiveDateTime = rtc.now().unwrap().into(); + let then: NaiveDateTime = time_provider.now().unwrap().into(); info!("Got RTC! {:?}", then.and_utc().timestamp()); } diff --git a/examples/stm32h7rs/src/bin/rtc.rs b/examples/stm32h7rs/src/bin/rtc.rs index 1bd71637b..965716d23 100644 --- a/examples/stm32h7rs/src/bin/rtc.rs +++ b/examples/stm32h7rs/src/bin/rtc.rs @@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) { .and_hms_opt(10, 30, 15) .unwrap(); - let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); + let (mut rtc, time_provider) = Rtc::new(p.RTC, RtcConfig::default()); info!("Got RTC! {:?}", now.and_utc().timestamp()); rtc.set_datetime(now.into()).expect("datetime not set"); @@ -31,6 +31,6 @@ async fn main(_spawner: Spawner) { // In reality the delay would be much longer Timer::after_millis(20000).await; - let then: NaiveDateTime = rtc.now().unwrap().into(); + let then: NaiveDateTime = time_provider.now().unwrap().into(); info!("Got RTC! {:?}", then.and_utc().timestamp()); } diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs index 1d26cd008..8b92075cc 100644 --- a/examples/stm32l4/src/bin/rtc.rs +++ b/examples/stm32l4/src/bin/rtc.rs @@ -39,7 +39,7 @@ async fn main(_spawner: Spawner) { .and_hms_opt(10, 30, 15) .unwrap(); - let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); + let (mut rtc, time_provider) = Rtc::new(p.RTC, RtcConfig::default()); info!("Got RTC! {:?}", now.and_utc().timestamp()); rtc.set_datetime(now.into()).expect("datetime not set"); @@ -47,6 +47,6 @@ async fn main(_spawner: Spawner) { // In reality the delay would be much longer Timer::after_millis(20000).await; - let then: NaiveDateTime = rtc.now().unwrap().into(); + let then: NaiveDateTime = time_provider.now().unwrap().into(); info!("Got RTC! {:?}", then.and_utc().timestamp()); } diff --git a/examples/stm32u0/src/bin/rtc.rs b/examples/stm32u0/src/bin/rtc.rs index d071cfbc7..56d16ccf7 100644 --- a/examples/stm32u0/src/bin/rtc.rs +++ b/examples/stm32u0/src/bin/rtc.rs @@ -36,7 +36,7 @@ async fn main(_spawner: Spawner) { .and_hms_opt(10, 30, 15) .unwrap(); - let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); + let (mut rtc, time_provider) = Rtc::new(p.RTC, RtcConfig::default()); info!("Got RTC! {:?}", now.and_utc().timestamp()); rtc.set_datetime(now.into()).expect("datetime not set"); @@ -44,6 +44,6 @@ async fn main(_spawner: Spawner) { // In reality the delay would be much longer Timer::after_millis(20000).await; - let then: NaiveDateTime = rtc.now().unwrap().into(); + let then: NaiveDateTime = time_provider.now().unwrap().into(); info!("Got RTC! {:?}", then.and_utc().timestamp()); } diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs index d3709120f..2185142c9 100644 --- a/examples/stm32wl/src/bin/rtc.rs +++ b/examples/stm32wl/src/bin/rtc.rs @@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) { .and_hms_opt(10, 30, 15) .unwrap(); - let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); + let (mut rtc, time_provider) = Rtc::new(p.RTC, RtcConfig::default()); info!("Got RTC! {:?}", now.and_utc().timestamp()); rtc.set_datetime(now.into()).expect("datetime not set"); @@ -52,6 +52,6 @@ async fn main(_spawner: Spawner) { // In reality the delay would be much longer Timer::after_millis(20000).await; - let then: NaiveDateTime = rtc.now().unwrap().into(); + let then: NaiveDateTime = time_provider.now().unwrap().into(); info!("Got RTC! {:?}", then.and_utc().timestamp()); } -- cgit From 141f826e10802a40ac1bca8fdcdfa3da821e0f28 Mon Sep 17 00:00:00 2001 From: Cristian Milatinov Date: Wed, 9 Jul 2025 20:35:01 -0400 Subject: feat: stm32 spi driver slave mode Add SPI slave constructors Fix SPI slave constructors Fix embedded hal async trait One more constructor fix Set SSM bit in SPI driver according to CommunicationMode Fix embedded_hal_async trait to be generic for both master and slave Fix I2S driver to use async master SPI Forgot import from spi mode Fix CommunicationMode associated const conditionals Duplicate doc for CommunicationMode const Add missing nss argument Fix existing SPI tests not compiling Fix stm32h7rs examples not compiling Fix failing stm32l4 example Fix stm32h7 example Fix stm32h7 spi_bdma example Fix stm32h7 spi example Fix stm32f4 example docs: added entry in changelog.md fix: spi_v3 vals mismatch + rise_fall_speed renamed to gpio_speed fix: added spi_v6 conditional compilation feature fix: use if_afio macro in slave constructors fix: add missing trait bound fix: if_afio for cs pin trait fix: changelog message fix: broken rebase --- examples/stm32f4/src/bin/eth_w5500.rs | 3 ++- examples/stm32h7/src/bin/spi.rs | 2 +- examples/stm32h7/src/bin/spi_bdma.rs | 2 +- examples/stm32h7/src/bin/spi_dma.rs | 2 +- examples/stm32h7rs/src/bin/spi.rs | 2 +- examples/stm32h7rs/src/bin/spi_dma.rs | 2 +- examples/stm32l4/src/bin/spe_adin1110_http_server.rs | 3 ++- 7 files changed, 9 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/stm32f4/src/bin/eth_w5500.rs b/examples/stm32f4/src/bin/eth_w5500.rs index cccf20949..0adcda614 100644 --- a/examples/stm32f4/src/bin/eth_w5500.rs +++ b/examples/stm32f4/src/bin/eth_w5500.rs @@ -12,6 +12,7 @@ use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_stm32::mode::Async; use embassy_stm32::rng::Rng; use embassy_stm32::spi::Spi; +use embassy_stm32::spi::mode::Master; use embassy_stm32::time::Hertz; use embassy_stm32::{Config, bind_interrupts, peripherals, rng, spi}; use embassy_time::{Delay, Timer}; @@ -24,7 +25,7 @@ bind_interrupts!(struct Irqs { HASH_RNG => rng::InterruptHandler; }); -type EthernetSPI = ExclusiveDevice, Output<'static>, Delay>; +type EthernetSPI = ExclusiveDevice, Output<'static>, Delay>; #[embassy_executor::task] async fn ethernet_task(runner: Runner<'static, W5500, EthernetSPI, ExtiInput<'static>, Output<'static>>) -> ! { runner.run().await diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs index 61f31be24..f7ab20cdd 100644 --- a/examples/stm32h7/src/bin/spi.rs +++ b/examples/stm32h7/src/bin/spi.rs @@ -15,7 +15,7 @@ use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] -async fn main_task(mut spi: spi::Spi<'static, Blocking>) { +async fn main_task(mut spi: spi::Spi<'static, Blocking, spi::mode::Master>) { for n in 0u32.. { let mut write: String<128> = String::new(); core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); diff --git a/examples/stm32h7/src/bin/spi_bdma.rs b/examples/stm32h7/src/bin/spi_bdma.rs index be6a26d82..cd9d6c789 100644 --- a/examples/stm32h7/src/bin/spi_bdma.rs +++ b/examples/stm32h7/src/bin/spi_bdma.rs @@ -20,7 +20,7 @@ use {defmt_rtt as _, panic_probe as _}; static mut RAM_D3: GroundedArrayCell = GroundedArrayCell::uninit(); #[embassy_executor::task] -async fn main_task(mut spi: spi::Spi<'static, Async>) { +async fn main_task(mut spi: spi::Spi<'static, Async, spi::mode::Master>) { let (read_buffer, write_buffer) = unsafe { let ram = &mut *core::ptr::addr_of_mut!(RAM_D3); ram.initialize_all_copied(0); diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs index 20cb67ba0..3d3c2f43e 100644 --- a/examples/stm32h7/src/bin/spi_dma.rs +++ b/examples/stm32h7/src/bin/spi_dma.rs @@ -15,7 +15,7 @@ use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] -async fn main_task(mut spi: spi::Spi<'static, Async>) { +async fn main_task(mut spi: spi::Spi<'static, Async, spi::mode::Master>) { for n in 0u32.. { let mut write: String<128> = String::new(); let mut read = [0; 128]; diff --git a/examples/stm32h7rs/src/bin/spi.rs b/examples/stm32h7rs/src/bin/spi.rs index 8c280fdae..3253304eb 100644 --- a/examples/stm32h7rs/src/bin/spi.rs +++ b/examples/stm32h7rs/src/bin/spi.rs @@ -15,7 +15,7 @@ use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] -async fn main_task(mut spi: spi::Spi<'static, Blocking>) { +async fn main_task(mut spi: spi::Spi<'static, Blocking, spi::mode::Master>) { for n in 0u32.. { let mut write: String<128> = String::new(); core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); diff --git a/examples/stm32h7rs/src/bin/spi_dma.rs b/examples/stm32h7rs/src/bin/spi_dma.rs index 3fa69fd15..ca644c6a8 100644 --- a/examples/stm32h7rs/src/bin/spi_dma.rs +++ b/examples/stm32h7rs/src/bin/spi_dma.rs @@ -15,7 +15,7 @@ use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] -async fn main_task(mut spi: spi::Spi<'static, Async>) { +async fn main_task(mut spi: spi::Spi<'static, Async, spi::mode::Master>) { for n in 0u32.. { let mut write: String<128> = String::new(); let mut read = [0; 128]; diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 8e54938d1..0dbf515cf 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -28,6 +28,7 @@ use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; use embassy_stm32::i2c::{self, Config as I2C_Config, I2c}; use embassy_stm32::mode::Async; use embassy_stm32::rng::{self, Rng}; +use embassy_stm32::spi::mode::Master; use embassy_stm32::spi::{Config as SPI_Config, Spi}; use embassy_stm32::time::Hertz; use embassy_stm32::{bind_interrupts, exti, pac, peripherals}; @@ -54,7 +55,7 @@ const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address::new(192, 168, 1, 5), 24) // Listen port for the webserver const HTTP_LISTEN_PORT: u16 = 80; -pub type SpeSpi = Spi<'static, Async>; +pub type SpeSpi = Spi<'static, Async, Master>; pub type SpeSpiCs = ExclusiveDevice, Delay>; pub type SpeInt = exti::ExtiInput<'static>; pub type SpeRst = Output<'static>; -- cgit From 8f6ce6b13e9ed1707f945d276439a31420f28bfb Mon Sep 17 00:00:00 2001 From: Jakob Date: Wed, 5 Nov 2025 20:53:43 +0100 Subject: Create raii wrapper for injected conversions --- .../stm32g4/src/bin/adc_injected_and_regular.rs | 38 ++++++++++++---------- 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'examples') diff --git a/examples/stm32g4/src/bin/adc_injected_and_regular.rs b/examples/stm32g4/src/bin/adc_injected_and_regular.rs index c2985e1d6..85e01dbf3 100644 --- a/examples/stm32g4/src/bin/adc_injected_and_regular.rs +++ b/examples/stm32g4/src/bin/adc_injected_and_regular.rs @@ -9,7 +9,7 @@ use core::cell::RefCell; use defmt::info; -use embassy_stm32::adc::{Adc, AdcChannel as _, Exten, SampleTime}; +use embassy_stm32::adc::{Adc, AdcChannel as _, Exten, SampleTime, ConversionTrigger, RegularConversionMode}; use embassy_stm32::interrupt::typelevel::{ADC1_2, Interrupt}; use embassy_stm32::peripherals::ADC1; use embassy_stm32::time::Hertz; @@ -17,9 +17,10 @@ use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, Mms2}; use embassy_stm32::timer::low_level::CountingMode; use embassy_stm32::{Config, interrupt}; use embassy_sync::blocking_mutex::CriticalSectionMutex; +use embassy_stm32::adc::InjectedAdc; use {critical_section, defmt_rtt as _, panic_probe as _}; -static ADC1_HANDLE: CriticalSectionMutex>>> = +static ADC1_HANDLE: CriticalSectionMutex>>> = CriticalSectionMutex::new(RefCell::new(None)); /// This example showcases how to use both regular ADC conversions with DMA and injected ADC @@ -85,29 +86,30 @@ async fn main(_spawner: embassy_executor::Spawner) { ] .into_iter(); + // Configurations of Injected ADC measurements + let mut pa2 = p.PA2.degrade_adc(); + let injected_sequence = [(&mut pa2, SampleTime::CYCLES247_5)].into_iter(); + // Configure DMA for retrieving regular ADC measurements let dma1_ch1 = p.DMA1_CH1; // Using buffer of double size means the half-full interrupts will generate at the expected rate let mut readings = [0u16; 4]; - let mut ring_buffered_adc = adc1.into_ring_buffered(dma1_ch1, &mut readings, regular_sequence); - - // Configurations of Injected ADC measurements - let mut pa2 = p.PA2.degrade_adc(); - let injected_seq = [(&mut pa2, SampleTime::CYCLES247_5)].into_iter(); - adc1.configure_injected_sequence(injected_seq); - adc1.set_regular_conversion_trigger(ADC1_REGULAR_TRIGGER_TIM1_TRGO2, Exten::RISING_EDGE); - adc1.set_injected_conversion_trigger(ADC1_INJECTED_TRIGGER_TIM1_TRGO2, Exten::RISING_EDGE); + let injected_trigger = ConversionTrigger { channel: ADC1_INJECTED_TRIGGER_TIM1_TRGO2, edge: Exten::RISING_EDGE }; + let regular_trigger = ConversionTrigger { channel: ADC1_REGULAR_TRIGGER_TIM1_TRGO2, edge: Exten::RISING_EDGE }; - // ADC must be started after all configurations are completed - adc1.start_injected_conversion(); - - // Enable interrupt at end of injected ADC conversion - adc1.enable_injected_eos_interrupt(true); + let (mut ring_buffered_adc, injected_adc) = adc1.into_regular_ringbuffered_and_injected_interrupts( + dma1_ch1, + &mut readings, + regular_sequence, + RegularConversionMode::Triggered(regular_trigger), + injected_sequence, + injected_trigger, + ); // Store ADC globally to allow access from ADC interrupt critical_section::with(|cs| { - ADC1_HANDLE.borrow(cs).replace(Some(adc1)); + ADC1_HANDLE.borrow(cs).replace(Some(injected_adc)); }); // Enable interrupt for ADC1_2 unsafe { ADC1_2::enable() }; @@ -136,8 +138,8 @@ async fn main(_spawner: embassy_executor::Spawner) { #[interrupt] unsafe fn ADC1_2() { critical_section::with(|cs| { - if let Some(adc) = ADC1_HANDLE.borrow(cs).borrow_mut().as_mut() { - let injected_data = adc.clear_injected_eos(); + if let Some(injected_adc) = ADC1_HANDLE.borrow(cs).borrow_mut().as_mut() { + let injected_data = injected_adc.read_injected_samples(); info!("Injected reading of PA2: {}", injected_data[0]); } }); -- cgit From 338c5bfc96c2b575a3e4007c23359a49c85fae00 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 5 Nov 2025 14:15:25 -0600 Subject: consume regular ringbuf --- examples/stm32g4/src/bin/adc_injected_and_regular.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/stm32g4/src/bin/adc_injected_and_regular.rs b/examples/stm32g4/src/bin/adc_injected_and_regular.rs index 85e01dbf3..d0c577b4b 100644 --- a/examples/stm32g4/src/bin/adc_injected_and_regular.rs +++ b/examples/stm32g4/src/bin/adc_injected_and_regular.rs @@ -9,7 +9,8 @@ use core::cell::RefCell; use defmt::info; -use embassy_stm32::adc::{Adc, AdcChannel as _, Exten, SampleTime, ConversionTrigger, RegularConversionMode}; +use embassy_stm32::adc::InjectedAdc; +use embassy_stm32::adc::{Adc, AdcChannel as _, ConversionTrigger, Exten, RegularConversionMode, SampleTime}; use embassy_stm32::interrupt::typelevel::{ADC1_2, Interrupt}; use embassy_stm32::peripherals::ADC1; use embassy_stm32::time::Hertz; @@ -17,7 +18,6 @@ use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, Mms2}; use embassy_stm32::timer::low_level::CountingMode; use embassy_stm32::{Config, interrupt}; use embassy_sync::blocking_mutex::CriticalSectionMutex; -use embassy_stm32::adc::InjectedAdc; use {critical_section, defmt_rtt as _, panic_probe as _}; static ADC1_HANDLE: CriticalSectionMutex>>> = @@ -76,7 +76,7 @@ async fn main(_spawner: embassy_executor::Spawner) { pwm.set_mms2(Mms2::UPDATE); // Configure regular conversions with DMA - let mut adc1 = Adc::new(p.ADC1); + let adc1 = Adc::new(p.ADC1); let mut vrefint_channel = adc1.enable_vrefint().degrade_adc(); let mut pa0 = p.PC1.degrade_adc(); @@ -95,10 +95,16 @@ async fn main(_spawner: embassy_executor::Spawner) { // Using buffer of double size means the half-full interrupts will generate at the expected rate let mut readings = [0u16; 4]; - let injected_trigger = ConversionTrigger { channel: ADC1_INJECTED_TRIGGER_TIM1_TRGO2, edge: Exten::RISING_EDGE }; - let regular_trigger = ConversionTrigger { channel: ADC1_REGULAR_TRIGGER_TIM1_TRGO2, edge: Exten::RISING_EDGE }; + let injected_trigger = ConversionTrigger { + channel: ADC1_INJECTED_TRIGGER_TIM1_TRGO2, + edge: Exten::RISING_EDGE, + }; + let regular_trigger = ConversionTrigger { + channel: ADC1_REGULAR_TRIGGER_TIM1_TRGO2, + edge: Exten::RISING_EDGE, + }; - let (mut ring_buffered_adc, injected_adc) = adc1.into_regular_ringbuffered_and_injected_interrupts( + let (mut ring_buffered_adc, injected_adc) = adc1.into_ring_buffered_and_injected( dma1_ch1, &mut readings, regular_sequence, -- cgit From 625550df00ee3fad74571a1e9e53c6470ef3497f Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 6 Nov 2025 08:42:12 -0600 Subject: stm32: add backup sram mod --- examples/stm32h5/src/bin/backup_sram.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 examples/stm32h5/src/bin/backup_sram.rs (limited to 'examples') diff --git a/examples/stm32h5/src/bin/backup_sram.rs b/examples/stm32h5/src/bin/backup_sram.rs new file mode 100644 index 000000000..f8db1853e --- /dev/null +++ b/examples/stm32h5/src/bin/backup_sram.rs @@ -0,0 +1,31 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::Config; +use embassy_stm32::backup_sram::BackupMemory; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + config.rcc.ls.enable_backup_sram = true; + + let p = embassy_stm32::init(config); + info!("Started!"); + + let (bytes, status) = BackupMemory::new(p.BKPSRAM); + + match status { + false => info!("BKPSRAM just enabled"), + true => info!("BKPSRAM already enabled"), + } + + loop { + info!("byte0: {}", bytes[0]); + bytes[0] = bytes[0].wrapping_add(1); + Timer::after_millis(500).await; + } +} -- cgit From b67c2055a54341c4cdf366688e6ef5ad6d87c7d2 Mon Sep 17 00:00:00 2001 From: Jakob Date: Fri, 7 Nov 2025 15:49:15 +0100 Subject: Rework how sequences ADC are specified. Update documentation in g4. Carefully chose which methods to expose publicly --- examples/stm32g4/.cargo/config.toml | 20 ++++++++++++++++---- examples/stm32g4/Cargo.toml | 2 +- examples/stm32g4/src/bin/adc_injected_and_regular.rs | 17 +++++++++-------- 3 files changed, 26 insertions(+), 13 deletions(-) (limited to 'examples') diff --git a/examples/stm32g4/.cargo/config.toml b/examples/stm32g4/.cargo/config.toml index de3e5718e..52b5a7bc8 100644 --- a/examples/stm32g4/.cargo/config.toml +++ b/examples/stm32g4/.cargo/config.toml @@ -1,9 +1,21 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace STM32G071C8Rx with your chip as listed in `probe-rs chip list` -runner = "probe-rs run --chip STM32G484VETx" +# Change this runner as required for your MCU. +runner = [ + "probe-rs", + "run", + "--chip", + "STM32G431VBTx", + "--speed", + "5000", + "--preverify", + "--log-format", + "{t} [{L}] {s}", +] + [build] -target = "thumbv7em-none-eabi" +target = "thumbv7em-none-eabihf" [env] -DEFMT_LOG = "trace" \ No newline at end of file +DEFMT_LOG = "info" +DEFMT_RTT_BUFFER_SIZE = "4096" diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 8bbeb594c..9089ec0d5 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] # Change stm32g491re to your chip name, if necessary. -embassy-stm32 = { path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } +embassy-stm32 = { path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g431vb", "memory-x", "unstable-pac", "exti"] } embassy-sync = { path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32g4/src/bin/adc_injected_and_regular.rs b/examples/stm32g4/src/bin/adc_injected_and_regular.rs index d0c577b4b..c929ca3bf 100644 --- a/examples/stm32g4/src/bin/adc_injected_and_regular.rs +++ b/examples/stm32g4/src/bin/adc_injected_and_regular.rs @@ -18,9 +18,9 @@ use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, Mms2}; use embassy_stm32::timer::low_level::CountingMode; use embassy_stm32::{Config, interrupt}; use embassy_sync::blocking_mutex::CriticalSectionMutex; -use {critical_section, defmt_rtt as _, panic_probe as _}; +use {defmt_rtt as _, panic_probe as _}; -static ADC1_HANDLE: CriticalSectionMutex>>> = +static ADC1_HANDLE: CriticalSectionMutex>>> = CriticalSectionMutex::new(RefCell::new(None)); /// This example showcases how to use both regular ADC conversions with DMA and injected ADC @@ -78,17 +78,17 @@ async fn main(_spawner: embassy_executor::Spawner) { // Configure regular conversions with DMA let adc1 = Adc::new(p.ADC1); - let mut vrefint_channel = adc1.enable_vrefint().degrade_adc(); - let mut pa0 = p.PC1.degrade_adc(); + let vrefint_channel = adc1.enable_vrefint().degrade_adc(); + let pa0 = p.PC1.degrade_adc(); let regular_sequence = [ - (&mut vrefint_channel, SampleTime::CYCLES247_5), - (&mut pa0, SampleTime::CYCLES247_5), + (vrefint_channel, SampleTime::CYCLES247_5), + (pa0, SampleTime::CYCLES247_5), ] .into_iter(); // Configurations of Injected ADC measurements - let mut pa2 = p.PA2.degrade_adc(); - let injected_sequence = [(&mut pa2, SampleTime::CYCLES247_5)].into_iter(); + let pa2 = p.PA2.degrade_adc(); + let injected_sequence = [(pa2, SampleTime::CYCLES247_5)]; // Configure DMA for retrieving regular ADC measurements let dma1_ch1 = p.DMA1_CH1; @@ -111,6 +111,7 @@ async fn main(_spawner: embassy_executor::Spawner) { RegularConversionMode::Triggered(regular_trigger), injected_sequence, injected_trigger, + true, ); // Store ADC globally to allow access from ADC interrupt -- cgit From f4746467438b9d385f03b85823e0eb6ce9f49ee9 Mon Sep 17 00:00:00 2001 From: Jakob Date: Fri, 7 Nov 2025 15:54:04 +0100 Subject: cargo fmt --- examples/stm32g4/src/bin/adc_injected_and_regular.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/stm32g4/src/bin/adc_injected_and_regular.rs b/examples/stm32g4/src/bin/adc_injected_and_regular.rs index c929ca3bf..eb6813459 100644 --- a/examples/stm32g4/src/bin/adc_injected_and_regular.rs +++ b/examples/stm32g4/src/bin/adc_injected_and_regular.rs @@ -9,8 +9,9 @@ use core::cell::RefCell; use defmt::info; -use embassy_stm32::adc::InjectedAdc; -use embassy_stm32::adc::{Adc, AdcChannel as _, ConversionTrigger, Exten, RegularConversionMode, SampleTime}; +use embassy_stm32::adc::{ + Adc, AdcChannel as _, ConversionTrigger, Exten, InjectedAdc, RegularConversionMode, SampleTime +}; use embassy_stm32::interrupt::typelevel::{ADC1_2, Interrupt}; use embassy_stm32::peripherals::ADC1; use embassy_stm32::time::Hertz; -- cgit From 85a07311544eee72b6aef8cbae161fa18b62f18e Mon Sep 17 00:00:00 2001 From: Jakob Date: Fri, 7 Nov 2025 15:56:04 +0100 Subject: fmt again --- examples/stm32g4/src/bin/adc_injected_and_regular.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32g4/src/bin/adc_injected_and_regular.rs b/examples/stm32g4/src/bin/adc_injected_and_regular.rs index eb6813459..3ae2ff064 100644 --- a/examples/stm32g4/src/bin/adc_injected_and_regular.rs +++ b/examples/stm32g4/src/bin/adc_injected_and_regular.rs @@ -10,7 +10,7 @@ use core::cell::RefCell; use defmt::info; use embassy_stm32::adc::{ - Adc, AdcChannel as _, ConversionTrigger, Exten, InjectedAdc, RegularConversionMode, SampleTime + Adc, AdcChannel as _, ConversionTrigger, Exten, InjectedAdc, RegularConversionMode, SampleTime, }; use embassy_stm32::interrupt::typelevel::{ADC1_2, Interrupt}; use embassy_stm32::peripherals::ADC1; -- cgit From 126f34e93145a43390193f07a3f1504a42204a57 Mon Sep 17 00:00:00 2001 From: Jakob Date: Fri, 7 Nov 2025 16:14:44 +0100 Subject: Restore cargo toml for examples --- examples/stm32g4/.cargo/config.toml | 20 ++++---------------- examples/stm32g4/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 17 deletions(-) (limited to 'examples') diff --git a/examples/stm32g4/.cargo/config.toml b/examples/stm32g4/.cargo/config.toml index 52b5a7bc8..d28ad069e 100644 --- a/examples/stm32g4/.cargo/config.toml +++ b/examples/stm32g4/.cargo/config.toml @@ -1,21 +1,9 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# Change this runner as required for your MCU. -runner = [ - "probe-rs", - "run", - "--chip", - "STM32G431VBTx", - "--speed", - "5000", - "--preverify", - "--log-format", - "{t} [{L}] {s}", -] - +# replace STM32G071C8Rx with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32G484VETx" [build] -target = "thumbv7em-none-eabihf" +target = "thumbv7em-none-eabi" [env] -DEFMT_LOG = "info" -DEFMT_RTT_BUFFER_SIZE = "4096" +DEFMT_LOG = "trace" diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 9089ec0d5..8bbeb594c 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] # Change stm32g491re to your chip name, if necessary. -embassy-stm32 = { path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g431vb", "memory-x", "unstable-pac", "exti"] } +embassy-stm32 = { path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -- cgit From 0df07c14b649c122cd639d7bb5f00ecc99ca1a5c Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 9 Nov 2025 17:24:56 -0600 Subject: update stm32-fmc --- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h755cm4/Cargo.toml | 2 +- examples/stm32h755cm7/Cargo.toml | 2 +- examples/stm32h7b0/Cargo.toml | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 475ba7e8a..512186c3d 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -29,7 +29,7 @@ panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } critical-section = "1.1" micromath = "2.0.0" -stm32-fmc = "0.3.0" +stm32-fmc = "0.4.0" embedded-storage = "0.3.1" static_cell = "2" diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 5993110de..09b734054 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -30,7 +30,7 @@ panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } critical-section = "1.1" micromath = "2.0.0" -stm32-fmc = "0.3.0" +stm32-fmc = "0.4.0" embedded-storage = "0.3.1" static_cell = "2" chrono = { version = "^0.4", default-features = false } diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index b5c313523..d69f0228e 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -30,7 +30,7 @@ panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } critical-section = "1.1" micromath = "2.0.0" -stm32-fmc = "0.3.0" +stm32-fmc = "0.4.0" embedded-storage = "0.3.1" static_cell = "2" chrono = { version = "^0.4", default-features = false } diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index 7a1519aae..f4e1e53b7 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -30,7 +30,7 @@ panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } critical-section = "1.1" micromath = "2.0.0" -stm32-fmc = "0.3.0" +stm32-fmc = "0.4.0" embedded-storage = "0.3.1" static_cell = "2" chrono = { version = "^0.4", default-features = false } diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml index 4cd7b84e5..0509d394d 100644 --- a/examples/stm32h7b0/Cargo.toml +++ b/examples/stm32h7b0/Cargo.toml @@ -29,7 +29,7 @@ panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } critical-section = "1.1" micromath = "2.0.0" -stm32-fmc = "0.3.0" +stm32-fmc = "0.4.0" embedded-storage = "0.3.1" static_cell = "2" chrono = { version = "^0.4", default-features = false } diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index 445916972..ab525ad91 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -29,7 +29,7 @@ panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } critical-section = "1.1" micromath = "2.0.0" -stm32-fmc = "0.3.0" +stm32-fmc = "0.4.0" embedded-storage = "0.3.1" static_cell = "2" chrono = { version = "^0.4", default-features = false } -- cgit