diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index c10af171..d4afbb8f 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -15,5 +15,5 @@ panic-probe = "0.3" embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f091rc", "time-driver-any"] } - +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti"] } +static_cell = "1.0" diff --git a/examples/stm32f0/src/bin/button_controlled_blink.rs b/examples/stm32f0/src/bin/button_controlled_blink.rs new file mode 100644 index 00000000..e1f22343 --- /dev/null +++ b/examples/stm32f0/src/bin/button_controlled_blink.rs @@ -0,0 +1,64 @@ +//! This example showcases how to create task + +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use core::sync::atomic::{AtomicU32, Ordering}; + +use defmt::info; +use embassy_executor::Spawner; +use embassy_stm32::exti::ExtiInput; +use embassy_stm32::gpio::{AnyPin, Input, Level, Output, Pin, Pull, Speed}; +use embassy_time::{Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +static BLINK_MS: AtomicU32 = AtomicU32::new(0); + +#[embassy_executor::task] +async fn led_task(led: AnyPin) { + // Configure the LED pin as a push pull ouput and obtain handler. + // On the Nucleo F091RC theres an on-board LED connected to pin PA5. + let mut led = Output::new(led, Level::Low, Speed::Low); + + loop { + let del = BLINK_MS.load(Ordering::Relaxed); + info!("Value of del is {}", del); + Timer::after(Duration::from_millis(del.into())).await; + info!("LED toggling"); + led.toggle(); + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + // Initialize and create handle for devicer peripherals + let p = embassy_stm32::init(Default::default()); + + // Configure the button pin and obtain handler. + // On the Nucleo F091RC there is a button connected to pin PC13. + let button = Input::new(p.PC13, Pull::None); + let mut button = ExtiInput::new(button, p.EXTI13); + + // Create and initialize a delay variable to manage delay loop + let mut del_var = 2000; + + // Blink duration value to global context + BLINK_MS.store(del_var, Ordering::Relaxed); + + // Spawn LED blinking task + spawner.spawn(led_task(p.PA5.degrade())).unwrap(); + + loop { + // Check if button got pressed + button.wait_for_rising_edge().await; + info!("rising_edge"); + del_var = del_var - 200; + // If updated delay value drops below 200 then reset it back to starting value + if del_var < 200 { + del_var = 2000; + } + // Updated delay value to global context + BLINK_MS.store(del_var, Ordering::Relaxed); + } +} diff --git a/examples/stm32f0/src/bin/button_exti.rs b/examples/stm32f0/src/bin/button_exti.rs new file mode 100644 index 00000000..40c0d584 --- /dev/null +++ b/examples/stm32f0/src/bin/button_exti.rs @@ -0,0 +1,27 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::exti::ExtiInput; +use embassy_stm32::gpio::{Input, Pull}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + // Initialize and create handle for devicer peripherals + let p = embassy_stm32::init(Default::default()); + // Configure the button pin and obtain handler. + // On the Nucleo F091RC there is a button connected to pin PC13. + let button = Input::new(p.PC13, Pull::Down); + let mut button = ExtiInput::new(button, p.EXTI13); + + 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/stm32f0/src/bin/priority.rs b/examples/stm32f0/src/bin/priority.rs new file mode 100644 index 00000000..7fed6a77 --- /dev/null +++ b/examples/stm32f0/src/bin/priority.rs @@ -0,0 +1,139 @@ +//! This example showcases how to create multiple Executor instances to run tasks at +//! different priority levels. +//! +//! Low priority executor runs in thread mode (not interrupt), and uses `sev` for signaling +//! there's work in the queue, and `wfe` for waiting for work. +//! +//! Medium and high priority executors run in two interrupts with different priorities. +//! Signaling work is done by pending the interrupt. No "waiting" needs to be done explicitly, since +//! when there's work the interrupt will trigger and run the executor. +//! +//! Sample output below. Note that high priority ticks can interrupt everything else, and +//! medium priority computations can interrupt low priority computations, making them to appear +//! to take significantly longer time. +//! +//! ```not_rust +//! [med] Starting long computation +//! [med] done in 992 ms +//! [high] tick! +//! [low] Starting long computation +//! [med] Starting long computation +//! [high] tick! +//! [high] tick! +//! [med] done in 993 ms +//! [med] Starting long computation +//! [high] tick! +//! [high] tick! +//! [med] done in 993 ms +//! [low] done in 3972 ms +//! [med] Starting long computation +//! [high] tick! +//! [high] tick! +//! [med] done in 993 ms +//! ``` +//! +//! For comparison, try changing the code so all 3 tasks get spawned on the low priority executor. +//! You will get an output like the following. Note that no computation is ever interrupted. +//! +//! ```not_rust +//! [high] tick! +//! [med] Starting long computation +//! [med] done in 496 ms +//! [low] Starting long computation +//! [low] done in 992 ms +//! [med] Starting long computation +//! [med] done in 496 ms +//! [high] tick! +//! [low] Starting long computation +//! [low] done in 992 ms +//! [high] tick! +//! [med] Starting long computation +//! [med] done in 496 ms +//! [high] tick! +//! ``` +//! + +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use cortex_m_rt::entry; +use defmt::*; +use embassy_stm32::executor::{Executor, InterruptExecutor}; +use embassy_stm32::interrupt; +use embassy_stm32::interrupt::InterruptExt; +use embassy_time::{Duration, Instant, Timer}; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::task] +async fn run_high() { + loop { + // info!(" [high] tick!"); + Timer::after(Duration::from_ticks(27374)).await; + } +} + +#[embassy_executor::task] +async fn run_med() { + loop { + let start = Instant::now(); + info!(" [med] Starting long computation"); + + // Spin-wait to simulate a long CPU computation + cortex_m::asm::delay(8_000_000); // ~1 second + + let end = Instant::now(); + let ms = end.duration_since(start).as_ticks() / 33; + info!(" [med] done in {} ms", ms); + + Timer::after(Duration::from_ticks(23421)).await; + } +} + +#[embassy_executor::task] +async fn run_low() { + loop { + let start = Instant::now(); + info!("[low] Starting long computation"); + + // Spin-wait to simulate a long CPU computation + cortex_m::asm::delay(16_000_000); // ~2 seconds + + let end = Instant::now(); + let ms = end.duration_since(start).as_ticks() / 33; + info!("[low] done in {} ms", ms); + + Timer::after(Duration::from_ticks(32983)).await; + } +} + +static EXECUTOR_HIGH: StaticCell> = StaticCell::new(); +static EXECUTOR_MED: StaticCell> = StaticCell::new(); +static EXECUTOR_LOW: StaticCell = StaticCell::new(); + +#[entry] +fn main() -> ! { + // Initialize and create handle for devicer peripherals + let _p = embassy_stm32::init(Default::default()); + + // High-priority executor: USART1, priority level 6 + let irq = interrupt::take!(USART1); + irq.set_priority(interrupt::Priority::P6); + let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq)); + let spawner = executor.start(); + unwrap!(spawner.spawn(run_high())); + + // Medium-priority executor: USART2, priority level 7 + let irq = interrupt::take!(USART2); + irq.set_priority(interrupt::Priority::P7); + let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq)); + let spawner = executor.start(); + unwrap!(spawner.spawn(run_med())); + + // Low priority executor: runs in thread mode, using WFE/SEV + let executor = EXECUTOR_LOW.init(Executor::new()); + executor.run(|spawner| { + unwrap!(spawner.spawn(run_low())); + }); +} diff --git a/examples/stm32f0/src/bin/wdg.rs b/examples/stm32f0/src/bin/wdg.rs new file mode 100644 index 00000000..80e76f90 --- /dev/null +++ b/examples/stm32f0/src/bin/wdg.rs @@ -0,0 +1,25 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::wdg::IndependentWatchdog; +use embassy_time::{Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + // Initialize and create handle for devicer peripherals + let p = embassy_stm32::init(Default::default()); + // Configure the independent watchdog timer + let mut wdg = IndependentWatchdog::new(p.IWDG, 20_000_00); + + info!("Watchdog start"); + unsafe { wdg.unleash() }; + + loop { + Timer::after(Duration::from_secs(1)).await; + unsafe { wdg.pet() }; + } +}