1 /*
2 * Copyright (c) 2020 Nordic Semiconductor ASA
3 * Copyright (c) 2020 STMicroelectronics
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 /**
9 * @file
10 * @brief ARM Cortex-M Timing functions interface based on DWT
11 *
12 */
13
14 #include <zephyr/init.h>
15 #include <zephyr/kernel.h>
16 #include <zephyr/timing/timing.h>
17 #include <cortex_m/dwt.h>
18 #include <cmsis_core.h>
19 #include <zephyr/sys_clock.h>
20
21 /**
22 * @brief Return the current frequency of the cycle counter
23 *
24 * This routine returns the current frequency of the DWT Cycle Counter
25 * in DWT cycles per second (Hz).
26 *
27 * @return the cycle counter frequency value
28 */
z_arm_dwt_freq_get(void)29 static inline uint64_t z_arm_dwt_freq_get(void)
30 {
31 #if defined(CONFIG_CMSIS_CORE_HAS_SYSTEM_CORE_CLOCK)
32 /*
33 * DWT frequency is taken directly from the
34 * System Core clock (CPU) frequency, if the
35 * CMSIS SystemCoreClock symbols is available.
36 */
37 SystemCoreClockUpdate();
38
39 return SystemCoreClock;
40 #elif defined(CONFIG_CORTEX_M_SYSTICK)
41 /* SysTick and DWT both run at CPU frequency,
42 * reflected in the system timer HW cycles/sec.
43 */
44 return sys_clock_hw_cycles_per_sec();
45 #else
46 static uint64_t dwt_frequency;
47 uint32_t cyc_start, cyc_end;
48 uint64_t dwt_start, dwt_end;
49 uint64_t cyc_freq = sys_clock_hw_cycles_per_sec();
50 uint64_t dcyc, ddwt;
51
52 if (!dwt_frequency) {
53
54 z_arm_dwt_init();
55
56 do {
57 cyc_start = k_cycle_get_32();
58 dwt_start = z_arm_dwt_get_cycles();
59
60 k_busy_wait(10 * USEC_PER_MSEC);
61
62 cyc_end = k_cycle_get_32();
63 dwt_end = z_arm_dwt_get_cycles();
64
65 /*
66 * cycles are in 32-bit, and delta must be
67 * calculated in 32-bit precision. Or it would be
68 * wrapping around in 64-bit.
69 */
70 dcyc = (uint32_t)cyc_end - (uint32_t)cyc_start;
71
72 ddwt = dwt_end - dwt_start;
73 } while ((dcyc == 0) || (ddwt == 0));
74
75 dwt_frequency = (cyc_freq * ddwt) / dcyc;
76 }
77 return dwt_frequency;
78 #endif /* CONFIG_SOC_FAMILY_NORDIC_NRF */
79 }
80
arch_timing_init(void)81 void arch_timing_init(void)
82 {
83 z_arm_dwt_init();
84 z_arm_dwt_init_cycle_counter();
85 }
86
arch_timing_start(void)87 void arch_timing_start(void)
88 {
89 z_arm_dwt_cycle_count_start();
90 }
91
arch_timing_stop(void)92 void arch_timing_stop(void)
93 {
94 DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk;
95 }
96
arch_timing_counter_get(void)97 timing_t arch_timing_counter_get(void)
98 {
99 return (timing_t)z_arm_dwt_get_cycles();
100 }
101
arch_timing_cycles_get(volatile timing_t * const start,volatile timing_t * const end)102 uint64_t arch_timing_cycles_get(volatile timing_t *const start, volatile timing_t *const end)
103 {
104 return ((uint32_t)*end - (uint32_t)*start);
105 }
106
arch_timing_freq_get(void)107 uint64_t arch_timing_freq_get(void)
108 {
109 return z_arm_dwt_freq_get();
110 }
111
arch_timing_cycles_to_ns(uint64_t cycles)112 uint64_t arch_timing_cycles_to_ns(uint64_t cycles)
113 {
114 return (cycles) * (NSEC_PER_USEC) / arch_timing_freq_get_mhz();
115 }
116
arch_timing_cycles_to_ns_avg(uint64_t cycles,uint32_t count)117 uint64_t arch_timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count)
118 {
119 return arch_timing_cycles_to_ns(cycles) / count;
120 }
121
arch_timing_freq_get_mhz(void)122 uint32_t arch_timing_freq_get_mhz(void)
123 {
124 return (uint32_t)(arch_timing_freq_get() / 1000000U);
125 }
126