stm32f4xx_hal/
dwt.rs

1//! Debug and trace and stuff
2
3use crate::rcc::Clocks;
4use cortex_m::peripheral::{DCB, DWT};
5use fugit::HertzU32 as Hertz;
6
7pub trait DwtExt {
8    fn constrain(self, dcb: DCB, clocks: &Clocks) -> Dwt;
9}
10impl DwtExt for DWT {
11    /// Enable trace unit and cycle counter
12    fn constrain(mut self, mut dcb: DCB, clocks: &Clocks) -> Dwt {
13        dcb.enable_trace();
14        self.enable_cycle_counter();
15        Dwt {
16            dwt: self,
17            dcb,
18            clock: clocks.hclk(),
19        }
20    }
21}
22
23/// DWT (Data Watchpoint and Trace) unit
24pub struct Dwt {
25    dwt: DWT,
26    dcb: DCB,
27    clock: Hertz,
28}
29impl Dwt {
30    /// Release the dwt and dcb control
31    /// # Safety
32    /// All instances of Delay and StopWatch become invalid after this
33    pub unsafe fn release(self) -> (DWT, DCB) {
34        (self.dwt, self.dcb)
35    }
36    /// Create a delay instance
37    pub fn delay(&self) -> Delay {
38        Delay { clock: self.clock }
39    }
40    /// Create a stopwatch instance
41    /// # Arguments
42    /// * `times` - Array which will be holding the timings in ticks (max laps == times.len()-1)
43    pub fn stopwatch<'i>(&self, times: &'i mut [u32]) -> StopWatch<'i> {
44        StopWatch::new(times, self.clock)
45    }
46    /// Measure cycles it takes to execute closure `f`.
47    ///
48    /// Since DWT Cycle Counter is a 32-bit counter that wraps around to 0 on overflow,
49    /// users should be aware that `Dwt::measure` cannot correctly measure running time of
50    /// closures which take longer than `u32::MAX` cycles
51    pub fn measure<F: FnOnce()>(&self, f: F) -> ClockDuration {
52        let mut times: [u32; 2] = [0; 2];
53        let mut sw = self.stopwatch(&mut times);
54        f();
55        sw.lap().lap_time(1).unwrap()
56    }
57}
58
59#[derive(Clone, Copy)]
60pub struct Delay {
61    clock: Hertz,
62}
63impl Delay {
64    /// Delay for `ClockDuration::ticks`
65    pub fn delay(duration: ClockDuration) {
66        let ticks = duration.ticks as u64;
67        Delay::delay_ticks(DWT::cycle_count(), ticks);
68    }
69    /// Delay ticks
70    /// NOTE DCB and DWT need to be set up for this to work, so it is private
71    fn delay_ticks(mut start: u32, ticks: u64) {
72        if ticks < (u32::MAX / 2) as u64 {
73            // Simple delay
74            let ticks = ticks as u32;
75            while (DWT::cycle_count().wrapping_sub(start)) < ticks {}
76        } else if ticks <= u32::MAX as u64 {
77            // Try to avoid race conditions by limiting delay to u32::MAX / 2
78            let mut ticks = ticks as u32;
79            ticks -= u32::MAX / 2;
80            while (DWT::cycle_count().wrapping_sub(start)) < u32::MAX / 2 {}
81            start -= u32::MAX / 2;
82            while (DWT::cycle_count().wrapping_sub(start)) < ticks {}
83        } else {
84            // Delay for ticks, then delay for rest * u32::MAX
85            let mut rest = (ticks >> 32) as u32;
86            let ticks = (ticks & u32::MAX as u64) as u32;
87            loop {
88                while (DWT::cycle_count().wrapping_sub(start)) < ticks {}
89                if rest == 0 {
90                    break;
91                }
92                rest -= 1;
93                while (DWT::cycle_count().wrapping_sub(start)) > ticks {}
94            }
95        }
96    }
97}
98
99// Implement DelayUs/DelayMs for various integer types
100impl<T: Into<u64>> embedded_hal_02::blocking::delay::DelayUs<T> for Delay {
101    fn delay_us(&mut self, us: T) {
102        // Convert us to ticks
103        let start = DWT::cycle_count();
104        let ticks = (us.into() * self.clock.raw() as u64) / 1_000_000;
105        Delay::delay_ticks(start, ticks);
106    }
107}
108impl<T: Into<u64>> embedded_hal_02::blocking::delay::DelayMs<T> for Delay {
109    fn delay_ms(&mut self, ms: T) {
110        // Convert ms to ticks
111        let start = DWT::cycle_count();
112        let ticks = (ms.into() * self.clock.raw() as u64) / 1_000;
113        Delay::delay_ticks(start, ticks);
114    }
115}
116
117impl embedded_hal::delay::DelayNs for Delay {
118    fn delay_ns(&mut self, ns: u32) {
119        // Convert us to ticks
120        let start = DWT::cycle_count();
121        let ticks = (ns as u64 * self.clock.raw() as u64) / 1_000_000_000;
122        Delay::delay_ticks(start, ticks);
123    }
124
125    fn delay_us(&mut self, us: u32) {
126        // Convert us to ticks
127        let start = DWT::cycle_count();
128        let ticks = (us as u64 * self.clock.raw() as u64) / 1_000_000;
129        Delay::delay_ticks(start, ticks);
130    }
131
132    fn delay_ms(&mut self, ms: u32) {
133        // Convert ms to ticks
134        let start = DWT::cycle_count();
135        let ticks = (ms as u64 * self.clock.raw() as u64) / 1_000;
136        Delay::delay_ticks(start, ticks);
137    }
138}
139
140/// Very simple stopwatch which reads from DWT Cycle Counter to record timing.
141///
142/// Since DWT Cycle Counter is a 32-bit counter that wraps around to 0 on overflow,
143/// users should be aware that `StopWatch` cannot correctly measure laps
144/// which take longer than `u32::MAX` cycles
145pub struct StopWatch<'l> {
146    times: &'l mut [u32],
147    timei: usize,
148    clock: Hertz,
149}
150impl<'l> StopWatch<'l> {
151    /// Create a new instance (Private because dwt/dcb should be set up)
152    /// # Arguments
153    /// * `times` - Array which will be holding the timings (max laps == times.len()-1)
154    /// * `clock` - The DWT cycle counters clock
155    fn new(times: &'l mut [u32], clock: Hertz) -> Self {
156        assert!(times.len() >= 2);
157        let mut sw = StopWatch {
158            times,
159            timei: 0,
160            clock,
161        };
162        sw.reset();
163        sw
164    }
165    /// Returns the numbers of laps recorded
166    pub fn lap_count(&self) -> usize {
167        self.timei
168    }
169    /// Resets recorded laps to 0 and sets 0 offset
170    pub fn reset(&mut self) {
171        self.timei = 0;
172        self.times[0] = DWT::cycle_count();
173    }
174    /// Record a new lap.
175    ///
176    /// If lap count exceeds maximum, the last lap is updated
177    pub fn lap(&mut self) -> &mut Self {
178        let c = DWT::cycle_count();
179        if self.timei < self.times.len() {
180            self.timei += 1;
181        }
182        self.times[self.timei] = c;
183        self
184    }
185    /// Calculate the time of lap n (n starting with 1).
186    ///
187    /// Returns None if `n` is out of range
188    pub fn lap_time(&self, n: usize) -> Option<ClockDuration> {
189        if (n < 1) || (self.timei < n) {
190            None
191        } else {
192            Some(ClockDuration {
193                ticks: self.times[n].wrapping_sub(self.times[n - 1]),
194                clock: self.clock,
195            })
196        }
197    }
198}
199
200/// Clock difference with capability to calculate SI units (s)
201#[derive(Clone, Copy)]
202pub struct ClockDuration {
203    ticks: u32,
204    clock: Hertz,
205}
206impl ClockDuration {
207    /// Returns ticks
208    pub fn as_ticks(self) -> u32 {
209        self.ticks
210    }
211    /// Returns calculated milliseconds as integer
212    pub fn as_millis(self) -> u64 {
213        self.ticks as u64 * 1_000 / self.clock.raw() as u64
214    }
215    /// Returns calculated microseconds as integer
216    pub fn as_micros(self) -> u64 {
217        self.ticks as u64 * 1_000_000 / self.clock.raw() as u64
218    }
219    /// Returns calculated nanoseconds as integer
220    pub fn as_nanos(self) -> u64 {
221        self.ticks as u64 * 1_000_000_000 / self.clock.raw() as u64
222    }
223    /// Return calculated seconds as 32-bit float
224    pub fn as_secs_f32(self) -> f32 {
225        self.ticks as f32 / self.clock.raw() as f32
226    }
227    /// Return calculated seconds as 64-bit float
228    pub fn as_secs_f64(self) -> f64 {
229        self.ticks as f64 / self.clock.raw() as f64
230    }
231}
232
233/// A monotonic non-decreasing timer
234///
235/// This uses the timer in the debug watch trace peripheral. This means, that if the
236/// core is stopped, the timer does not count up. This may be relevant if you are using
237/// cortex_m_semihosting::hprintln for debugging in which case the timer will be stopped
238/// while printing
239#[derive(Clone, Copy)]
240pub struct MonoTimer {
241    frequency: Hertz,
242}
243
244impl MonoTimer {
245    /// Creates a new `Monotonic` timer
246    pub fn new(mut dwt: DWT, mut dcb: DCB, clocks: &Clocks) -> Self {
247        dcb.enable_trace();
248        dwt.enable_cycle_counter();
249
250        // now the CYCCNT counter can't be stopped or reset
251
252        MonoTimer {
253            frequency: clocks.hclk(),
254        }
255    }
256
257    /// Returns the frequency at which the monotonic timer is operating at
258    pub fn frequency(self) -> Hertz {
259        self.frequency
260    }
261
262    /// Returns an `Instant` corresponding to "now"
263    pub fn now(self) -> Instant {
264        Instant {
265            now: DWT::cycle_count(),
266        }
267    }
268}
269
270/// A measurement of a monotonically non-decreasing clock
271#[derive(Clone, Copy)]
272pub struct Instant {
273    now: u32,
274}
275
276impl Instant {
277    /// Ticks elapsed since the `Instant` was created
278    pub fn elapsed(self) -> u32 {
279        DWT::cycle_count().wrapping_sub(self.now)
280    }
281}