Open
Description
Below is a test case demonstrating the issue.
I think what's happening is that the two high priority tasks are fighting over the mutex, preventing the low priority task from making forward progress so that it can release the mutex.
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use defmt_rtt as _;
use embassy_stm32::{
executor::Executor, executor::InterruptExecutor, interrupt, interrupt::InterruptExt, time,
};
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::mutex::Mutex;
use embassy_time::{Duration, Timer};
use static_cell::StaticCell;
static MUTEX: Mutex<CriticalSectionRawMutex, u32> = Mutex::new(0);
#[cortex_m_rt::entry]
fn main() -> ! {
/* clocks */
let mut cfg = embassy_stm32::Config::default();
cfg.rcc.hse = Some(time::mhz(8));
cfg.rcc.sys_ck = Some(time::mhz(180));
embassy_stm32::init(cfg);
/* enable flash cache & prefetching */
unsafe {
embassy_stm32::pac::FLASH.acr().modify(|w| {
w.set_dcen(true);
w.set_icen(true);
w.set_prften(true);
});
}
/* high priority */
let irq = interrupt::take!(UART4);
irq.set_priority(interrupt::Priority::P14);
static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::UART4>> = StaticCell::new();
let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
let spawner = executor.start();
defmt::unwrap!(spawner.spawn(high_task(1)));
defmt::unwrap!(spawner.spawn(high_task(2)));
/* low priority */
static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
let executor = EXECUTOR_LOW.init(Executor::new());
executor.run(|spawner| {
defmt::unwrap!(spawner.spawn(low_task()));
});
}
#[embassy_executor::task]
async fn low_task() {
loop {
defmt::println!("low priority task locking mutex");
let mut m = MUTEX.lock().await;
defmt::println!("low priority task got mutex");
for i in 0..10 {
cortex_m::asm::delay(10000000); // ~100 millisecond
defmt::println!("low priority task busy {}", i);
}
*m += 1;
defmt::println!("low priority task releasing mutex");
}
}
#[embassy_executor::task(pool_size=2)]
async fn high_task(i: usize) {
defmt::println!("high priority task {} waiting", i);
Timer::after(Duration::from_millis(500)).await;
loop {
defmt::println!("high priority task {} locking mutex", i);
let mut m = MUTEX.lock().await;
defmt::println!("high priority task {} got mutex", i);
Timer::after(Duration::from_millis(500)).await;
*m += 1;
defmt::println!("high priority task {} releasing mutex", i);
}
}
#[panic_handler]
fn panic(panic: &core::panic::PanicInfo) -> ! {
defmt::error!("{}", defmt::Display2Format(panic));
cortex_m::asm::udf();
}