85 lines
2.6 KiB
Rust
85 lines
2.6 KiB
Rust
// 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);
|
|
}
|
|
}
|
|
}
|