Skip to content

Commit 2aedaf2

Browse files
committed
fix cyccnt extension based on cortex-m change
fire just before overflow instead and don't reset cyccnt latest cortex-m changes make `new` falible remove debug code
1 parent 731f32f commit 2aedaf2

File tree

4 files changed

+68
-19
lines changed

4 files changed

+68
-19
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,6 @@ codegen-units = 1
1313
debug = true
1414
lto = true
1515
opt-level = 'z'
16+
17+
[patch.crates-io]
18+
cortex-m = { git = 'https://github.com/TDHolmes/cortex-m', package = 'cortex-m', branch = 'comparator-changes-only' }

embedded-profiling-examples/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ default = ["panic_persist"]
3131
usb = ["usb-device", "usbd-serial"]
3232
panic_persist = ["panic-persist"]
3333
panic_halt = ["panic-halt"]
34-
extended = ["ep-systick/extended", "embedded-profiling/container-u64"]
34+
extended = ["ep-systick/extended", "ep-dwt/extended", "embedded-profiling/container-u64"]
3535

3636
[[bin]]
3737
name = "delay_usb_dwt"

embedded-profiling-examples/src/bin/delay_usb_dwt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ fn main() -> ! {
8181
// initialize our profiling timer & structure
8282
log::debug!("initializing our tracing stuff");
8383
let dwt_profiler = cortex_m::singleton!(: ep_dwt::DwtProfiler<CORE_FREQ> =
84-
ep_dwt::DwtProfiler::new(&mut core.DCB, core.DWT, CORE_FREQ))
84+
ep_dwt::DwtProfiler::new(&mut core.DCB, core.DWT, CORE_FREQ).unwrap())
8585
.unwrap();
8686
unsafe {
8787
ep::set_profiler(dwt_profiler).unwrap();

ep-dwt/src/lib.rs

Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
//! let mut core = CorePeripherals::take().unwrap();
2121
//! // (...)
2222
//! let dwt_profiler = cortex_m::singleton!(: ep_dwt::DwtProfiler::<CORE_FREQ> =
23-
//! ep_dwt::DwtProfiler::<CORE_FREQ>::new(&mut core.DCB, core.DWT, CORE_FREQ))
23+
//! ep_dwt::DwtProfiler::<CORE_FREQ>::new(&mut core.DCB, core.DWT, CORE_FREQ).unwrap())
2424
//! .unwrap();
2525
//! unsafe {
2626
//! embedded_profiling::set_profiler(dwt_profiler).unwrap();
@@ -65,6 +65,16 @@ static ROLLOVER_COUNT: AtomicU32 = AtomicU32::new(0);
6565
// For extended mode to work, we really need a u64 container. Double check this.
6666
static_assertions::assert_type_eq_all!(EPContainer, u64);
6767

68+
#[derive(Debug)]
69+
/// Things that can go wrong when configuring the [`DWT`] hardware
70+
pub enum DwtProfilerError {
71+
/// [`cortex_m::peripheral::DWT::has_cycle_counter()`] reported that this hardware
72+
/// does not support cycle count hardware
73+
CycleCounterUnsupported,
74+
/// We failed to configure cycle count compare for the `extended` feature
75+
CycleCounterInvalidSettings,
76+
}
77+
6878
/// DWT trace unit implementing [`EmbeddedProfiler`].
6979
///
7080
/// The frequency of the [`DWT`] is encoded using the parameter `FREQ`.
@@ -80,37 +90,73 @@ impl<const FREQ: u32> DwtProfiler<FREQ> {
8090
///
8191
/// # Panics
8292
/// asserts that the compile time constant `FREQ` matches the runtime provided `sysclk`
83-
#[must_use]
84-
pub fn new(dcb: &mut DCB, mut dwt: DWT, sysclk: u32) -> Self {
93+
pub fn new(dcb: &mut DCB, mut dwt: DWT, sysclk: u32) -> Result<Self, DwtProfilerError> {
8594
assert!(FREQ == sysclk);
8695

96+
// check if our HW supports it
97+
if !dwt.has_cycle_counter() {
98+
return Err(DwtProfilerError::CycleCounterUnsupported);
99+
}
100+
87101
// Enable the DWT block
88102
dcb.enable_trace();
89-
#[cfg(feature = "extended")]
90-
// Enable DebugMonitor exceptions to fire to track overflows
91-
unsafe {
92-
dcb.demcr.modify(|f| f | 1 << 16);
93-
}
94103
DWT::unlock();
95104

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

100-
Self { dwt }
109+
if cfg!(feature = "extended") {
110+
use cortex_m::peripheral::dwt::{ComparatorFunction, CycleCountSettings, EmitOption};
111+
112+
// Enable DebugMonitor exceptions to fire to track overflows
113+
dcb.enable_debug_monitor();
114+
dwt.comp0
115+
.configure(ComparatorFunction::CycleCount(CycleCountSettings {
116+
emit: EmitOption::WatchpointDebugEvent,
117+
compare: 4_294_967_295, // just before overflow (2**32 - 1)
118+
}))
119+
.map_err(|_conf_err| DwtProfilerError::CycleCounterInvalidSettings)?
120+
}
121+
122+
Ok(Self { dwt })
101123
}
102124
}
103125

104126
impl<const FREQ: u32> EmbeddedProfiler for DwtProfiler<FREQ> {
105127
fn read_clock(&self) -> EPInstant {
106128
// get the cycle count and add the rollover if we're extended
107-
#[allow(unused_mut)]
108-
let mut count = EPContainer::from(self.dwt.cyccnt.read());
109-
#[cfg(feature = "extended")]
110-
{
111-
count += EPContainer::from(ROLLOVER_COUNT.load(Ordering::Relaxed))
112-
* EPContainer::from(u32::MAX);
113-
}
129+
let count: EPContainer = {
130+
#[cfg(feature = "extended")]
131+
{
132+
/// Every time we roll over, we should add 2**32
133+
const ROLLOVER_AMOUNT: EPContainer = 0x1_0000_0000;
134+
135+
// read the clock & ROLLOVER_COUNT. We read `cyccnt` twice because we need to detect
136+
// if we've rolled over, and if we have make sure we have the right value for ROLLOVER_COUNT.
137+
let first = self.dwt.cyccnt.read();
138+
let rollover: EPContainer = ROLLOVER_COUNT.load(Ordering::Acquire).into();
139+
let second = self.dwt.cyccnt.read();
140+
141+
if first < second {
142+
// The usual case. We did not roll over between the first and second reading,
143+
// and because of that we also know we got a valid read on ROLLOVER_COUNT.
144+
rollover * ROLLOVER_AMOUNT + EPContainer::from(first)
145+
} else {
146+
// we rolled over sometime between the first and second read. We may or may not have
147+
// caught the right ROLLOVER_COUNT, so grab that again and then use the second reading.
148+
let rollover: EPContainer = ROLLOVER_COUNT.load(Ordering::Acquire).into();
149+
150+
rollover * ROLLOVER_AMOUNT + EPContainer::from(second)
151+
}
152+
}
153+
154+
#[cfg(not(feature = "extended"))]
155+
{
156+
// We aren't trying to be fancy here, we don't care if this rolled over from the last read.
157+
EPContainer::from(self.dwt.cyccnt.read())
158+
}
159+
};
114160

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

0 commit comments

Comments
 (0)