use core::sync::atomic::{AtomicU32, Ordering};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TraceTransport {
None,
#[cfg(feature = "rtt-trace")]
Rtt,
#[cfg(feature = "itm-trace")]
Itm,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CycleSample {
pub label: &'static str,
pub cycles: u32,
}
static LAST_SAMPLE_CYCLES: AtomicU32 = AtomicU32::new(0);
#[cfg(all(feature = "dwt-profiler", target_arch = "arm"))]
const DEMCR: *mut u32 = 0xE000_EDFC as *mut u32;
#[cfg(all(feature = "dwt-profiler", target_arch = "arm"))]
const DWT_CTRL: *mut u32 = 0xE000_1000 as *mut u32;
#[cfg(all(feature = "dwt-profiler", target_arch = "arm"))]
const DWT_CYCCNT: *mut u32 = 0xE000_1004 as *mut u32;
#[cfg(all(feature = "dwt-profiler", target_arch = "arm"))]
pub fn init_dwt_cycle_counter() {
unsafe {
let demcr = core::ptr::read_volatile(DEMCR);
core::ptr::write_volatile(DEMCR, demcr | (1 << 24));
let dwt_ctrl = core::ptr::read_volatile(DWT_CTRL);
core::ptr::write_volatile(DWT_CTRL, dwt_ctrl | 1);
}
}
#[cfg(not(all(feature = "dwt-profiler", target_arch = "arm")))]
pub fn init_dwt_cycle_counter() {}
#[cfg(all(feature = "dwt-profiler", target_arch = "arm"))]
pub fn read_cycle_counter() -> Option<u32> {
Some(unsafe { core::ptr::read_volatile(DWT_CYCCNT) })
}
#[cfg(not(all(feature = "dwt-profiler", target_arch = "arm")))]
pub fn read_cycle_counter() -> Option<u32> {
None
}
pub fn sample_cycles(label: &'static str, start_cycles: u32, end_cycles: u32) -> CycleSample {
let cycles = end_cycles.wrapping_sub(start_cycles);
LAST_SAMPLE_CYCLES.store(cycles, Ordering::Relaxed);
CycleSample { label, cycles }
}
pub fn last_sample_cycles() -> u32 {
LAST_SAMPLE_CYCLES.load(Ordering::Relaxed)
}
pub fn emit_trace(_sample: CycleSample) {
#[cfg(feature = "rtt-trace")]
{
#[cfg(feature = "std")]
{
std::println!(
"RTT_TRACE label={} cycles={}",
_sample.label,
_sample.cycles
);
}
}
#[cfg(feature = "itm-trace")]
{
#[cfg(feature = "std")]
{
std::println!(
"ITM_TRACE label={} cycles={}",
_sample.label,
_sample.cycles
);
}
}
}