Skip to content

Commit

Permalink
fix cyccnt extension based on cortex-m change
Browse files Browse the repository at this point in the history
fire just before overflow instead and don't reset cyccnt

latest cortex-m changes

make `new` falible

remove debug code
  • Loading branch information
TDHolmes committed Jul 2, 2022
1 parent 731f32f commit 2aedaf2
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 19 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ codegen-units = 1
debug = true
lto = true
opt-level = 'z'

[patch.crates-io]
cortex-m = { git = 'https://github.com/TDHolmes/cortex-m', package = 'cortex-m', branch = 'comparator-changes-only' }
2 changes: 1 addition & 1 deletion embedded-profiling-examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ default = ["panic_persist"]
usb = ["usb-device", "usbd-serial"]
panic_persist = ["panic-persist"]
panic_halt = ["panic-halt"]
extended = ["ep-systick/extended", "embedded-profiling/container-u64"]
extended = ["ep-systick/extended", "ep-dwt/extended", "embedded-profiling/container-u64"]

[[bin]]
name = "delay_usb_dwt"
Expand Down
2 changes: 1 addition & 1 deletion embedded-profiling-examples/src/bin/delay_usb_dwt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ fn main() -> ! {
// initialize our profiling timer & structure
log::debug!("initializing our tracing stuff");
let dwt_profiler = cortex_m::singleton!(: ep_dwt::DwtProfiler<CORE_FREQ> =
ep_dwt::DwtProfiler::new(&mut core.DCB, core.DWT, CORE_FREQ))
ep_dwt::DwtProfiler::new(&mut core.DCB, core.DWT, CORE_FREQ).unwrap())
.unwrap();
unsafe {
ep::set_profiler(dwt_profiler).unwrap();
Expand Down
80 changes: 63 additions & 17 deletions ep-dwt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
//! let mut core = CorePeripherals::take().unwrap();
//! // (...)
//! let dwt_profiler = cortex_m::singleton!(: ep_dwt::DwtProfiler::<CORE_FREQ> =
//! ep_dwt::DwtProfiler::<CORE_FREQ>::new(&mut core.DCB, core.DWT, CORE_FREQ))
//! ep_dwt::DwtProfiler::<CORE_FREQ>::new(&mut core.DCB, core.DWT, CORE_FREQ).unwrap())
//! .unwrap();
//! unsafe {
//! embedded_profiling::set_profiler(dwt_profiler).unwrap();
Expand Down Expand Up @@ -65,6 +65,16 @@ static ROLLOVER_COUNT: AtomicU32 = AtomicU32::new(0);
// For extended mode to work, we really need a u64 container. Double check this.
static_assertions::assert_type_eq_all!(EPContainer, u64);

#[derive(Debug)]
/// Things that can go wrong when configuring the [`DWT`] hardware
pub enum DwtProfilerError {
/// [`cortex_m::peripheral::DWT::has_cycle_counter()`] reported that this hardware
/// does not support cycle count hardware
CycleCounterUnsupported,
/// We failed to configure cycle count compare for the `extended` feature
CycleCounterInvalidSettings,
}

/// DWT trace unit implementing [`EmbeddedProfiler`].
///
/// The frequency of the [`DWT`] is encoded using the parameter `FREQ`.
Expand All @@ -80,37 +90,73 @@ impl<const FREQ: u32> DwtProfiler<FREQ> {
///
/// # Panics
/// asserts that the compile time constant `FREQ` matches the runtime provided `sysclk`
#[must_use]
pub fn new(dcb: &mut DCB, mut dwt: DWT, sysclk: u32) -> Self {
pub fn new(dcb: &mut DCB, mut dwt: DWT, sysclk: u32) -> Result<Self, DwtProfilerError> {
assert!(FREQ == sysclk);

// check if our HW supports it
if !dwt.has_cycle_counter() {
return Err(DwtProfilerError::CycleCounterUnsupported);
}

// Enable the DWT block
dcb.enable_trace();
#[cfg(feature = "extended")]
// Enable DebugMonitor exceptions to fire to track overflows
unsafe {
dcb.demcr.modify(|f| f | 1 << 16);
}
DWT::unlock();

// reset cycle count and enable it to run
unsafe { dwt.cyccnt.write(0) };
dwt.enable_cycle_counter();

Self { dwt }
if cfg!(feature = "extended") {
use cortex_m::peripheral::dwt::{ComparatorFunction, CycleCountSettings, EmitOption};

// Enable DebugMonitor exceptions to fire to track overflows
dcb.enable_debug_monitor();
dwt.comp0
.configure(ComparatorFunction::CycleCount(CycleCountSettings {
emit: EmitOption::WatchpointDebugEvent,
compare: 4_294_967_295, // just before overflow (2**32 - 1)
}))
.map_err(|_conf_err| DwtProfilerError::CycleCounterInvalidSettings)?
}

Ok(Self { dwt })
}
}

impl<const FREQ: u32> EmbeddedProfiler for DwtProfiler<FREQ> {
fn read_clock(&self) -> EPInstant {
// get the cycle count and add the rollover if we're extended
#[allow(unused_mut)]
let mut count = EPContainer::from(self.dwt.cyccnt.read());
#[cfg(feature = "extended")]
{
count += EPContainer::from(ROLLOVER_COUNT.load(Ordering::Relaxed))
* EPContainer::from(u32::MAX);
}
let count: EPContainer = {
#[cfg(feature = "extended")]
{
/// Every time we roll over, we should add 2**32
const ROLLOVER_AMOUNT: EPContainer = 0x1_0000_0000;

// read the clock & ROLLOVER_COUNT. We read `cyccnt` twice because we need to detect
// if we've rolled over, and if we have make sure we have the right value for ROLLOVER_COUNT.
let first = self.dwt.cyccnt.read();
let rollover: EPContainer = ROLLOVER_COUNT.load(Ordering::Acquire).into();
let second = self.dwt.cyccnt.read();

if first < second {
// The usual case. We did not roll over between the first and second reading,
// and because of that we also know we got a valid read on ROLLOVER_COUNT.
rollover * ROLLOVER_AMOUNT + EPContainer::from(first)
} else {
// we rolled over sometime between the first and second read. We may or may not have
// caught the right ROLLOVER_COUNT, so grab that again and then use the second reading.
let rollover: EPContainer = ROLLOVER_COUNT.load(Ordering::Acquire).into();

rollover * ROLLOVER_AMOUNT + EPContainer::from(second)
}
}

#[cfg(not(feature = "extended"))]
{
// We aren't trying to be fancy here, we don't care if this rolled over from the last read.
EPContainer::from(self.dwt.cyccnt.read())
}
};

// convert count and return the instant
embedded_profiling::convert_instant(EPInstantGeneric::<1, FREQ>::from_ticks(count))
Expand All @@ -125,5 +171,5 @@ impl<const FREQ: u32> EmbeddedProfiler for DwtProfiler<FREQ> {
#[exception]
#[allow(non_snake_case)]
fn DebugMonitor() {
ROLLOVER_COUNT.fetch_add(1, Ordering::Relaxed);
ROLLOVER_COUNT.fetch_add(1, Ordering::Release);
}

0 comments on commit 2aedaf2

Please sign in to comment.