// src/bin/main.rs #![no_std] #![no_main] use core::sync::atomic::{AtomicUsize, Ordering}; use defmt::*; use embassy_executor::Spawner; use embassy_stm32::pac; use embassy_stm32::interrupt::InterruptExt; use embassy_stm32::timer::low_level::{CountingMode, Timer as LLTimer}; use embassy_stm32::time::khz; use embassy_stm32::interrupt; use {defmt_rtt as _, panic_probe as _}; // Pointer to the local `counter` so the ISR can read it with zero per-iteration overhead. static COUNTER_PTR: AtomicUsize = AtomicUsize::new(0); // NVIC handler for TIM2 #[interrupt] fn TIM2() { // Clear UIF, stop the timer pac::TIM2.sr().modify(|r| r.set_uif(false)); pac::TIM2.cr1().modify(|r| r.set_cen(false)); // Snapshot the counter that the loop has been incrementing let ptr = COUNTER_PTR.load(Ordering::Relaxed) as *const u32; let count = unsafe { core::ptr::read_volatile(ptr) }; info!("10 seconds elapsed, counter = {}", count); // Halt loop { cortex_m::asm::bkpt(); } } #[embassy_executor::main] async fn main(_spawner: Spawner) { info!("Start"); let p = embassy_stm32::init(Default::default()); // Configure TIM2 let mut tim2 = LLTimer::new(p.TIM2); tim2.stop(); tim2.set_counting_mode(CountingMode::EdgeAlignedUp); // Make the timer tick at 10 kHz. Driver derives PSC from RCC, so timing is exact. tim2.set_tick_freq(khz(10)); // 10 seconds => 10_000 ticks/s * 10 s = 100_000 ticks. ARR is inclusive: set to 100_000 - 1. tim2.set_max_compare_value(100_000 - 1); // One-pulse mode (auto-stop after the first update event) tim2.regs_core().cr1().modify(|r| r.set_opm(true)); // Ensure no pending UIF from the UG we generated during PSC/ARR programming. // Important: do this BEFORE enabling UIE/NVIC to avoid an immediate ISR. let _ = tim2.clear_update_interrupt(); // Enable update interrupt, reset counter to 0. Do not start yet. tim2.enable_update_interrupt(true); tim2.reset(); // Expose the address of the loop counter BEFORE enabling the NVIC so the ISR // never runs before COUNTER_PTR is valid. let mut counter: u32 = 0; COUNTER_PTR.store(&counter as *const u32 as usize, Ordering::Relaxed); // Unpend and enable NVIC for TIM2, then start the timer. unsafe { embassy_stm32::interrupt::TIM2.unpend(); embassy_stm32::interrupt::TIM2.enable(); } tim2.start(); // Tight CPU loop for benchmarking loop { counter = counter.wrapping_add(1); if counter % 10000 == 0 { info!("CPU doing other work: {}", counter); } } }