From 530ea9a0e504983478827ff8c4184a64910ac0b5 Mon Sep 17 00:00:00 2001 From: Dominic Date: Fri, 6 Oct 2023 09:45:43 +0200 Subject: [PATCH] handle button press to enable/disable blinking --- Cargo.lock | 39 +++++++++++++++++++++++++---- Cargo.toml | 3 ++- src/main.rs | 55 ++++++++++++++++++++++++++++++++-------- src/static_mutex.rs | 61 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 142 insertions(+), 16 deletions(-) create mode 100644 src/static_mutex.rs diff --git a/Cargo.lock b/Cargo.lock index 4b529c9..6d32835 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -229,6 +229,7 @@ dependencies = [ "defmt-rtt", "embassy-executor", "embassy-stm32", + "embassy-sync 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "embassy-time 0.1.3", "panic-probe", ] @@ -240,7 +241,7 @@ source = "git+https://github.com/embassy-rs/embassy#42176b1a3addde3a6daad0662d36 dependencies = [ "defmt", "embassy-futures", - "embassy-sync", + "embassy-sync 0.3.0 (git+https://github.com/embassy-rs/embassy)", "embassy-time 0.1.4", "embedded-hal 0.2.7", "embedded-hal 1.0.0-rc.1", @@ -320,14 +321,14 @@ dependencies = [ "embassy-futures", "embassy-hal-internal", "embassy-net-driver", - "embassy-sync", + "embassy-sync 0.3.0 (git+https://github.com/embassy-rs/embassy)", "embassy-time 0.1.4", "embassy-usb-driver", "embedded-hal 0.2.7", "embedded-hal 1.0.0-rc.1", "embedded-hal-async", - "embedded-io", - "embedded-io-async", + "embedded-io 0.6.0", + "embedded-io-async 0.6.0", "embedded-storage", "embedded-storage-async", "futures", @@ -342,6 +343,19 @@ dependencies = [ "vcell", ] +[[package]] +name = "embassy-sync" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0525b466ca3ace30b57f2db868a35215dfaecd038d8668cb2db03feb7c069a0" +dependencies = [ + "cfg-if", + "critical-section 1.1.2", + "embedded-io-async 0.5.0", + "futures-util", + "heapless", +] + [[package]] name = "embassy-sync" version = "0.3.0" @@ -417,6 +431,12 @@ dependencies = [ "embedded-hal 1.0.0-rc.1", ] +[[package]] +name = "embedded-io" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bbadc628dc286b9ae02f0cb0f5411c056eb7487b72f0083203f115de94060" + [[package]] name = "embedded-io" version = "0.6.0" @@ -426,6 +446,15 @@ dependencies = [ "defmt", ] +[[package]] +name = "embedded-io-async" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1394754ad749a560b25a0c70dcd2b66a450824a1311fc475bb2ccbfabe7f8414" +dependencies = [ + "embedded-io 0.5.0", +] + [[package]] name = "embedded-io-async" version = "0.6.0" @@ -433,7 +462,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de03527d6fb488b2d7c7a4dc81dfb6a657efe264256bfc70bb899746821666b1" dependencies = [ "defmt", - "embedded-io", + "embedded-io 0.6.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b37ae4a..fcda0fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ defmt = "0.3" defmt-rtt = "0.3" # potentially use executor-interrupt instead of executor-thread for cortex-m architectures embassy-executor = { version = "0.3", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread", "nightly"] } -embassy-stm32 = { git = "https://github.com/embassy-rs/embassy", features = ["defmt", "time", "time-driver-tim2", "stm32l476rg", "nightly"] } +embassy-stm32 = { git = "https://github.com/embassy-rs/embassy", features = ["defmt", "exti", "time", "time-driver-tim2", "stm32l476rg", "nightly"] } +embassy-sync = { version = "0.3", features = ["nightly"] } embassy-time = { version = "0.1.3", features = ["defmt", "nightly"] } panic-probe = { version = "0.3", features = ["print-defmt"] } diff --git a/src/main.rs b/src/main.rs index 783a23d..f36acb7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,31 +1,66 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait)] +#![feature(async_fn_track_caller, type_alias_impl_trait)] +#![warn(rust_2018_idioms)] +#![forbid(elided_lifetimes_in_paths, unsafe_code)] + +mod static_mutex; use defmt::*; use defmt_rtt as _; use embassy_executor::Spawner; use embassy_stm32::{ - gpio::{Level, Output, Speed}, - peripherals::PA5 + exti::ExtiInput, + gpio::{Input, Level, Output, Pull, Speed}, + peripherals::{PA5, PC13} }; +use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_time::{Duration, Timer}; -use panic_probe as _; // global logger +use panic_probe as _; +use static_mutex::StaticMutex; + +type Mutex = embassy_sync::mutex::Mutex; +type MutexGuard<'a, T> = embassy_sync::mutex::MutexGuard<'a, ThreadModeRawMutex, T>; + +type NucleoLed = Output<'static, PA5>; +type NucleoButton = ExtiInput<'static, PC13>; + +static LED: StaticMutex = StaticMutex::new(); +static BLINKING: Mutex = Mutex::new(true); #[embassy_executor::task] -async fn blinker(mut led: Output<'static, PA5>, interval: Duration) { +async fn blinker(interval: Duration) { loop { - led.set_high(); - Timer::after(interval).await; - led.set_low(); + if *BLINKING.lock().await { + LED.lock().await.toggle(); + } Timer::after(interval).await; } } +#[embassy_executor::task] +async fn button_handler(mut button: NucleoButton) { + loop { + button.wait_for_falling_edge().await; + let mut blinking = BLINKING.lock().await; + if *blinking { + info!("Disable blinking"); + LED.lock().await.set_low(); + *blinking = false; + } else { + info!("Enable blinking"); + *blinking = true; + } + } +} + #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let led = Output::new(p.PA5, Level::Low, Speed::Low); - unwrap!(spawner.spawn(blinker(led, Duration::from_millis(500)))); + LED.init(Output::new(p.PA5, Level::Low, Speed::Low)).await; + let button = ExtiInput::new(Input::new(p.PC13, Pull::Up), p.EXTI13); + + unwrap!(spawner.spawn(blinker(Duration::from_millis(500)))); + unwrap!(spawner.spawn(button_handler(button))); } diff --git a/src/static_mutex.rs b/src/static_mutex.rs new file mode 100644 index 0000000..65a19b1 --- /dev/null +++ b/src/static_mutex.rs @@ -0,0 +1,61 @@ +use crate::{Mutex, MutexGuard}; +use core::ops::{Deref, DerefMut}; + +enum Value { + Full(T), + Empty +} + +pub struct StaticMutex { + value: Mutex> +} + +impl StaticMutex { + pub const fn new() -> Self { + Self { + value: Mutex::new(Value::Empty) + } + } + + #[track_caller] + pub async fn init(&self, new: T) { + let mut value = self.value.lock().await; + if !matches!(*value, Value::Empty) { + panic!("Cannot initialise StaticMutex more than once"); + } + *value = Value::Full(new); + } + + #[track_caller] + pub async fn lock(&self) -> StaticMutexLockGuard<'_, T> { + let inner = self.value.lock().await; + if matches!(*inner, Value::Empty) { + panic!("This StaticMutex has not been initialised yet"); + } + StaticMutexLockGuard { inner } + } +} + +pub struct StaticMutexLockGuard<'a, T> { + inner: MutexGuard<'a, Value> +} + +impl Deref for StaticMutexLockGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + match self.inner.deref() { + Value::Full(ref value) => value, + _ => unreachable!() + } + } +} + +impl DerefMut for StaticMutexLockGuard<'_, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + match self.inner.deref_mut() { + Value::Full(ref mut value) => value, + _ => unreachable!() + } + } +}